summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Branson <andrew.branson@jolla.com>2026-04-03 22:55:30 +0200
committerAndrew Branson <andrew.branson@jolla.com>2026-04-04 11:55:25 +0200
commita35c9fa159173388d88ef77e1d31f53488aad094 (patch)
treee4691b5bbf054ca13e35d98d9df653bf9cdc0054
parent5f999f7a4712c4a4d1c89054b544064cfd4b769e (diff)
Generalize for all fediverse accounts
-rw-r--r--README.md98
-rw-r--r--buteo-plugins/buteo-common/buteo-common.pri2
-rw-r--r--buteo-plugins/buteo-common/buteo-common.pro2
-rw-r--r--buteo-plugins/buteo-plugins.pro8
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/buteo-sync-plugin-fediverse-notifications.pro (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro)26
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediverse-notifications.xml (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml)2
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediverse.Notifications.xml (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml)6
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversedatatypesyncadaptor.cpp (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp)64
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversedatatypesyncadaptor.h (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h)12
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationsplugin.cpp (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationsplugin.cpp)22
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationsplugin.h (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationsplugin.h)16
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationssyncadaptor.cpp (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp)162
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationssyncadaptor.h (renamed from buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h)14
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/buteo-sync-plugin-fediverse-posts.pro (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro)22
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediverse-posts.xml (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml)2
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediverse.Posts.xml (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml)6
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversedatatypesyncadaptor.cpp (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp)70
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversedatatypesyncadaptor.h (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h)14
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostsplugin.cpp (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostsplugin.cpp)18
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostsplugin.h (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostsplugin.h)16
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostssyncadaptor.cpp (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostssyncadaptor.cpp)47
-rw-r--r--buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostssyncadaptor.h (renamed from buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostssyncadaptor.h)20
-rw-r--r--common/common.pri2
-rw-r--r--common/common.pro10
-rw-r--r--common/fediverseauthutils.h (renamed from common/mastodonauthutils.h)26
-rw-r--r--common/fediversepostsdatabase.cpp (renamed from common/mastodonpostsdatabase.cpp)107
-rw-r--r--common/fediversepostsdatabase.h (renamed from common/mastodonpostsdatabase.h)18
-rw-r--r--common/fediversetextutils.h (renamed from common/mastodontextutils.h)10
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/FediverseFeedItem.qml362
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/eventsview-plugin-fediverse.pro (renamed from eventsview-plugins/eventsview-plugin-mastodon/eventsview-plugin-mastodon.pro)19
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml185
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/fediversepostactions.cpp (renamed from eventsview-plugins/eventsview-plugin-mastodon/mastodonpostactions.cpp)38
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/fediversepostactions.h (renamed from eventsview-plugins/eventsview-plugin-mastodon/mastodonpostactions.h)10
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.cpp200
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.h (renamed from eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.h)19
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/plugin.cpp27
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/qmldir4
-rw-r--r--eventsview-plugins/eventsview-plugin-mastodon/MastodonFeedItem.qml488
-rw-r--r--eventsview-plugins/eventsview-plugin-mastodon/mastodon-delegate.qml214
-rw-r--r--eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.cpp165
-rw-r--r--eventsview-plugins/eventsview-plugin-mastodon/plugin.cpp27
-rw-r--r--eventsview-plugins/eventsview-plugin-mastodon/qmldir4
-rw-r--r--eventsview-plugins/eventsview-plugins.pro2
-rw-r--r--icons/svgs/icons/icon-l-fediverse.svg10
-rw-r--r--icons/svgs/icons/icon-l-mastodon.svg10
-rw-r--r--rpm/sailfish-account-fediverse.spec133
-rw-r--r--rpm/sailfish-account-mastodon.spec133
-rw-r--r--sailfish-account-fediverse.pro (renamed from sailfish-account-mastodon.pro)2
-rw-r--r--settings/accounts-translations-plugin/accounts-translations-plugin.pro6
-rw-r--r--settings/accounts-translations-plugin/plugin.cpp182
-rw-r--r--settings/accounts-translations-plugin/qmldir4
-rw-r--r--settings/accounts/accounts.pro38
-rw-r--r--settings/accounts/providers/fediverse.provider (renamed from settings/accounts/providers/mastodon.provider)14
-rw-r--r--settings/accounts/services/fediverse-microblog.service (renamed from settings/accounts/services/mastodon-microblog.service)12
-rw-r--r--settings/accounts/services/fediverse-notifications.service (renamed from settings/accounts/services/mastodon-notifications.service)12
-rw-r--r--settings/accounts/services/fediverse-sharing.service (renamed from settings/accounts/services/mastodon-sharing.service)10
-rw-r--r--settings/accounts/ui/FediverseSettingsDisplay.qml (renamed from settings/accounts/ui/MastodonSettingsDisplay.qml)45
-rw-r--r--settings/accounts/ui/fediverse-settings.qml (renamed from settings/accounts/ui/mastodon-settings.qml)14
-rw-r--r--settings/accounts/ui/fediverse-update.qml (renamed from settings/accounts/ui/mastodon-update.qml)27
-rw-r--r--settings/accounts/ui/fediverse.qml (renamed from settings/accounts/ui/mastodon.qml)293
-rw-r--r--transferengine-plugins/fediverseshareplugin/FediverseSharePost.qml (renamed from transferengine-plugins/mastodonshareplugin/MastodonSharePost.qml)0
-rw-r--r--transferengine-plugins/fediverseshareplugin/fediverseplugininfo.cpp62
-rw-r--r--transferengine-plugins/fediverseshareplugin/fediverseplugininfo.h (renamed from transferengine-plugins/mastodonshareplugin/mastodonplugininfo.h)16
-rw-r--r--transferengine-plugins/fediverseshareplugin/fediverseshareplugin.cpp29
-rw-r--r--transferengine-plugins/fediverseshareplugin/fediverseshareplugin.h28
-rw-r--r--transferengine-plugins/fediverseshareplugin/fediverseshareplugin.pro (renamed from transferengine-plugins/mastodonshareplugin/mastodonshareplugin.pro)18
-rw-r--r--transferengine-plugins/fediverseshareservicestatus.cpp (renamed from transferengine-plugins/mastodonshareservicestatus.cpp)52
-rw-r--r--transferengine-plugins/fediverseshareservicestatus.h (renamed from transferengine-plugins/mastodonshareservicestatus.h)11
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediverseapi.cpp (renamed from transferengine-plugins/mastodontransferplugin/mastodonapi.cpp)36
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediverseapi.h (renamed from transferengine-plugins/mastodontransferplugin/mastodonapi.h)12
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediversetransferplugin.cpp31
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediversetransferplugin.h (renamed from transferengine-plugins/mastodontransferplugin/mastodontransferplugin.h)14
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediversetransferplugin.pro (renamed from transferengine-plugins/mastodontransferplugin/mastodontransferplugin.pro)19
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp (renamed from transferengine-plugins/mastodontransferplugin/mastodonuploader.cpp)92
-rw-r--r--transferengine-plugins/fediversetransferplugin/fediverseuploader.h (renamed from transferengine-plugins/mastodontransferplugin/mastodonuploader.h)22
-rw-r--r--transferengine-plugins/mastodonshareplugin/mastodonplugininfo.cpp60
-rw-r--r--transferengine-plugins/mastodonshareplugin/mastodonshareplugin.cpp29
-rw-r--r--transferengine-plugins/mastodonshareplugin/mastodonshareplugin.h28
-rw-r--r--transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp31
-rw-r--r--transferengine-plugins/transferengine-plugins.pro2
80 files changed, 2202 insertions, 1921 deletions
diff --git a/README.md b/README.md
index 6ce2dfb..f8a1b97 100644
--- a/README.md
+++ b/README.md
@@ -1,89 +1,73 @@
-# sailfish-account-mastodon
+# sailfish-account-fediverse
-Sailfish OS account integration for Mastodon.
+Sailfish OS account integration for the Fediverse.
-## Repository Components
+## Repository components
### `common/`
- Shared C++ library code used by multiple plugins.
-- Includes socialcache-backed storage for Mastodon posts and shared Mastodon auth helpers.
+- Includes socialcache-backed storage for Fediverse posts and shared OAuth helper code.
### `settings/`
- Sailfish Accounts provider, service definitions, and account UI.
-- OAuth2 (`web_server`) account flow with per-instance Mastodon app registration.
-- Translations:
- - QML translation-loader module at `/usr/lib*/qt5/qml/com/jolla/settings/accounts/mastodon/` loads `settings-accounts-mastodon` catalogs for `qsTrId` strings.
- - Engineering English catalog: `/usr/share/translations/settings-accounts-mastodon_eng_en.qm`
- - Translation source catalog: `/usr/share/translations/source/settings-accounts-mastodon.ts`
- - Provider/service metadata uses `<translations>/usr/share/translations/settings-accounts-mastodon</translations>` for metadata string translation paths.
-- Services:
- - `mastodon-microblog`: sync service for posts and notifications.
- - `mastodon-sharing`: Transfer Engine sharing service.
+- OAuth2 (`web_server`) account flow with per-instance application registration.
+- Discovers instance title, description, and icon from the instance entity.
+- Caches remote instance icons and uses them in place of the generic Fediverse icon when available.
+- Installs the QML translation-loader plugin under `/usr/lib*/qt5/qml/com/jolla/settings/accounts/fediverse/`.
+- Installs `fediverse-microblog`, `fediverse-notifications`, and `fediverse-sharing` service definitions.
### `buteo-plugins/`
-- Buteo sync plugins and shared social sync framework code.
-- Includes:
- - `buteo-sync-plugin-mastodon-posts`
- - `buteo-sync-plugin-mastodon-notifications`
-- Installs Buteo client profile and sync profile XML files.
+- Shared Buteo sync framework support library.
+- Sync plugins for Fediverse posts and notifications.
+- Installs the Buteo client profile and sync profile XML files.
### `eventsview-plugins/`
-- Events view extension for Mastodon posts.
-- Includes delegate/feed item QML and `MastodonPostsModel`.
+- Events view extension for Fediverse posts.
+- Includes the delegate/feed item QML and `FediversePostsModel`.
### `transferengine-plugins/`
-- Transfer Engine integration for Mastodon sharing.
-- `mastodonshareplugin/`: sharing method discovery + metadata.
-- `mastodontransferplugin/`: media upload + status creation.
-- Single share UI entry: `MastodonSharePost.qml` handles both media and text/link posting.
-- Supports:
- - media sharing (`image/jpeg`, `image/png`, `video/mp4`)
- - link/text sharing (`text/x-url`, `text/plain`) with title/link extraction from share resources.
+- Transfer Engine integration for Fediverse sharing.
+- `fediverseshareplugin/`: sharing method discovery and metadata.
+- `fediversetransferplugin/`: media upload and status creation.
+- `FediverseSharePost.qml` handles both media and text/link posting.
### `icons/`
-- Mastodon SVG assets and `sailfish-svg2png` conversion setup.
-- Uses canonical icon names only:
- - `icons/icon-l-mastodon`
+- Generic Fediverse SVG assets and `sailfish-svg2png` conversion setup.
+- Uses the canonical icon name `icons/icon-l-fediverse`.
+
### `rpm/`
-- Packaging for all modules in `rpm/sailfish-account-mastodon.spec`.
+- Packaging for all modules in `rpm/sailfish-account-fediverse.spec`.
- Packages:
- - `sailfish-account-mastodon` (all runtime components)
- - `sailfish-account-mastodon-ts-devel` (translation source files only)
-- `%qmake5_install` already installs icon outputs from the `icons/` subproject; avoid a second explicit `icons` `make install` in `%install`.
-- Translation source `.ts` files are packaged in `sailfish-account-mastodon-ts-devel` (runtime package ships `.qm` only).
-- Runtime package ships the Mastodon settings translation-loader QML plugin under `%{_libdir}/qt5/qml/com/jolla/settings/accounts/mastodon/`.
+ - `sailfish-account-fediverse`
+ - `sailfish-account-fediverse-ts-devel`
+- `%qmake5_install` installs the icon outputs from the `icons/` subproject.
+- Translation source `.ts` files are packaged separately from runtime `.qm` files.
### Root project
-- `sailfish-account-mastodon.pro` ties subprojects together.
+- `sailfish-account-fediverse.pro` ties the subprojects together.
-## Current Notification Behavior
+## Current behaviour
-- Events view shows Mastodon posts (not notification entries).
-- Events view post metadata line includes replies, favourites, and boosts alongside elapsed timestamp.
-- Long-pressing a Mastodon post reveals quick actions for favourite and boost, calling Mastodon API endpoints directly with account OAuth credentials.
-- System notifications are produced by `buteo-sync-plugin-mastodon-notifications`.
-- Notifications sync starts from Mastodon server marker (`notifications.last_read_id`) and uses local cursor dedupe via per-account `LastFetchedNotificationId`.
-- Each unread Mastodon notification is published as a separate Sailfish system notification.
-- Mastodon marker (`last_read_id`) is updated only when no local Mastodon notifications remain for that account.
-- Notification template profile dispatches per-account sync profiles on schedule (default every 30 minutes), not only at boot.
+- The Events view shows Fediverse posts, not notification entries.
+- The Events view metadata line includes replies, favourites, and boosts alongside elapsed time.
+- Long-press actions call the instance API directly with the account OAuth credentials.
+- System notifications are produced by the Fediverse notifications sync plugin.
+- Notifications sync starts from the server marker (`notifications.last_read_id`) and uses a per-account local cursor for dedupe.
+- Each unread notification is published as a separate Sailfish system notification.
-## Build Requirements
+## Build requirements
This project targets Sailfish OS build tooling.
-Full build/package validation is not possible without Sailfish SDK access (target sysroot + Sailfish packages).
-
-Required SDK-provided dependencies include (not exhaustive):
+Required SDK-provided dependencies include:
- `buteosyncfw5`
- `socialcache`
- `sailfishaccounts`
- `nemotransferengine-qt5`
-- related Qt/account stack packages listed in `rpm/sailfish-account-mastodon.spec`
-
-## Typical Build Flow (Inside Sailfish SDK)
+- related Qt and Sailfish account stack packages listed in `rpm/sailfish-account-fediverse.spec`
-1. Enter Sailfish SDK shell/target.
-2. Build from repository root (`qmake` / `make`).
-3. Build RPM package(s) from `rpm/sailfish-account-mastodon.spec`.
+## Typical build flow
-Outside Sailfish SDK, only static validation (wiring, paths, spec consistency) should be considered reliable.
+1. Enter a Sailfish SDK shell or target.
+2. Build from the repository root.
+3. Build RPM packages from `rpm/sailfish-account-fediverse.spec`.
diff --git a/buteo-plugins/buteo-common/buteo-common.pri b/buteo-plugins/buteo-common/buteo-common.pri
index 83452ac..422d98f 100644
--- a/buteo-plugins/buteo-common/buteo-common.pri
+++ b/buteo-plugins/buteo-common/buteo-common.pri
@@ -10,4 +10,4 @@ QT += dbus
CONFIG += link_pkgconfig
PKGCONFIG += accounts-qt5 buteosyncfw5 socialcache libsignon-qt5 libsailfishkeyprovider
-LIBS += -L$$PWD -lmastodonbuteocommon
+LIBS += -L$$PWD -lfediversebuteocommon
diff --git a/buteo-plugins/buteo-common/buteo-common.pro b/buteo-plugins/buteo-common/buteo-common.pro
index c0b84a9..70a8332 100644
--- a/buteo-plugins/buteo-common/buteo-common.pro
+++ b/buteo-plugins/buteo-common/buteo-common.pro
@@ -4,7 +4,7 @@
TEMPLATE = lib
-TARGET = mastodonbuteocommon
+TARGET = fediversebuteocommon
TARGET = $$qtLibraryTarget($$TARGET)
QT -= gui
diff --git a/buteo-plugins/buteo-plugins.pro b/buteo-plugins/buteo-plugins.pro
index ead60e6..7938956 100644
--- a/buteo-plugins/buteo-plugins.pro
+++ b/buteo-plugins/buteo-plugins.pro
@@ -5,8 +5,8 @@
TEMPLATE = subdirs
SUBDIRS += \
buteo-common \
- buteo-sync-plugin-mastodon-posts \
- buteo-sync-plugin-mastodon-notifications
+ buteo-sync-plugin-fediverse-posts \
+ buteo-sync-plugin-fediverse-notifications
-buteo-sync-plugin-mastodon-posts.depends = buteo-common
-buteo-sync-plugin-mastodon-notifications.depends = buteo-common
+buteo-sync-plugin-fediverse-posts.depends = buteo-common
+buteo-sync-plugin-fediverse-notifications.depends = buteo-common
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/buteo-sync-plugin-fediverse-notifications.pro
index d16cc3d..0ba9d2f 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/buteo-sync-plugin-fediverse-notifications.pro
@@ -2,15 +2,15 @@
#
# SPDX-License-Identifier: BSD-3-Clause
-TARGET = mastodon-notifications-client
+TARGET = fediverse-notifications-client
QT -= gui
include($$PWD/../buteo-common/buteo-common.pri)
include($$PWD/../../common/common.pri)
-TS_FILE = $$OUT_PWD/lipstick-jolla-home-mastodon-notifications.ts
-EE_QM = $$OUT_PWD/lipstick-jolla-home-mastodon-notifications_eng_en.qm
+TS_FILE = $$OUT_PWD/lipstick-jolla-home-fediverse-notifications.ts
+EE_QM = $$OUT_PWD/lipstick-jolla-home-fediverse-notifications_eng_en.qm
ts.commands += lupdate $$PWD -ts $$TS_FILE
ts.CONFIG += no_check_exist no_link
@@ -40,27 +40,27 @@ PKGCONFIG += mlite5 nemonotifications-qt5
INCLUDEPATH += $$PWD
SOURCES += \
- $$PWD/mastodondatatypesyncadaptor.cpp \
- $$PWD/mastodonnotificationsplugin.cpp \
- $$PWD/mastodonnotificationssyncadaptor.cpp
+ $$PWD/fediversedatatypesyncadaptor.cpp \
+ $$PWD/fediversenotificationsplugin.cpp \
+ $$PWD/fediversenotificationssyncadaptor.cpp
HEADERS += \
- $$PWD/mastodondatatypesyncadaptor.h \
- $$PWD/mastodonnotificationsplugin.h \
- $$PWD/mastodonnotificationssyncadaptor.h
+ $$PWD/fediversedatatypesyncadaptor.h \
+ $$PWD/fediversenotificationsplugin.h \
+ $$PWD/fediversenotificationssyncadaptor.h
OTHER_FILES += \
- $$PWD/mastodon-notifications.xml \
- $$PWD/mastodon.Notifications.xml
+ $$PWD/fediverse-notifications.xml \
+ $$PWD/fediverse.Notifications.xml
TEMPLATE = lib
CONFIG += plugin
target.path = $$[QT_INSTALL_LIBS]/buteo-plugins-qt5/oopp
sync.path = /etc/buteo/profiles/sync
-sync.files = mastodon.Notifications.xml
+sync.files = fediverse.Notifications.xml
client.path = /etc/buteo/profiles/client
-client.files = mastodon-notifications.xml
+client.files = fediverse-notifications.xml
INSTALLS += target sync client ts_install engineering_english_install
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediverse-notifications.xml
index 3284d61..81de349 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediverse-notifications.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<profile name="mastodon-notifications" type="client" >
+<profile name="fediverse-notifications" type="client" >
<field name="Sync Direction" />
</profile>
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediverse.Notifications.xml
index 05d5218..bf0ecee 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediverse.Notifications.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<profile name="mastodon.Notifications" type="sync" >
+<profile name="fediverse.Notifications" type="sync" >
<key name="category" value="eventfeed" />
<key name="enabled" value="true" />
<key name="use_accounts" value="false" />
<key name="destinationtype" value="online" />
<key name="hidden" value="true" />
- <key name="displayname" value="Mastodon Notifications"/>
+ <key name="displayname" value="Fediverse Notifications"/>
<schedule enabled="true" interval="30" days="1,2,3,4,5,6,7" syncconfiguredtime="" time="" />
- <profile name="mastodon-notifications" type="client" >
+ <profile name="fediverse-notifications" type="client" >
<key name="Sync Direction" value="from-remote" />
</profile>
</profile>
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversedatatypesyncadaptor.cpp
index ddf6686..3d71585 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversedatatypesyncadaptor.cpp
@@ -18,8 +18,8 @@
**
****************************************************************************/
-#include "mastodondatatypesyncadaptor.h"
-#include "mastodonauthutils.h"
+#include "fediversedatatypesyncadaptor.h"
+#include "fediverseauthutils.h"
#include <QtCore/QLoggingCategory>
#include <QtCore/QVariantMap>
@@ -36,23 +36,23 @@
#include <SignOn/AuthSession>
#include <SignOn/SessionData>
-Q_LOGGING_CATEGORY(lcMastodonNotificationsSync, "buteo.plugin.mastodon.notifications.sync", QtWarningMsg)
+Q_LOGGING_CATEGORY(lcFediverseNotificationsSync, "buteo.plugin.fediverse.notifications.sync", QtWarningMsg)
-MastodonNotificationsDataTypeSyncAdaptor::MastodonNotificationsDataTypeSyncAdaptor(
+FediverseNotificationsDataTypeSyncAdaptor::FediverseNotificationsDataTypeSyncAdaptor(
SocialNetworkSyncAdaptor::DataType dataType,
QObject *parent)
- : SocialNetworkSyncAdaptor(QStringLiteral("mastodon"), dataType, 0, parent)
+ : SocialNetworkSyncAdaptor(QStringLiteral("fediverse"), dataType, 0, parent)
{
}
-MastodonNotificationsDataTypeSyncAdaptor::~MastodonNotificationsDataTypeSyncAdaptor()
+FediverseNotificationsDataTypeSyncAdaptor::~FediverseNotificationsDataTypeSyncAdaptor()
{
}
-void MastodonNotificationsDataTypeSyncAdaptor::sync(const QString &dataTypeString, int accountId)
+void FediverseNotificationsDataTypeSyncAdaptor::sync(const QString &dataTypeString, int accountId)
{
if (dataTypeString != SocialNetworkSyncAdaptor::dataTypeName(m_dataType)) {
- qCWarning(lcMastodonNotificationsSync) << "Mastodon" << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
+ qCWarning(lcFediverseNotificationsSync) << "Fediverse" << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
<< "sync adaptor was asked to sync" << dataTypeString;
setStatus(SocialNetworkSyncAdaptor::Error);
return;
@@ -60,14 +60,14 @@ void MastodonNotificationsDataTypeSyncAdaptor::sync(const QString &dataTypeStrin
setStatus(SocialNetworkSyncAdaptor::Busy);
updateDataForAccount(accountId);
- qCDebug(lcMastodonNotificationsSync) << "successfully triggered sync with profile:" << m_accountSyncProfile->name();
+ qCDebug(lcFediverseNotificationsSync) << "successfully triggered sync with profile:" << m_accountSyncProfile->name();
}
-void MastodonNotificationsDataTypeSyncAdaptor::updateDataForAccount(int accountId)
+void FediverseNotificationsDataTypeSyncAdaptor::updateDataForAccount(int accountId)
{
Accounts::Account *account = Accounts::Account::fromId(m_accountManager, accountId, this);
if (!account) {
- qCWarning(lcMastodonNotificationsSync) << "existing account with id" << accountId << "couldn't be retrieved";
+ qCWarning(lcFediverseNotificationsSync) << "existing account with id" << accountId << "couldn't be retrieved";
setStatus(SocialNetworkSyncAdaptor::Error);
return;
}
@@ -76,17 +76,17 @@ void MastodonNotificationsDataTypeSyncAdaptor::updateDataForAccount(int accountI
signIn(account);
}
-QString MastodonNotificationsDataTypeSyncAdaptor::apiHost(int accountId) const
+QString FediverseNotificationsDataTypeSyncAdaptor::apiHost(int accountId) const
{
- return m_apiHosts.value(accountId, QStringLiteral("https://mastodon.social"));
+ return m_apiHosts.value(accountId, FediverseAuthUtils::defaultApiHost());
}
-QString MastodonNotificationsDataTypeSyncAdaptor::authServiceName() const
+QString FediverseNotificationsDataTypeSyncAdaptor::authServiceName() const
{
return syncServiceName();
}
-void MastodonNotificationsDataTypeSyncAdaptor::errorHandler(QNetworkReply::NetworkError err)
+void FediverseNotificationsDataTypeSyncAdaptor::errorHandler(QNetworkReply::NetworkError err)
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) {
@@ -96,7 +96,7 @@ void MastodonNotificationsDataTypeSyncAdaptor::errorHandler(QNetworkReply::Netwo
const int accountId = reply->property("accountId").toInt();
const int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- qCWarning(lcMastodonNotificationsSync) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
+ qCWarning(lcFediverseNotificationsSync) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
<< "request with account" << accountId
<< "experienced error:" << err
<< "HTTP:" << httpStatus;
@@ -111,7 +111,7 @@ void MastodonNotificationsDataTypeSyncAdaptor::errorHandler(QNetworkReply::Netwo
}
}
-void MastodonNotificationsDataTypeSyncAdaptor::sslErrorsHandler(const QList<QSslError> &errs)
+void FediverseNotificationsDataTypeSyncAdaptor::sslErrorsHandler(const QList<QSslError> &errs)
{
QString sslerrs;
foreach (const QSslError &e, errs) {
@@ -121,24 +121,24 @@ void MastodonNotificationsDataTypeSyncAdaptor::sslErrorsHandler(const QList<QSsl
sslerrs.chop(2);
}
- qCWarning(lcMastodonNotificationsSync) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
+ qCWarning(lcFediverseNotificationsSync) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
<< "request with account" << sender()->property("accountId").toInt()
<< "experienced ssl errors:" << sslerrs;
sender()->setProperty("isError", QVariant::fromValue<bool>(true));
}
-void MastodonNotificationsDataTypeSyncAdaptor::setCredentialsNeedUpdate(Accounts::Account *account)
+void FediverseNotificationsDataTypeSyncAdaptor::setCredentialsNeedUpdate(Accounts::Account *account)
{
- qCInfo(lcMastodonNotificationsSync) << "sociald:Mastodon: setting CredentialsNeedUpdate to true for account:" << account->id();
+ qCInfo(lcFediverseNotificationsSync) << "sociald:Fediverse: setting CredentialsNeedUpdate to true for account:" << account->id();
Accounts::Service srv(m_accountManager->service(authServiceName()));
account->selectService(srv);
account->setValue(QStringLiteral("CredentialsNeedUpdate"), QVariant::fromValue<bool>(true));
- account->setValue(QStringLiteral("CredentialsNeedUpdateFrom"), QVariant::fromValue<QString>(QString::fromLatin1("sociald-mastodon")));
+ account->setValue(QStringLiteral("CredentialsNeedUpdateFrom"), QVariant::fromValue<QString>(QString::fromLatin1("sociald-fediverse")));
account->selectService(Accounts::Service());
account->syncAndBlock();
}
-void MastodonNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account)
+void FediverseNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account)
{
const int accountId = account->id();
if (!checkAccount(account)) {
@@ -153,7 +153,7 @@ void MastodonNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account
? SignOn::Identity::existingIdentity(account->credentialsId())
: 0;
if (!identity) {
- qCWarning(lcMastodonNotificationsSync) << "account" << accountId << "has no valid credentials, cannot sign in";
+ qCWarning(lcFediverseNotificationsSync) << "account" << accountId << "has no valid credentials, cannot sign in";
decrementSemaphore(accountId);
return;
}
@@ -163,14 +163,14 @@ void MastodonNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account
const QString mechanism = accSrv.authData().mechanism();
SignOn::AuthSession *session = identity->createSession(method);
if (!session) {
- qCWarning(lcMastodonNotificationsSync) << "could not create signon session for account" << accountId;
+ qCWarning(lcFediverseNotificationsSync) << "could not create signon session for account" << accountId;
identity->deleteLater();
decrementSemaphore(accountId);
return;
}
QVariantMap signonSessionData = accSrv.authData().parameters();
- MastodonAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
+ FediverseAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
connect(session, SIGNAL(response(SignOn::SessionData)),
this, SLOT(signOnResponse(SignOn::SessionData)),
@@ -184,14 +184,14 @@ void MastodonNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account
session->process(SignOn::SessionData(signonSessionData), mechanism);
}
-void MastodonNotificationsDataTypeSyncAdaptor::signOnError(const SignOn::Error &error)
+void FediverseNotificationsDataTypeSyncAdaptor::signOnError(const SignOn::Error &error)
{
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender());
Accounts::Account *account = session->property("account").value<Accounts::Account*>();
SignOn::Identity *identity = session->property("identity").value<SignOn::Identity*>();
const int accountId = account->id();
- qCWarning(lcMastodonNotificationsSync) << "credentials for account with id" << accountId
+ qCWarning(lcFediverseNotificationsSync) << "credentials for account with id" << accountId
<< "couldn't be retrieved:" << error.type() << error.message();
if (error.type() == SignOn::Error::UserInteraction) {
@@ -207,9 +207,9 @@ void MastodonNotificationsDataTypeSyncAdaptor::signOnError(const SignOn::Error &
decrementSemaphore(accountId);
}
-void MastodonNotificationsDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &responseData)
+void FediverseNotificationsDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &responseData)
{
- const QVariantMap data = MastodonAuthUtils::responseDataToMap(responseData);
+ const QVariantMap data = FediverseAuthUtils::responseDataToMap(responseData);
QString accessToken;
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender());
@@ -217,13 +217,13 @@ void MastodonNotificationsDataTypeSyncAdaptor::signOnResponse(const SignOn::Sess
SignOn::Identity *identity = session->property("identity").value<SignOn::Identity*>();
const int accountId = account->id();
- accessToken = MastodonAuthUtils::accessToken(data);
+ accessToken = FediverseAuthUtils::accessToken(data);
if (accessToken.isEmpty()) {
- qCWarning(lcMastodonNotificationsSync) << "signon response for account with id" << accountId
+ qCWarning(lcFediverseNotificationsSync) << "signon response for account with id" << accountId
<< "contained no access token; keys:" << data.keys();
}
- m_apiHosts.insert(accountId, MastodonAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString()));
+ m_apiHosts.insert(accountId, FediverseAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString()));
session->disconnect(this);
identity->destroySession(session);
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversedatatypesyncadaptor.h
index 3c61ade..0acbc87 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversedatatypesyncadaptor.h
@@ -18,8 +18,8 @@
**
****************************************************************************/
-#ifndef MASTODONNOTIFICATIONSDATATYPESYNCADAPTOR_H
-#define MASTODONNOTIFICATIONSDATATYPESYNCADAPTOR_H
+#ifndef FEDIVERSENOTIFICATIONSDATATYPESYNCADAPTOR_H
+#define FEDIVERSENOTIFICATIONSDATATYPESYNCADAPTOR_H
#include "socialnetworksyncadaptor.h"
@@ -35,13 +35,13 @@ namespace SignOn {
class SessionData;
}
-class MastodonNotificationsDataTypeSyncAdaptor : public SocialNetworkSyncAdaptor
+class FediverseNotificationsDataTypeSyncAdaptor : public SocialNetworkSyncAdaptor
{
Q_OBJECT
public:
- MastodonNotificationsDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::DataType dataType, QObject *parent);
- virtual ~MastodonNotificationsDataTypeSyncAdaptor();
+ FediverseNotificationsDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::DataType dataType, QObject *parent);
+ virtual ~FediverseNotificationsDataTypeSyncAdaptor();
void sync(const QString &dataTypeString, int accountId) override;
@@ -67,4 +67,4 @@ private:
QMap<int, QString> m_apiHosts;
};
-#endif // MASTODONNOTIFICATIONSDATATYPESYNCADAPTOR_H
+#endif // FEDIVERSENOTIFICATIONSDATATYPESYNCADAPTOR_H
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationsplugin.cpp b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationsplugin.cpp
index 9dd3724..c518e7e 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationsplugin.cpp
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationsplugin.cpp
@@ -18,8 +18,8 @@
**
****************************************************************************/
-#include "mastodonnotificationsplugin.h"
-#include "mastodonnotificationssyncadaptor.h"
+#include "fediversenotificationsplugin.h"
+#include "fediversenotificationssyncadaptor.h"
#include "socialnetworksyncadaptor.h"
#include <QCoreApplication>
@@ -55,12 +55,12 @@ void ensureNotificationTranslations()
}
AppTranslator *engineeringEnglish = new AppTranslator(app);
- engineeringEnglish->load(QStringLiteral("lipstick-jolla-home-mastodon-notifications_eng_en"),
+ engineeringEnglish->load(QStringLiteral("lipstick-jolla-home-fediverse-notifications_eng_en"),
QStringLiteral("/usr/share/translations"));
AppTranslator *translator = new AppTranslator(app);
translator->load(QLocale(),
- QStringLiteral("lipstick-jolla-home-mastodon-notifications"),
+ QStringLiteral("lipstick-jolla-home-fediverse-notifications"),
QStringLiteral("-"),
QStringLiteral("/usr/share/translations"));
@@ -68,29 +68,29 @@ void ensureNotificationTranslations()
}
}
-MastodonNotificationsPlugin::MastodonNotificationsPlugin(const QString& pluginName,
+FediverseNotificationsPlugin::FediverseNotificationsPlugin(const QString& pluginName,
const Buteo::SyncProfile& profile,
Buteo::PluginCbInterface *callbackInterface)
: SocialdButeoPlugin(pluginName, profile, callbackInterface,
- QStringLiteral("mastodon"),
+ QStringLiteral("fediverse"),
SocialNetworkSyncAdaptor::dataTypeName(SocialNetworkSyncAdaptor::Notifications))
{
ensureNotificationTranslations();
}
-MastodonNotificationsPlugin::~MastodonNotificationsPlugin()
+FediverseNotificationsPlugin::~FediverseNotificationsPlugin()
{
}
-SocialNetworkSyncAdaptor *MastodonNotificationsPlugin::createSocialNetworkSyncAdaptor()
+SocialNetworkSyncAdaptor *FediverseNotificationsPlugin::createSocialNetworkSyncAdaptor()
{
- return new MastodonNotificationsSyncAdaptor(this);
+ return new FediverseNotificationsSyncAdaptor(this);
}
-Buteo::ClientPlugin* MastodonNotificationsPluginLoader::createClientPlugin(
+Buteo::ClientPlugin* FediverseNotificationsPluginLoader::createClientPlugin(
const QString& pluginName,
const Buteo::SyncProfile& profile,
Buteo::PluginCbInterface* cbInterface)
{
- return new MastodonNotificationsPlugin(pluginName, profile, cbInterface);
+ return new FediverseNotificationsPlugin(pluginName, profile, cbInterface);
}
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationsplugin.h b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationsplugin.h
index a5a7b37..002aeb6 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationsplugin.h
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationsplugin.h
@@ -18,31 +18,31 @@
**
****************************************************************************/
-#ifndef MASTODONNOTIFICATIONSPLUGIN_H
-#define MASTODONNOTIFICATIONSPLUGIN_H
+#ifndef FEDIVERSENOTIFICATIONSPLUGIN_H
+#define FEDIVERSENOTIFICATIONSPLUGIN_H
#include "socialdbuteoplugin.h"
#include <buteosyncfw5/SyncPluginLoader.h>
-class Q_DECL_EXPORT MastodonNotificationsPlugin : public SocialdButeoPlugin
+class Q_DECL_EXPORT FediverseNotificationsPlugin : public SocialdButeoPlugin
{
Q_OBJECT
public:
- MastodonNotificationsPlugin(const QString& pluginName,
+ FediverseNotificationsPlugin(const QString& pluginName,
const Buteo::SyncProfile& profile,
Buteo::PluginCbInterface *cbInterface);
- ~MastodonNotificationsPlugin();
+ ~FediverseNotificationsPlugin();
protected:
SocialNetworkSyncAdaptor *createSocialNetworkSyncAdaptor() override;
};
-class MastodonNotificationsPluginLoader : public Buteo::SyncPluginLoader
+class FediverseNotificationsPluginLoader : public Buteo::SyncPluginLoader
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.sailfishos.plugins.sync.MastodonNotificationsPluginLoader")
+ Q_PLUGIN_METADATA(IID "org.sailfishos.plugins.sync.FediverseNotificationsPluginLoader")
Q_INTERFACES(Buteo::SyncPluginLoader)
public:
@@ -51,4 +51,4 @@ public:
Buteo::PluginCbInterface* cbInterface) override;
};
-#endif // MASTODONNOTIFICATIONSPLUGIN_H
+#endif // FEDIVERSENOTIFICATIONSPLUGIN_H
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationssyncadaptor.cpp
index 98dbbc8..2a84637 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationssyncadaptor.cpp
@@ -18,8 +18,8 @@
**
****************************************************************************/
-#include "mastodonnotificationssyncadaptor.h"
-#include "mastodontextutils.h"
+#include "fediversenotificationssyncadaptor.h"
+#include "fediversetextutils.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QLoggingCategory>
@@ -51,79 +51,79 @@
)
namespace {
- Q_LOGGING_CATEGORY(lcMastodonNotifications, "buteo.plugin.mastodon.notifications", QtWarningMsg)
+ Q_LOGGING_CATEGORY(lcFediverseNotifications, "buteo.plugin.fediverse.notifications", QtWarningMsg)
- const char *const NotificationCategory = "x-nemo.social.mastodon.notification";
+ const char *const NotificationCategory = "x-nemo.social.fediverse.notification";
const char *const NotificationIdHint = "x-nemo.sociald.notification-id";
const char *const LastFetchedNotificationIdKey = "LastFetchedNotificationId";
const int NotificationsPageLimit = 80;
const uint NotificationDismissedReason = 1;
//% "mentioned you"
- const char *const TrIdMentionedYou = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-mentioned_you");
+ const char *const TrIdMentionedYou = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-mentioned_you");
//% "boosted your post"
- const char *const TrIdBoostedYourPost = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-boosted_your_post");
+ const char *const TrIdBoostedYourPost = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-boosted_your_post");
//% "favourited your post"
- const char *const TrIdFavouritedYourPost = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-favourited_your_post");
+ const char *const TrIdFavouritedYourPost = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-favourited_your_post");
//% "started following you"
- const char *const TrIdStartedFollowingYou = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-started_following_you");
+ const char *const TrIdStartedFollowingYou = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-started_following_you");
//% "requested to follow you"
- const char *const TrIdRequestedToFollowYou = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-requested_to_follow_you");
+ const char *const TrIdRequestedToFollowYou = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-requested_to_follow_you");
//% "interacted with your poll"
- const char *const TrIdInteractedWithYourPoll = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-interacted_with_your_poll");
+ const char *const TrIdInteractedWithYourPoll = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-interacted_with_your_poll");
//% "posted"
- const char *const TrIdPosted = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-posted");
+ const char *const TrIdPosted = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-posted");
//% "updated a post"
- const char *const TrIdUpdatedPost = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-updated_post");
+ const char *const TrIdUpdatedPost = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-updated_post");
//% "signed up"
- const char *const TrIdSignedUp = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-signed_up");
+ const char *const TrIdSignedUp = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-signed_up");
//% "reported an account"
- const char *const TrIdReportedAccount = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-reported_account");
+ const char *const TrIdReportedAccount = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-reported_account");
//% "received a moderation warning"
- const char *const TrIdReceivedModerationWarning = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-received_moderation_warning");
+ const char *const TrIdReceivedModerationWarning = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-received_moderation_warning");
//% "quoted your post"
- const char *const TrIdQuotedYourPost = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-quoted_your_post");
+ const char *const TrIdQuotedYourPost = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-quoted_your_post");
//% "updated a post that quoted you"
- const char *const TrIdUpdatedQuotedPost = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-updated_quoted_post");
+ const char *const TrIdUpdatedQuotedPost = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-updated_quoted_post");
//% "sent you a notification"
- const char *const TrIdSentNotification = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-sent_notification");
+ const char *const TrIdSentNotification = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-sent_notification");
//% "An admin blocked an instance"
- const char *const TrIdAdminBlockedInstance = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-admin_blocked_instance");
+ const char *const TrIdAdminBlockedInstance = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-admin_blocked_instance");
//% "An admin blocked %1"
- const char *const TrIdAdminBlockedTarget = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-admin_blocked_target");
+ const char *const TrIdAdminBlockedTarget = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-admin_blocked_target");
//% "You blocked an instance"
- const char *const TrIdYouBlockedInstance = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-you_blocked_instance");
+ const char *const TrIdYouBlockedInstance = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-you_blocked_instance");
//% "You blocked %1"
- const char *const TrIdYouBlockedTarget = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-you_blocked_target");
+ const char *const TrIdYouBlockedTarget = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-you_blocked_target");
//% "An account was suspended"
- const char *const TrIdAccountSuspended = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-account_suspended");
+ const char *const TrIdAccountSuspended = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-account_suspended");
//% "%1 was suspended"
- const char *const TrIdTargetSuspended = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-target_suspended");
+ const char *const TrIdTargetSuspended = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-target_suspended");
//% "Some follow relationships were severed"
- const char *const TrIdRelationshipsSevered = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-relationships_severed");
+ const char *const TrIdRelationshipsSevered = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-relationships_severed");
//% "%1 (%2 followers, %3 following removed)"
- const char *const TrIdRelationshipsSummary = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-relationships_summary");
+ const char *const TrIdRelationshipsSummary = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-relationships_summary");
//% "A moderator sent you a warning"
- const char *const TrIdModeratorWarningNone = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_none");
+ const char *const TrIdModeratorWarningNone = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_none");
//% "A moderator disabled your account"
- const char *const TrIdModeratorWarningDisable = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_disable");
+ const char *const TrIdModeratorWarningDisable = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_disable");
//% "A moderator marked specific posts as sensitive"
- const char *const TrIdModeratorWarningSpecificSensitive = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_specific_sensitive");
+ const char *const TrIdModeratorWarningSpecificSensitive = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_specific_sensitive");
//% "A moderator deleted specific posts"
- const char *const TrIdModeratorWarningDeletePosts = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_delete_posts");
+ const char *const TrIdModeratorWarningDeletePosts = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_delete_posts");
//% "A moderator marked all your posts as sensitive"
- const char *const TrIdModeratorWarningAllSensitive = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_all_sensitive");
+ const char *const TrIdModeratorWarningAllSensitive = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_all_sensitive");
//% "A moderator limited your account"
- const char *const TrIdModeratorWarningSilence = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_silence");
+ const char *const TrIdModeratorWarningSilence = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_silence");
//% "A moderator suspended your account"
- const char *const TrIdModeratorWarningSuspend = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-moderator_warning_suspend");
+ const char *const TrIdModeratorWarningSuspend = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-moderator_warning_suspend");
- //% "Mastodon"
- const char *const TrIdMastodon = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-mastodon");
+ //% "Fediverse"
+ const char *const TrIdFediverse = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-fediverse");
//% "New notification"
- const char *const TrIdNewNotification = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-new_notification");
+ const char *const TrIdNewNotification = QT_TRID_NOOP("lipstick-jolla-home-la-fediverse-notification-new_notification");
QString displayNameForAccount(const QJsonObject &account)
{
@@ -290,27 +290,27 @@ namespace {
}
-MastodonNotificationsSyncAdaptor::MastodonNotificationsSyncAdaptor(QObject *parent)
- : MastodonNotificationsDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Notifications, parent)
+FediverseNotificationsSyncAdaptor::FediverseNotificationsSyncAdaptor(QObject *parent)
+ : FediverseNotificationsDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Notifications, parent)
{
setInitialActive(true);
}
-MastodonNotificationsSyncAdaptor::~MastodonNotificationsSyncAdaptor()
+FediverseNotificationsSyncAdaptor::~FediverseNotificationsSyncAdaptor()
{
}
-QString MastodonNotificationsSyncAdaptor::syncServiceName() const
+QString FediverseNotificationsSyncAdaptor::syncServiceName() const
{
- return QStringLiteral("mastodon-notifications");
+ return QStringLiteral("fediverse-notifications");
}
-QString MastodonNotificationsSyncAdaptor::authServiceName() const
+QString FediverseNotificationsSyncAdaptor::authServiceName() const
{
- return QStringLiteral("mastodon-microblog");
+ return QStringLiteral("fediverse-microblog");
}
-void MastodonNotificationsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSyncAdaptor::PurgeMode)
+void FediverseNotificationsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSyncAdaptor::PurgeMode)
{
closeAccountNotifications(oldId);
@@ -320,33 +320,33 @@ void MastodonNotificationsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialN
saveLastFetchedId(oldId, QString());
}
-void MastodonNotificationsSyncAdaptor::beginSync(int accountId, const QString &accessToken)
+void FediverseNotificationsSyncAdaptor::beginSync(int accountId, const QString &accessToken)
{
m_accessTokens.insert(accountId, accessToken);
m_pendingSyncStates.remove(accountId);
requestUnreadMarker(accountId, accessToken);
}
-void MastodonNotificationsSyncAdaptor::finalize(int accountId)
+void FediverseNotificationsSyncAdaptor::finalize(int accountId)
{
if (syncAborted()) {
- qCInfo(lcMastodonNotifications) << "sync aborted, won't update notifications";
+ qCInfo(lcFediverseNotifications) << "sync aborted, won't update notifications";
}
Q_UNUSED(accountId)
}
-QString MastodonNotificationsSyncAdaptor::sanitizeContent(const QString &content)
+QString FediverseNotificationsSyncAdaptor::sanitizeContent(const QString &content)
{
- return MastodonTextUtils::sanitizeContent(content);
+ return FediverseTextUtils::sanitizeContent(content);
}
-QDateTime MastodonNotificationsSyncAdaptor::parseTimestamp(const QString &timestampString)
+QDateTime FediverseNotificationsSyncAdaptor::parseTimestamp(const QString &timestampString)
{
- return MastodonTextUtils::parseTimestamp(timestampString);
+ return FediverseTextUtils::parseTimestamp(timestampString);
}
-int MastodonNotificationsSyncAdaptor::compareNotificationIds(const QString &left, const QString &right)
+int FediverseNotificationsSyncAdaptor::compareNotificationIds(const QString &left, const QString &right)
{
if (left == right) {
return 0;
@@ -366,12 +366,12 @@ int MastodonNotificationsSyncAdaptor::compareNotificationIds(const QString &left
return left < right ? -1 : 1;
}
-QString MastodonNotificationsSyncAdaptor::notificationObjectKey(int accountId, const QString &notificationId)
+QString FediverseNotificationsSyncAdaptor::notificationObjectKey(int accountId, const QString &notificationId)
{
return QString::number(accountId) + QLatin1Char(':') + notificationId;
}
-QString MastodonNotificationsSyncAdaptor::loadLastFetchedId(int accountId) const
+QString FediverseNotificationsSyncAdaptor::loadLastFetchedId(int accountId) const
{
Accounts::Account *account = Accounts::Account::fromId(m_accountManager, accountId, 0);
if (!account) {
@@ -386,7 +386,7 @@ QString MastodonNotificationsSyncAdaptor::loadLastFetchedId(int accountId) const
return lastFetchedId;
}
-void MastodonNotificationsSyncAdaptor::saveLastFetchedId(int accountId, const QString &lastFetchedId)
+void FediverseNotificationsSyncAdaptor::saveLastFetchedId(int accountId, const QString &lastFetchedId)
{
Accounts::Account *account = Accounts::Account::fromId(m_accountManager, accountId, 0);
if (!account) {
@@ -404,7 +404,7 @@ void MastodonNotificationsSyncAdaptor::saveLastFetchedId(int accountId, const QS
account->deleteLater();
}
-void MastodonNotificationsSyncAdaptor::requestUnreadMarker(int accountId, const QString &accessToken)
+void FediverseNotificationsSyncAdaptor::requestUnreadMarker(int accountId, const QString &accessToken)
{
QUrl url(apiHost(accountId) + QStringLiteral("/api/v1/markers"));
@@ -426,11 +426,11 @@ void MastodonNotificationsSyncAdaptor::requestUnreadMarker(int accountId, const
incrementSemaphore(accountId);
setupReplyTimeout(accountId, reply);
} else {
- qCWarning(lcMastodonNotifications) << "unable to request notifications marker from Mastodon account with id" << accountId;
+ qCWarning(lcFediverseNotifications) << "unable to request notifications marker from Fediverse account with id" << accountId;
}
}
-void MastodonNotificationsSyncAdaptor::finishedUnreadMarkerHandler()
+void FediverseNotificationsSyncAdaptor::finishedUnreadMarkerHandler()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) {
@@ -449,7 +449,7 @@ void MastodonNotificationsSyncAdaptor::finishedUnreadMarkerHandler()
bool ok = false;
const QJsonObject markerObject = parseJsonObjectReplyData(replyData, &ok);
if (isError || !ok) {
- qCWarning(lcMastodonNotifications) << "unable to parse notifications marker data from request with account"
+ qCWarning(lcFediverseNotifications) << "unable to parse notifications marker data from request with account"
<< accountId << ", got:" << QString::fromUtf8(replyData);
PendingSyncState fallbackState;
fallbackState.accessToken = accessToken;
@@ -482,7 +482,7 @@ void MastodonNotificationsSyncAdaptor::finishedUnreadMarkerHandler()
decrementSemaphore(accountId);
}
-void MastodonNotificationsSyncAdaptor::requestNotifications(int accountId,
+void FediverseNotificationsSyncAdaptor::requestNotifications(int accountId,
const QString &accessToken,
const QString &minId,
const QString &maxId)
@@ -514,11 +514,11 @@ void MastodonNotificationsSyncAdaptor::requestNotifications(int accountId,
incrementSemaphore(accountId);
setupReplyTimeout(accountId, reply);
} else {
- qCWarning(lcMastodonNotifications) << "unable to request notifications from Mastodon account with id" << accountId;
+ qCWarning(lcFediverseNotifications) << "unable to request notifications from Fediverse account with id" << accountId;
}
}
-void MastodonNotificationsSyncAdaptor::requestMarkRead(int accountId,
+void FediverseNotificationsSyncAdaptor::requestMarkRead(int accountId,
const QString &accessToken,
const QString &lastReadId)
{
@@ -542,11 +542,11 @@ void MastodonNotificationsSyncAdaptor::requestMarkRead(int accountId,
incrementSemaphore(accountId);
setupReplyTimeout(accountId, reply);
} else {
- qCWarning(lcMastodonNotifications) << "unable to update notifications marker for Mastodon account with id" << accountId;
+ qCWarning(lcFediverseNotifications) << "unable to update notifications marker for Fediverse account with id" << accountId;
}
}
-void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler()
+void FediverseNotificationsSyncAdaptor::finishedNotificationsHandler()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) {
@@ -580,7 +580,7 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler()
const QJsonArray notifications = parseJsonArrayReplyData(replyData, &ok);
if (!isError && ok) {
if (!notifications.size()) {
- qCDebug(lcMastodonNotifications) << "no notifications received for account" << accountId;
+ qCDebug(lcFediverseNotifications) << "no notifications received for account" << accountId;
if (state.markerKnown) {
closeAccountNotifications(accountId);
}
@@ -682,7 +682,7 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler()
PendingNotification pendingNotification;
pendingNotification.notificationId = notificationId;
pendingNotification.summary = useSystemSummary(notificationType)
- ? qtTrId(TrIdMastodon)
+ ? qtTrId(TrIdFediverse)
: displayName;
pendingNotification.body = body;
pendingNotification.link = url;
@@ -737,7 +737,7 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler()
maybeMarkAccountNotificationsRead(accountId, state.accessToken);
}
} else {
- qCWarning(lcMastodonNotifications) << "unable to parse notifications data from request with account" << accountId
+ qCWarning(lcFediverseNotifications) << "unable to parse notifications data from request with account" << accountId
<< ", got:" << QString::fromUtf8(replyData);
}
@@ -745,7 +745,7 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler()
decrementSemaphore(accountId);
}
-void MastodonNotificationsSyncAdaptor::finishedMarkReadHandler()
+void FediverseNotificationsSyncAdaptor::finishedMarkReadHandler()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
if (!reply) {
@@ -769,14 +769,14 @@ void MastodonNotificationsSyncAdaptor::finishedMarkReadHandler()
m_lastMarkedReadIds.insert(accountId, lastReadId);
}
} else {
- qCWarning(lcMastodonNotifications) << "unable to update notifications marker for account" << accountId
+ qCWarning(lcFediverseNotifications) << "unable to update notifications marker for account" << accountId
<< ", got:" << QString::fromUtf8(replyData);
}
decrementSemaphore(accountId);
}
-void MastodonNotificationsSyncAdaptor::publishSystemNotification(int accountId,
+void FediverseNotificationsSyncAdaptor::publishSystemNotification(int accountId,
const PendingNotification &notificationData)
{
Notification *notification = createNotification(accountId, notificationData.notificationId);
@@ -785,7 +785,7 @@ void MastodonNotificationsSyncAdaptor::publishSystemNotification(int accountId,
? notificationData.timestamp
: QDateTime::currentDateTimeUtc());
notification->setSummary(notificationData.summary.isEmpty()
- ? qtTrId(TrIdMastodon)
+ ? qtTrId(TrIdFediverse)
: notificationData.summary);
notification->setBody(notificationData.body.isEmpty()
? qtTrId(TrIdNewNotification)
@@ -806,12 +806,12 @@ void MastodonNotificationsSyncAdaptor::publishSystemNotification(int accountId,
notification->setRemoteAction(OPEN_URL_ACTION(authorizeInteractionUrl(apiHost(accountId), safeOpenUrl)));
notification->publish();
if (notification->replacesId() == 0) {
- qCWarning(lcMastodonNotifications) << "failed to publish Mastodon notification"
+ qCWarning(lcFediverseNotifications) << "failed to publish Fediverse notification"
<< notificationData.notificationId;
}
}
-void MastodonNotificationsSyncAdaptor::notificationClosedWithReason(uint reason)
+void FediverseNotificationsSyncAdaptor::notificationClosedWithReason(uint reason)
{
Notification *notification = qobject_cast<Notification *>(sender());
removeCachedNotification(notification);
@@ -820,7 +820,7 @@ void MastodonNotificationsSyncAdaptor::notificationClosedWithReason(uint reason)
}
}
-void MastodonNotificationsSyncAdaptor::maybeMarkAccountNotificationsRead(int accountId,
+void FediverseNotificationsSyncAdaptor::maybeMarkAccountNotificationsRead(int accountId,
const QString &accessToken,
Notification *ignoredNotification)
{
@@ -845,7 +845,7 @@ void MastodonNotificationsSyncAdaptor::maybeMarkAccountNotificationsRead(int acc
requestMarkRead(accountId, accessToken, lastReadId);
}
-void MastodonNotificationsSyncAdaptor::markReadFromNotification(Notification *notification)
+void FediverseNotificationsSyncAdaptor::markReadFromNotification(Notification *notification)
{
if (!notification) {
return;
@@ -860,7 +860,7 @@ void MastodonNotificationsSyncAdaptor::markReadFromNotification(Notification *no
maybeMarkAccountNotificationsRead(accountId, accessToken, notification);
}
-void MastodonNotificationsSyncAdaptor::removeCachedNotification(Notification *notification)
+void FediverseNotificationsSyncAdaptor::removeCachedNotification(Notification *notification)
{
if (!notification) {
return;
@@ -875,7 +875,7 @@ void MastodonNotificationsSyncAdaptor::removeCachedNotification(Notification *no
m_notificationObjects.remove(notificationObjectKey(accountId, notificationId));
}
-void MastodonNotificationsSyncAdaptor::closeAccountNotifications(int accountId,
+void FediverseNotificationsSyncAdaptor::closeAccountNotifications(int accountId,
const QSet<QString> &keepNotificationIds)
{
QStringList cachedKeys = m_notificationObjects.keys();
@@ -918,7 +918,7 @@ void MastodonNotificationsSyncAdaptor::closeAccountNotifications(int accountId,
}
}
-Notification *MastodonNotificationsSyncAdaptor::createNotification(int accountId, const QString &notificationId)
+Notification *FediverseNotificationsSyncAdaptor::createNotification(int accountId, const QString &notificationId)
{
const QString objectKey = notificationObjectKey(accountId, notificationId);
Notification *notification = m_notificationObjects.value(objectKey);
@@ -931,8 +931,8 @@ Notification *MastodonNotificationsSyncAdaptor::createNotification(int accountId
notification->setParent(this);
}
- notification->setAppName(QStringLiteral("Mastodon"));
- notification->setAppIcon(QStringLiteral("icon-l-mastodon"));
+ notification->setAppName(QStringLiteral("Fediverse"));
+ notification->setAppIcon(QStringLiteral("icon-l-fediverse"));
notification->setHintValue("x-nemo.sociald.account-id", accountId);
notification->setHintValue(NotificationIdHint, notificationId);
notification->setHintValue("x-nemo-feedback", QStringLiteral("social"));
@@ -945,7 +945,7 @@ Notification *MastodonNotificationsSyncAdaptor::createNotification(int accountId
return notification;
}
-Notification *MastodonNotificationsSyncAdaptor::findNotification(int accountId, const QString &notificationId)
+Notification *FediverseNotificationsSyncAdaptor::findNotification(int accountId, const QString &notificationId)
{
Notification *notification = 0;
QList<QObject *> notifications = Notification::notifications();
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationssyncadaptor.h
index 0e9106c..24f2745 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-notifications/fediversenotificationssyncadaptor.h
@@ -18,10 +18,10 @@
**
****************************************************************************/
-#ifndef MASTODONNOTIFICATIONSSYNCADAPTOR_H
-#define MASTODONNOTIFICATIONSSYNCADAPTOR_H
+#ifndef FEDIVERSENOTIFICATIONSSYNCADAPTOR_H
+#define FEDIVERSENOTIFICATIONSSYNCADAPTOR_H
-#include "mastodondatatypesyncadaptor.h"
+#include "fediversedatatypesyncadaptor.h"
#include <QtCore/QDateTime>
#include <QtCore/QHash>
@@ -30,13 +30,13 @@
class Notification;
-class MastodonNotificationsSyncAdaptor : public MastodonNotificationsDataTypeSyncAdaptor
+class FediverseNotificationsSyncAdaptor : public FediverseNotificationsDataTypeSyncAdaptor
{
Q_OBJECT
public:
- MastodonNotificationsSyncAdaptor(QObject *parent);
- ~MastodonNotificationsSyncAdaptor();
+ FediverseNotificationsSyncAdaptor(QObject *parent);
+ ~FediverseNotificationsSyncAdaptor();
QString syncServiceName() const override;
@@ -101,4 +101,4 @@ private:
QHash<QString, Notification *> m_notificationObjects;
};
-#endif // MASTODONNOTIFICATIONSSYNCADAPTOR_H
+#endif // FEDIVERSENOTIFICATIONSSYNCADAPTOR_H
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro b/buteo-plugins/buteo-sync-plugin-fediverse-posts/buteo-sync-plugin-fediverse-posts.pro
index a9f65af..d9936b0 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/buteo-sync-plugin-fediverse-posts.pro
@@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause
-TARGET = mastodon-posts-client
+TARGET = fediverse-posts-client
QT -= gui
@@ -15,27 +15,27 @@ PKGCONFIG += mlite5 nemonotifications-qt5
INCLUDEPATH += $$PWD
SOURCES += \
- $$PWD/mastodondatatypesyncadaptor.cpp \
- $$PWD/mastodonpostsplugin.cpp \
- $$PWD/mastodonpostssyncadaptor.cpp
+ $$PWD/fediversedatatypesyncadaptor.cpp \
+ $$PWD/fediversepostsplugin.cpp \
+ $$PWD/fediversepostssyncadaptor.cpp
HEADERS += \
- $$PWD/mastodondatatypesyncadaptor.h \
- $$PWD/mastodonpostsplugin.h \
- $$PWD/mastodonpostssyncadaptor.h
+ $$PWD/fediversedatatypesyncadaptor.h \
+ $$PWD/fediversepostsplugin.h \
+ $$PWD/fediversepostssyncadaptor.h
OTHER_FILES += \
- $$PWD/mastodon-posts.xml \
- $$PWD/mastodon.Posts.xml
+ $$PWD/fediverse-posts.xml \
+ $$PWD/fediverse.Posts.xml
TEMPLATE = lib
CONFIG += plugin
target.path = $$[QT_INSTALL_LIBS]/buteo-plugins-qt5/oopp
sync.path = /etc/buteo/profiles/sync
-sync.files = mastodon.Posts.xml
+sync.files = fediverse.Posts.xml
client.path = /etc/buteo/profiles/client
-client.files = mastodon-posts.xml
+client.files = fediverse-posts.xml
INSTALLS += target sync client
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediverse-posts.xml
index c1e25ae..4397ff0 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediverse-posts.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<profile name="mastodon-posts" type="client" >
+<profile name="fediverse-posts" type="client" >
<field name="Sync Direction" />
</profile>
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediverse.Posts.xml
index c7e2448..6601313 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediverse.Posts.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<profile name="mastodon.Posts" type="sync" >
+<profile name="fediverse.Posts" type="sync" >
<key name="category" value="eventfeed" />
<key name="enabled" value="false" />
<key name="use_accounts" value="false" />
<key name="destinationtype" value="online" />
<key name="hidden" value="true" />
- <key name="displayname" value="Mastodon Posts"/>
+ <key name="displayname" value="Fediverse Posts"/>
<schedule enabled="false" interval="30" days="1,2,3,4,5,6,7" syncconfiguredtime="" time="" />
- <profile name="mastodon-posts" type="client" >
+ <profile name="fediverse-posts" type="client" >
<key name="Sync Direction" value="from-remote" />
</profile>
</profile>
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversedatatypesyncadaptor.cpp
index 7b47fe8..3ef6f35 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversedatatypesyncadaptor.cpp
@@ -18,10 +18,10 @@
**
****************************************************************************/
-#include "mastodondatatypesyncadaptor.h"
-#include "mastodonauthutils.h"
-#include "trace.h"
+#include "fediversedatatypesyncadaptor.h"
+#include "fediverseauthutils.h"
+#include <QtCore/QLoggingCategory>
#include <QtCore/QVariantMap>
#include <QtNetwork/QNetworkRequest>
@@ -36,21 +36,23 @@
#include <SignOn/AuthSession>
#include <SignOn/SessionData>
-MastodonDataTypeSyncAdaptor::MastodonDataTypeSyncAdaptor(
+Q_LOGGING_CATEGORY(lcFediverseSync, "buteo.plugin.fediverse.sync", QtWarningMsg)
+
+FediverseDataTypeSyncAdaptor::FediverseDataTypeSyncAdaptor(
SocialNetworkSyncAdaptor::DataType dataType,
QObject *parent)
- : SocialNetworkSyncAdaptor(QStringLiteral("mastodon"), dataType, 0, parent)
+ : SocialNetworkSyncAdaptor(QStringLiteral("fediverse"), dataType, 0, parent)
{
}
-MastodonDataTypeSyncAdaptor::~MastodonDataTypeSyncAdaptor()
+FediverseDataTypeSyncAdaptor::~FediverseDataTypeSyncAdaptor()
{
}
-void MastodonDataTypeSyncAdaptor::sync(const QString &dataTypeString, int accountId)
+void FediverseDataTypeSyncAdaptor::sync(const QString &dataTypeString, int accountId)
{
if (dataTypeString != SocialNetworkSyncAdaptor::dataTypeName(m_dataType)) {
- qCWarning(lcSocialPlugin) << "Mastodon" << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
+ qCWarning(lcFediverseSync) << "Fediverse" << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
<< "sync adaptor was asked to sync" << dataTypeString;
setStatus(SocialNetworkSyncAdaptor::Error);
return;
@@ -58,14 +60,14 @@ void MastodonDataTypeSyncAdaptor::sync(const QString &dataTypeString, int accoun
setStatus(SocialNetworkSyncAdaptor::Busy);
updateDataForAccount(accountId);
- qCDebug(lcSocialPlugin) << "successfully triggered sync with profile:" << m_accountSyncProfile->name();
+ qCDebug(lcFediverseSync) << "successfully triggered sync with profile:" << m_accountSyncProfile->name();
}
-void MastodonDataTypeSyncAdaptor::updateDataForAccount(int accountId)
+void FediverseDataTypeSyncAdaptor::updateDataForAccount(int accountId)
{
Accounts::Account *account = Accounts::Account::fromId(m_accountManager, accountId, this);
if (!account) {
- qCWarning(lcSocialPlugin) << "existing account with id" << accountId << "couldn't be retrieved";
+ qCWarning(lcFediverseSync) << "existing account with id" << accountId << "couldn't be retrieved";
setStatus(SocialNetworkSyncAdaptor::Error);
return;
}
@@ -74,12 +76,17 @@ void MastodonDataTypeSyncAdaptor::updateDataForAccount(int accountId)
signIn(account);
}
-QString MastodonDataTypeSyncAdaptor::apiHost(int accountId) const
+QString FediverseDataTypeSyncAdaptor::apiHost(int accountId) const
+{
+ return m_apiHosts.value(accountId, FediverseAuthUtils::defaultApiHost());
+}
+
+QString FediverseDataTypeSyncAdaptor::iconPath(int accountId) const
{
- return m_apiHosts.value(accountId, QStringLiteral("https://mastodon.social"));
+ return m_iconPaths.value(accountId, QStringLiteral("image://theme/icon-l-fediverse"));
}
-void MastodonDataTypeSyncAdaptor::errorHandler(QNetworkReply::NetworkError err)
+void FediverseDataTypeSyncAdaptor::errorHandler(QNetworkReply::NetworkError err)
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) {
@@ -89,7 +96,7 @@ void MastodonDataTypeSyncAdaptor::errorHandler(QNetworkReply::NetworkError err)
const int accountId = reply->property("accountId").toInt();
const int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
- qCWarning(lcSocialPlugin) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
+ qCWarning(lcFediverseSync) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
<< "request with account" << accountId
<< "experienced error:" << err
<< "HTTP:" << httpStatus;
@@ -104,7 +111,7 @@ void MastodonDataTypeSyncAdaptor::errorHandler(QNetworkReply::NetworkError err)
}
}
-void MastodonDataTypeSyncAdaptor::sslErrorsHandler(const QList<QSslError> &errs)
+void FediverseDataTypeSyncAdaptor::sslErrorsHandler(const QList<QSslError> &errs)
{
QString sslerrs;
foreach (const QSslError &e, errs) {
@@ -114,24 +121,24 @@ void MastodonDataTypeSyncAdaptor::sslErrorsHandler(const QList<QSslError> &errs)
sslerrs.chop(2);
}
- qCWarning(lcSocialPlugin) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
+ qCWarning(lcFediverseSync) << SocialNetworkSyncAdaptor::dataTypeName(m_dataType)
<< "request with account" << sender()->property("accountId").toInt()
<< "experienced ssl errors:" << sslerrs;
sender()->setProperty("isError", QVariant::fromValue<bool>(true));
}
-void MastodonDataTypeSyncAdaptor::setCredentialsNeedUpdate(Accounts::Account *account)
+void FediverseDataTypeSyncAdaptor::setCredentialsNeedUpdate(Accounts::Account *account)
{
- qCInfo(lcSocialPlugin) << "sociald:Mastodon: setting CredentialsNeedUpdate to true for account:" << account->id();
+ qCInfo(lcFediverseSync) << "sociald:Fediverse: setting CredentialsNeedUpdate to true for account:" << account->id();
Accounts::Service srv(m_accountManager->service(syncServiceName()));
account->selectService(srv);
account->setValue(QStringLiteral("CredentialsNeedUpdate"), QVariant::fromValue<bool>(true));
- account->setValue(QStringLiteral("CredentialsNeedUpdateFrom"), QVariant::fromValue<QString>(QString::fromLatin1("sociald-mastodon")));
+ account->setValue(QStringLiteral("CredentialsNeedUpdateFrom"), QVariant::fromValue<QString>(QString::fromLatin1("sociald-fediverse")));
account->selectService(Accounts::Service());
account->syncAndBlock();
}
-void MastodonDataTypeSyncAdaptor::signIn(Accounts::Account *account)
+void FediverseDataTypeSyncAdaptor::signIn(Accounts::Account *account)
{
const int accountId = account->id();
if (!checkAccount(account)) {
@@ -145,7 +152,7 @@ void MastodonDataTypeSyncAdaptor::signIn(Accounts::Account *account)
? SignOn::Identity::existingIdentity(account->credentialsId())
: 0;
if (!identity) {
- qCWarning(lcSocialPlugin) << "account" << accountId << "has no valid credentials, cannot sign in";
+ qCWarning(lcFediverseSync) << "account" << accountId << "has no valid credentials, cannot sign in";
decrementSemaphore(accountId);
return;
}
@@ -155,14 +162,14 @@ void MastodonDataTypeSyncAdaptor::signIn(Accounts::Account *account)
const QString mechanism = accSrv.authData().mechanism();
SignOn::AuthSession *session = identity->createSession(method);
if (!session) {
- qCWarning(lcSocialPlugin) << "could not create signon session for account" << accountId;
+ qCWarning(lcFediverseSync) << "could not create signon session for account" << accountId;
identity->deleteLater();
decrementSemaphore(accountId);
return;
}
QVariantMap signonSessionData = accSrv.authData().parameters();
- MastodonAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
+ FediverseAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
connect(session, SIGNAL(response(SignOn::SessionData)),
this, SLOT(signOnResponse(SignOn::SessionData)),
@@ -176,14 +183,14 @@ void MastodonDataTypeSyncAdaptor::signIn(Accounts::Account *account)
session->process(SignOn::SessionData(signonSessionData), mechanism);
}
-void MastodonDataTypeSyncAdaptor::signOnError(const SignOn::Error &error)
+void FediverseDataTypeSyncAdaptor::signOnError(const SignOn::Error &error)
{
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender());
Accounts::Account *account = session->property("account").value<Accounts::Account*>();
SignOn::Identity *identity = session->property("identity").value<SignOn::Identity*>();
const int accountId = account->id();
- qCWarning(lcSocialPlugin) << "credentials for account with id" << accountId
+ qCWarning(lcFediverseSync) << "credentials for account with id" << accountId
<< "couldn't be retrieved:" << error.type() << error.message();
if (error.type() == SignOn::Error::UserInteraction) {
@@ -199,9 +206,9 @@ void MastodonDataTypeSyncAdaptor::signOnError(const SignOn::Error &error)
decrementSemaphore(accountId);
}
-void MastodonDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &responseData)
+void FediverseDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &responseData)
{
- const QVariantMap data = MastodonAuthUtils::responseDataToMap(responseData);
+ const QVariantMap data = FediverseAuthUtils::responseDataToMap(responseData);
QString accessToken;
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender());
@@ -209,13 +216,14 @@ void MastodonDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &resp
SignOn::Identity *identity = session->property("identity").value<SignOn::Identity*>();
const int accountId = account->id();
- accessToken = MastodonAuthUtils::accessToken(data);
+ accessToken = FediverseAuthUtils::accessToken(data);
if (accessToken.isEmpty()) {
- qCWarning(lcSocialPlugin) << "signon response for account with id" << accountId
+ qCWarning(lcFediverseSync) << "signon response for account with id" << accountId
<< "contained no access token; keys:" << data.keys();
}
- m_apiHosts.insert(accountId, MastodonAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString()));
+ m_apiHosts.insert(accountId, FediverseAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString()));
+ m_iconPaths.insert(accountId, account->value(QStringLiteral("iconPath")).toString().trimmed());
session->disconnect(this);
identity->destroySession(session);
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversedatatypesyncadaptor.h
index 3ebbbf5..4511a26 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversedatatypesyncadaptor.h
@@ -18,8 +18,8 @@
**
****************************************************************************/
-#ifndef MASTODONDATATYPESYNCADAPTOR_H
-#define MASTODONDATATYPESYNCADAPTOR_H
+#ifndef FEDIVERSEDATATYPESYNCADAPTOR_H
+#define FEDIVERSEDATATYPESYNCADAPTOR_H
#include "socialnetworksyncadaptor.h"
@@ -35,18 +35,19 @@ namespace SignOn {
class SessionData;
}
-class MastodonDataTypeSyncAdaptor : public SocialNetworkSyncAdaptor
+class FediverseDataTypeSyncAdaptor : public SocialNetworkSyncAdaptor
{
Q_OBJECT
public:
- MastodonDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::DataType dataType, QObject *parent);
- virtual ~MastodonDataTypeSyncAdaptor();
+ FediverseDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::DataType dataType, QObject *parent);
+ virtual ~FediverseDataTypeSyncAdaptor();
void sync(const QString &dataTypeString, int accountId) override;
protected:
QString apiHost(int accountId) const;
+ QString iconPath(int accountId) const;
virtual void updateDataForAccount(int accountId);
virtual void beginSync(int accountId, const QString &accessToken) = 0;
@@ -64,6 +65,7 @@ private:
private:
QMap<int, QString> m_apiHosts;
+ QMap<int, QString> m_iconPaths;
};
-#endif // MASTODONDATATYPESYNCADAPTOR_H
+#endif // FEDIVERSEDATATYPESYNCADAPTOR_H
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostsplugin.cpp b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostsplugin.cpp
index a196180..c794c00 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostsplugin.cpp
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostsplugin.cpp
@@ -18,32 +18,32 @@
**
****************************************************************************/
-#include "mastodonpostsplugin.h"
-#include "mastodonpostssyncadaptor.h"
+#include "fediversepostsplugin.h"
+#include "fediversepostssyncadaptor.h"
#include "socialnetworksyncadaptor.h"
-MastodonPostsPlugin::MastodonPostsPlugin(const QString& pluginName,
+FediversePostsPlugin::FediversePostsPlugin(const QString& pluginName,
const Buteo::SyncProfile& profile,
Buteo::PluginCbInterface *callbackInterface)
: SocialdButeoPlugin(pluginName, profile, callbackInterface,
- QStringLiteral("mastodon"),
+ QStringLiteral("fediverse"),
SocialNetworkSyncAdaptor::dataTypeName(SocialNetworkSyncAdaptor::Posts))
{
}
-MastodonPostsPlugin::~MastodonPostsPlugin()
+FediversePostsPlugin::~FediversePostsPlugin()
{
}
-SocialNetworkSyncAdaptor *MastodonPostsPlugin::createSocialNetworkSyncAdaptor()
+SocialNetworkSyncAdaptor *FediversePostsPlugin::createSocialNetworkSyncAdaptor()
{
- return new MastodonPostsSyncAdaptor(this);
+ return new FediversePostsSyncAdaptor(this);
}
-Buteo::ClientPlugin* MastodonPostsPluginLoader::createClientPlugin(
+Buteo::ClientPlugin* FediversePostsPluginLoader::createClientPlugin(
const QString& pluginName,
const Buteo::SyncProfile& profile,
Buteo::PluginCbInterface* cbInterface)
{
- return new MastodonPostsPlugin(pluginName, profile, cbInterface);
+ return new FediversePostsPlugin(pluginName, profile, cbInterface);
}
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostsplugin.h b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostsplugin.h
index c8a1d6b..933cd97 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostsplugin.h
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostsplugin.h
@@ -18,31 +18,31 @@
**
****************************************************************************/
-#ifndef MASTODONPOSTSPLUGIN_H
-#define MASTODONPOSTSPLUGIN_H
+#ifndef FEDIVERSEPOSTSPLUGIN_H
+#define FEDIVERSEPOSTSPLUGIN_H
#include "socialdbuteoplugin.h"
#include <buteosyncfw5/SyncPluginLoader.h>
-class Q_DECL_EXPORT MastodonPostsPlugin : public SocialdButeoPlugin
+class Q_DECL_EXPORT FediversePostsPlugin : public SocialdButeoPlugin
{
Q_OBJECT
public:
- MastodonPostsPlugin(const QString& pluginName,
+ FediversePostsPlugin(const QString& pluginName,
const Buteo::SyncProfile& profile,
Buteo::PluginCbInterface *cbInterface);
- ~MastodonPostsPlugin();
+ ~FediversePostsPlugin();
protected:
SocialNetworkSyncAdaptor *createSocialNetworkSyncAdaptor() override;
};
-class MastodonPostsPluginLoader : public Buteo::SyncPluginLoader
+class FediversePostsPluginLoader : public Buteo::SyncPluginLoader
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.sailfishos.plugins.sync.MastodonPostsPluginLoader")
+ Q_PLUGIN_METADATA(IID "org.sailfishos.plugins.sync.FediversePostsPluginLoader")
Q_INTERFACES(Buteo::SyncPluginLoader)
public:
@@ -51,4 +51,4 @@ public:
Buteo::PluginCbInterface* cbInterface) override;
};
-#endif // MASTODONPOSTSPLUGIN_H
+#endif // FEDIVERSEPOSTSPLUGIN_H
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostssyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostssyncadaptor.cpp
index 160d6cc..59e37bf 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostssyncadaptor.cpp
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostssyncadaptor.cpp
@@ -18,10 +18,10 @@
**
****************************************************************************/
-#include "mastodonpostssyncadaptor.h"
-#include "trace.h"
-#include "mastodontextutils.h"
+#include "fediversepostssyncadaptor.h"
+#include "fediversetextutils.h"
+#include <QtCore/QLoggingCategory>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonValue>
@@ -30,6 +30,8 @@
#include <QtNetwork/QNetworkRequest>
namespace {
+ Q_LOGGING_CATEGORY(lcFediversePostsSync, "buteo.plugin.fediverse.posts.sync", QtWarningMsg)
+
QString displayNameForAccount(const QJsonObject &account)
{
const QString displayName = account.value(QStringLiteral("display_name")).toString().trimmed();
@@ -46,22 +48,22 @@ namespace {
}
}
-MastodonPostsSyncAdaptor::MastodonPostsSyncAdaptor(QObject *parent)
- : MastodonDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Posts, parent)
+FediversePostsSyncAdaptor::FediversePostsSyncAdaptor(QObject *parent)
+ : FediverseDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Posts, parent)
{
setInitialActive(m_db.isValid());
}
-MastodonPostsSyncAdaptor::~MastodonPostsSyncAdaptor()
+FediversePostsSyncAdaptor::~FediversePostsSyncAdaptor()
{
}
-QString MastodonPostsSyncAdaptor::syncServiceName() const
+QString FediversePostsSyncAdaptor::syncServiceName() const
{
- return QStringLiteral("mastodon-microblog");
+ return QStringLiteral("fediverse-microblog");
}
-void MastodonPostsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSyncAdaptor::PurgeMode)
+void FediversePostsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSyncAdaptor::PurgeMode)
{
m_db.removePosts(oldId);
m_db.commit();
@@ -72,15 +74,15 @@ void MastodonPostsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSy
purgeCachedImages(&m_imageCacheDb, oldId);
}
-void MastodonPostsSyncAdaptor::beginSync(int accountId, const QString &accessToken)
+void FediversePostsSyncAdaptor::beginSync(int accountId, const QString &accessToken)
{
requestPosts(accountId, accessToken);
}
-void MastodonPostsSyncAdaptor::finalize(int accountId)
+void FediversePostsSyncAdaptor::finalize(int accountId)
{
if (syncAborted()) {
- qCInfo(lcSocialPlugin) << "sync aborted, won't commit database changes";
+ qCInfo(lcFediversePostsSync) << "sync aborted, won't commit database changes";
} else {
m_db.commit();
m_db.wait();
@@ -90,17 +92,17 @@ void MastodonPostsSyncAdaptor::finalize(int accountId)
}
}
-QString MastodonPostsSyncAdaptor::sanitizeContent(const QString &content)
+QString FediversePostsSyncAdaptor::sanitizeContent(const QString &content)
{
- return MastodonTextUtils::sanitizeContent(content);
+ return FediverseTextUtils::sanitizeContent(content);
}
-QDateTime MastodonPostsSyncAdaptor::parseTimestamp(const QString &timestampString)
+QDateTime FediversePostsSyncAdaptor::parseTimestamp(const QString &timestampString)
{
- return MastodonTextUtils::parseTimestamp(timestampString);
+ return FediverseTextUtils::parseTimestamp(timestampString);
}
-void MastodonPostsSyncAdaptor::requestPosts(int accountId, const QString &accessToken)
+void FediversePostsSyncAdaptor::requestPosts(int accountId, const QString &accessToken)
{
QUrl url(apiHost(accountId) + QStringLiteral("/api/v1/timelines/home"));
@@ -121,11 +123,11 @@ void MastodonPostsSyncAdaptor::requestPosts(int accountId, const QString &access
incrementSemaphore(accountId);
setupReplyTimeout(accountId, reply);
} else {
- qCWarning(lcSocialPlugin) << "unable to request home timeline posts from Mastodon account with id" << accountId;
+ qCWarning(lcFediversePostsSync) << "unable to request home timeline posts from Fediverse account with id" << accountId;
}
}
-void MastodonPostsSyncAdaptor::finishedPostsHandler()
+void FediversePostsSyncAdaptor::finishedPostsHandler()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply) {
@@ -146,7 +148,7 @@ void MastodonPostsSyncAdaptor::finishedPostsHandler()
m_db.removePosts(accountId);
if (!statuses.size()) {
- qCDebug(lcSocialPlugin) << "no feed posts received for account" << accountId;
+ qCDebug(lcFediversePostsSync) << "no feed posts received for account" << accountId;
decrementSemaphore(accountId);
return;
}
@@ -231,7 +233,7 @@ void MastodonPostsSyncAdaptor::finishedPostsHandler()
}
}
- m_db.addMastodonPost(identifier,
+ m_db.addFediversePost(identifier,
displayName,
accountName,
body,
@@ -246,10 +248,11 @@ void MastodonPostsSyncAdaptor::finishedPostsHandler()
favourited,
reblogged,
apiHost(accountId),
+ iconPath(accountId),
accountId);
}
} else {
- qCWarning(lcSocialPlugin) << "unable to parse event feed data from request with account" << accountId
+ qCWarning(lcFediversePostsSync) << "unable to parse event feed data from request with account" << accountId
<< ", got:" << QString::fromUtf8(replyData);
}
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostssyncadaptor.h b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostssyncadaptor.h
index d2ca464..341e049 100644
--- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodonpostssyncadaptor.h
+++ b/buteo-plugins/buteo-sync-plugin-fediverse-posts/fediversepostssyncadaptor.h
@@ -18,24 +18,24 @@
**
****************************************************************************/
-#ifndef MASTODONPOSTSSYNCADAPTOR_H
-#define MASTODONPOSTSSYNCADAPTOR_H
+#ifndef FEDIVERSEPOSTSSYNCADAPTOR_H
+#define FEDIVERSEPOSTSSYNCADAPTOR_H
-#include "mastodondatatypesyncadaptor.h"
+#include "fediversedatatypesyncadaptor.h"
#include <QtCore/QDateTime>
#include <QtNetwork/QNetworkReply>
-#include "mastodonpostsdatabase.h"
-#include <socialcache/socialimagesdatabase.h>
+#include "fediversepostsdatabase.h"
+#include <socialimagesdatabase.h>
-class MastodonPostsSyncAdaptor : public MastodonDataTypeSyncAdaptor
+class FediversePostsSyncAdaptor : public FediverseDataTypeSyncAdaptor
{
Q_OBJECT
public:
- MastodonPostsSyncAdaptor(QObject *parent);
- ~MastodonPostsSyncAdaptor();
+ FediversePostsSyncAdaptor(QObject *parent);
+ ~FediversePostsSyncAdaptor();
QString syncServiceName() const override;
@@ -54,8 +54,8 @@ private Q_SLOTS:
void finishedPostsHandler();
private:
- MastodonPostsDatabase m_db;
+ FediversePostsDatabase m_db;
SocialImagesDatabase m_imageCacheDb;
};
-#endif // MASTODONPOSTSSYNCADAPTOR_H
+#endif // FEDIVERSEPOSTSSYNCADAPTOR_H
diff --git a/common/common.pri b/common/common.pri
index 7f593db..1e75506 100644
--- a/common/common.pri
+++ b/common/common.pri
@@ -5,4 +5,4 @@
INCLUDEPATH += $$PWD
DEPENDPATH += .
-LIBS += -L$$PWD -lmastodoncommon
+LIBS += -L$$PWD -lfediversecommon
diff --git a/common/common.pro b/common/common.pro
index c01e571..13aadb0 100644
--- a/common/common.pro
+++ b/common/common.pro
@@ -10,16 +10,16 @@ QT += sql
CONFIG += link_pkgconfig
PKGCONFIG += socialcache
-TARGET = mastodoncommon
+TARGET = fediversecommon
TARGET = $$qtLibraryTarget($$TARGET)
HEADERS += \
- $$PWD/mastodonauthutils.h \
- $$PWD/mastodontextutils.h \
- $$PWD/mastodonpostsdatabase.h
+ $$PWD/fediverseauthutils.h \
+ $$PWD/fediversetextutils.h \
+ $$PWD/fediversepostsdatabase.h
SOURCES += \
- $$PWD/mastodonpostsdatabase.cpp
+ $$PWD/fediversepostsdatabase.cpp
TARGETPATH = $$[QT_INSTALL_LIBS]
target.path = $$TARGETPATH
diff --git a/common/mastodonauthutils.h b/common/fediverseauthutils.h
index 3f1fc85..01f264a 100644
--- a/common/mastodonauthutils.h
+++ b/common/fediverseauthutils.h
@@ -16,8 +16,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef MASTODONAUTHUTILS_H
-#define MASTODONAUTHUTILS_H
+#ifndef FEDIVERSEAUTHUTILS_H
+#define FEDIVERSEAUTHUTILS_H
#include <QtCore/QVariantMap>
#include <QtCore/QUrl>
@@ -26,13 +26,23 @@
#include <SignOn/SessionData>
-namespace MastodonAuthUtils {
+namespace FediverseAuthUtils {
+
+inline QString defaultServerHost()
+{
+ return QStringLiteral("mastodon.social");
+}
+
+inline QString defaultApiHost()
+{
+ return QStringLiteral("https://") + defaultServerHost();
+}
inline QString normalizeApiHost(const QString &rawHost)
{
QString host = rawHost.trimmed();
if (host.isEmpty()) {
- host = QStringLiteral("https://mastodon.social");
+ host = defaultServerHost();
}
if (!host.startsWith(QLatin1String("https://"))
&& !host.startsWith(QLatin1String("http://"))) {
@@ -41,7 +51,7 @@ inline QString normalizeApiHost(const QString &rawHost)
QUrl url(host);
if (!url.isValid() || url.host().isEmpty()) {
- return QStringLiteral("https://mastodon.social");
+ return defaultApiHost();
}
QString normalized = QString::fromLatin1(url.toEncoded(QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment));
@@ -72,7 +82,7 @@ inline QString signOnHost(Accounts::Account *account)
configuredHost.chop(1);
}
if (configuredHost.isEmpty()) {
- configuredHost = QStringLiteral("mastodon.social");
+ configuredHost = defaultServerHost();
}
return configuredHost;
@@ -138,6 +148,6 @@ inline QVariantMap responseDataToMap(const SignOn::SessionData &responseData)
return data;
}
-} // namespace MastodonAuthUtils
+} // namespace FediverseAuthUtils
-#endif // MASTODONAUTHUTILS_H
+#endif // FEDIVERSEAUTHUTILS_H
diff --git a/common/mastodonpostsdatabase.cpp b/common/fediversepostsdatabase.cpp
index 7f82162..50bdf96 100644
--- a/common/mastodonpostsdatabase.cpp
+++ b/common/fediversepostsdatabase.cpp
@@ -16,9 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "mastodonpostsdatabase.h"
+#include "fediversepostsdatabase.h"
-static const char *DB_NAME = "mastodon.db";
+namespace {
+
+QVariantMap postExtra(const SocialPost::ConstPtr &post)
+{
+ return post ? post->extra() : QVariantMap();
+}
+
+QString extraString(const SocialPost::ConstPtr &post, const char *key)
+{
+ return postExtra(post).value(QString::fromLatin1(key)).toString();
+}
+
+int extraInt(const SocialPost::ConstPtr &post, const char *key, int defaultValue = 0)
+{
+ return postExtra(post).value(QString::fromLatin1(key), defaultValue).toInt();
+}
+
+bool extraBool(const SocialPost::ConstPtr &post, const char *key, bool defaultValue = false)
+{
+ return postExtra(post).value(QString::fromLatin1(key), defaultValue).toBool();
+}
+
+}
+
+static const char *DB_NAME = "fediverse.db";
static const char *ACCOUNT_NAME_KEY = "account_name";
static const char *URL_KEY = "url";
static const char *BOOSTED_BY_KEY = "boosted_by";
@@ -28,17 +52,18 @@ static const char *REBLOGS_COUNT_KEY = "reblogs_count";
static const char *FAVOURITED_KEY = "favourited";
static const char *REBLOGGED_KEY = "reblogged";
static const char *INSTANCE_URL_KEY = "instance_url";
+static const char *INSTANCE_ICON_PATH_KEY = "instance_icon_path";
-MastodonPostsDatabase::MastodonPostsDatabase()
- : AbstractSocialPostCacheDatabase(QStringLiteral("mastodon"), QLatin1String(DB_NAME))
+FediversePostsDatabase::FediversePostsDatabase()
+ : AbstractSocialPostCacheDatabase(QStringLiteral("fediverse"), QLatin1String(DB_NAME))
{
}
-MastodonPostsDatabase::~MastodonPostsDatabase()
+FediversePostsDatabase::~FediversePostsDatabase()
{
}
-void MastodonPostsDatabase::addMastodonPost(
+void FediversePostsDatabase::addFediversePost(
const QString &identifier,
const QString &name,
const QString &accountName,
@@ -54,6 +79,7 @@ void MastodonPostsDatabase::addMastodonPost(
bool favourited,
bool reblogged,
const QString &instanceUrl,
+ const QString &instanceIconPath,
int account)
{
QVariantMap extra;
@@ -66,77 +92,56 @@ void MastodonPostsDatabase::addMastodonPost(
extra.insert(FAVOURITED_KEY, favourited);
extra.insert(REBLOGGED_KEY, reblogged);
extra.insert(INSTANCE_URL_KEY, instanceUrl);
+ extra.insert(INSTANCE_ICON_PATH_KEY, instanceIconPath);
addPost(identifier, name, body, timestamp, icon, images, extra, account);
}
-QString MastodonPostsDatabase::accountName(const SocialPost::ConstPtr &post)
+QString FediversePostsDatabase::accountName(const SocialPost::ConstPtr &post)
+{
+ return extraString(post, ACCOUNT_NAME_KEY);
+}
+
+QString FediversePostsDatabase::url(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return QString();
- }
- return post->extra().value(ACCOUNT_NAME_KEY).toString();
+ return extraString(post, URL_KEY);
}
-QString MastodonPostsDatabase::url(const SocialPost::ConstPtr &post)
+QString FediversePostsDatabase::boostedBy(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return QString();
- }
- return post->extra().value(URL_KEY).toString();
+ return extraString(post, BOOSTED_BY_KEY);
}
-QString MastodonPostsDatabase::boostedBy(const SocialPost::ConstPtr &post)
+int FediversePostsDatabase::repliesCount(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return QString();
- }
- return post->extra().value(BOOSTED_BY_KEY).toString();
+ return extraInt(post, REPLIES_COUNT_KEY);
}
-int MastodonPostsDatabase::repliesCount(const SocialPost::ConstPtr &post)
+int FediversePostsDatabase::favouritesCount(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return 0;
- }
- return post->extra().value(REPLIES_COUNT_KEY).toInt();
+ return extraInt(post, FAVOURITES_COUNT_KEY);
}
-int MastodonPostsDatabase::favouritesCount(const SocialPost::ConstPtr &post)
+int FediversePostsDatabase::reblogsCount(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return 0;
- }
- return post->extra().value(FAVOURITES_COUNT_KEY).toInt();
+ return extraInt(post, REBLOGS_COUNT_KEY);
}
-int MastodonPostsDatabase::reblogsCount(const SocialPost::ConstPtr &post)
+bool FediversePostsDatabase::favourited(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return 0;
- }
- return post->extra().value(REBLOGS_COUNT_KEY).toInt();
+ return extraBool(post, FAVOURITED_KEY);
}
-bool MastodonPostsDatabase::favourited(const SocialPost::ConstPtr &post)
+bool FediversePostsDatabase::reblogged(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return false;
- }
- return post->extra().value(FAVOURITED_KEY).toBool();
+ return extraBool(post, REBLOGGED_KEY);
}
-bool MastodonPostsDatabase::reblogged(const SocialPost::ConstPtr &post)
+QString FediversePostsDatabase::instanceUrl(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return false;
- }
- return post->extra().value(REBLOGGED_KEY).toBool();
+ return extraString(post, INSTANCE_URL_KEY);
}
-QString MastodonPostsDatabase::instanceUrl(const SocialPost::ConstPtr &post)
+QString FediversePostsDatabase::instanceIconPath(const SocialPost::ConstPtr &post)
{
- if (post.isNull()) {
- return QString();
- }
- return post->extra().value(INSTANCE_URL_KEY).toString();
+ return extraString(post, INSTANCE_ICON_PATH_KEY);
}
diff --git a/common/mastodonpostsdatabase.h b/common/fediversepostsdatabase.h
index 9736fa8..2c085e0 100644
--- a/common/mastodonpostsdatabase.h
+++ b/common/fediversepostsdatabase.h
@@ -16,19 +16,19 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef MASTODONPOSTSDATABASE_H
-#define MASTODONPOSTSDATABASE_H
+#ifndef FEDIVERSEPOSTSDATABASE_H
+#define FEDIVERSEPOSTSDATABASE_H
-#include <socialcache/abstractsocialpostcachedatabase.h>
+#include <abstractsocialpostcachedatabase.h>
-class MastodonPostsDatabase: public AbstractSocialPostCacheDatabase
+class FediversePostsDatabase: public AbstractSocialPostCacheDatabase
{
Q_OBJECT
public:
- MastodonPostsDatabase();
- ~MastodonPostsDatabase();
+ FediversePostsDatabase();
+ ~FediversePostsDatabase();
- void addMastodonPost(const QString &identifier, const QString &name,
+ void addFediversePost(const QString &identifier, const QString &name,
const QString &accountName, const QString &body,
const QDateTime &timestamp,
const QString &icon,
@@ -37,6 +37,7 @@ public:
int repliesCount, int favouritesCount, int reblogsCount,
bool favourited, bool reblogged,
const QString &instanceUrl,
+ const QString &instanceIconPath,
int account);
static QString accountName(const SocialPost::ConstPtr &post);
@@ -48,6 +49,7 @@ public:
static bool favourited(const SocialPost::ConstPtr &post);
static bool reblogged(const SocialPost::ConstPtr &post);
static QString instanceUrl(const SocialPost::ConstPtr &post);
+ static QString instanceIconPath(const SocialPost::ConstPtr &post);
};
-#endif // MASTODONPOSTSDATABASE_H
+#endif // FEDIVERSEPOSTSDATABASE_H
diff --git a/common/mastodontextutils.h b/common/fediversetextutils.h
index bde74c4..4fa7aed 100644
--- a/common/mastodontextutils.h
+++ b/common/fediversetextutils.h
@@ -16,14 +16,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef MASTODONTEXTUTILS_H
-#define MASTODONTEXTUTILS_H
+#ifndef FEDIVERSETEXTUTILS_H
+#define FEDIVERSETEXTUTILS_H
#include <QtCore/QDateTime>
#include <QtCore/QRegularExpression>
#include <QtCore/QString>
-namespace MastodonTextUtils {
+namespace FediverseTextUtils {
inline QString decodeHtmlEntities(QString text)
{
@@ -117,6 +117,6 @@ inline QDateTime parseTimestamp(const QString &timestampString)
return timestamp;
}
-} // namespace MastodonTextUtils
+} // namespace FediverseTextUtils
-#endif // MASTODONTEXTUTILS_H
+#endif // FEDIVERSETEXTUTILS_H
diff --git a/eventsview-plugins/eventsview-plugin-fediverse/FediverseFeedItem.qml b/eventsview-plugins/eventsview-plugin-fediverse/FediverseFeedItem.qml
new file mode 100644
index 0000000..16dc191
--- /dev/null
+++ b/eventsview-plugins/eventsview-plugin-fediverse/FediverseFeedItem.qml
@@ -0,0 +1,362 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import Sailfish.Share 1.0
+import Sailfish.TextLinking 1.0
+import org.nemomobile.lipstick 0.1
+import "shared"
+
+SocialMediaFeedItem {
+ id: item
+
+ property variant imageList
+ property string resolvedStatusUrl: model && model.url ? model.url.toString() : ""
+ property string postId
+ property QtObject postActions
+ property int likeCount: model && model.favouritesCount ? model.favouritesCount : 0
+ property int commentCount: model && model.repliesCount ? model.repliesCount : 0
+ property int boostCount: model && model.reblogsCount ? model.reblogsCount : 0
+ property bool favourited: model ? !!model.favourited : false
+ property bool reblogged: model ? !!model.reblogged : false
+ property int _likeCountOverride: -1
+ property int _boostCountOverride: -1
+ property int _favouritedOverride: -1
+ property int _rebloggedOverride: -1
+ property bool isFavourited: _favouritedOverride >= 0 ? _favouritedOverride === 1 : favourited
+ property bool isReblogged: _rebloggedOverride >= 0 ? _rebloggedOverride === 1 : reblogged
+ readonly property bool housekeeping: Lipstick.compositor.eventsLayer.housekeeping
+ readonly property bool lockScreenActive: Lipstick.compositor.lockScreenLayer.deviceIsLocked
+ property bool _pendingOpenActionMenu: false
+ property bool _contextMenuOpen: false
+ property var _actionMenu
+ property real _contextMenuHeight: (_contextMenuOpen && _actionMenu) ? _actionMenu.height : 0
+
+ property string _booster: model && model.boostedBy ? model.boostedBy.toString() : ""
+ property string _displayName: model && model.name ? model.name.toString() : ""
+ property string _accountName: model && model.accountName ? model.accountName.toString() : ""
+ property string _bodyText: model && model.body ? model.body.toString() : ""
+ //: Action label shown in Fediverse interaction menu.
+ //% "Favourite"
+ readonly property string _favouriteActionText: qsTrId("lipstick-jolla-home-la-fediverse_favourite")
+ //: Action label shown in Fediverse interaction menu when the post is already favourited.
+ //% "Unfavourite"
+ readonly property string _unfavouriteActionText: qsTrId("lipstick-jolla-home-la-fediverse_unfavourite")
+ //: Action label shown in Fediverse interaction menu.
+ //% "Boost"
+ readonly property string _boostActionText: qsTrId("lipstick-jolla-home-la-fediverse_boost")
+ //: Action label shown in Fediverse interaction menu when the post is already boosted.
+ //% "Undo boost"
+ readonly property string _unboostActionText: qsTrId("lipstick-jolla-home-la-fediverse_unboost")
+ //: Action label shown in Fediverse interaction menu.
+ //% "Share"
+ readonly property string _shareActionText: qsTrId("lipstick-jolla-home-la-fediverse_share")
+ //: Link title used when sharing a Fediverse post.
+ //% "Post from Fediverse"
+ readonly property string _shareLinkTitle: qsTrId("lipstick-jolla-home-la-fediverse_share_link_title")
+ property var _shareAction: ShareAction {
+ title: item._shareActionText
+ }
+
+ timestamp: model.timestamp
+ onRefreshTimeCountChanged: formattedTime = Format.formatDate(model.timestamp, Format.TimeElapsed)
+ onLockScreenActiveChanged: {
+ if (lockScreenActive && _actionMenu) {
+ _actionMenu.close()
+ }
+ }
+ onPressAndHold: function(mouse) {
+ if (mouse) {
+ mouse.accepted = true
+ }
+ _pendingOpenActionMenu = !lockScreenActive
+ && postActions
+ && actionPostId().length > 0
+ && actionAccountId() >= 0
+ openActionMenuTimer.restart()
+ }
+ onHousekeepingChanged: {
+ if (housekeeping && _pendingOpenActionMenu) {
+ Lipstick.compositor.eventsLayer.setHousekeeping(false)
+ }
+ }
+ Component.onDestruction: {
+ if (_actionMenu) {
+ _actionMenu.destroy()
+ _actionMenu = null
+ }
+ }
+
+ avatar.y: item._booster.length > 0
+ ? topMargin + boosterIcon.height + Theme.paddingSmall
+ : topMargin
+ contentHeight: Math.max(content.y + content.height, avatar.y + avatar.height) + bottomMargin + _contextMenuHeight
+ topMargin: item._booster.length > 0 ? Theme.paddingMedium : Theme.paddingLarge
+ userRemovable: false
+
+ SocialReshareIcon {
+ id: boosterIcon
+
+ anchors {
+ right: avatar.right
+ top: parent.top
+ topMargin: item.topMargin
+ }
+ visible: item._booster.length > 0
+ highlighted: item.highlighted
+ iconSource: "image://theme/icon-s-repost"
+ }
+
+ SocialReshareText {
+ anchors {
+ left: content.left
+ right: content.right
+ verticalCenter: boosterIcon.verticalCenter
+ }
+ highlighted: item.highlighted
+ text: item._booster.length > 0
+ ? //: Shown above a post that is boosted by another user. %1 = name of user who boosted
+ //% "%1 boosted"
+ qsTrId("lipstick-jolla-home-la-boosted_by").arg(item._booster)
+ : ""
+ }
+
+ Column {
+ id: content
+
+ anchors {
+ left: avatar.right
+ leftMargin: Theme.paddingMedium
+ top: avatar.top
+ }
+ width: parent.width - x
+
+ Label {
+ width: parent.width
+ truncationMode: TruncationMode.Fade
+ text: item._displayName
+ color: item.highlighted ? Theme.highlightColor : Theme.primaryColor
+ textFormat: Text.PlainText
+ }
+
+ Label {
+ width: parent.width
+ truncationMode: TruncationMode.Fade
+ text: item._accountName.length > 0 && item._accountName.charAt(0) !== "@"
+ ? "@" + item._accountName
+ : item._accountName
+ font.pixelSize: Theme.fontSizeSmall
+ color: item.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
+ textFormat: Text.PlainText
+ }
+
+ LinkedText {
+ width: parent.width
+ elide: Text.ElideRight
+ wrapMode: Text.Wrap
+ font.pixelSize: Theme.fontSizeSmall
+ shortenUrl: true
+ color: item.highlighted ? Theme.highlightColor : Theme.primaryColor
+ linkColor: Theme.highlightColor
+ plainText: item._bodyText
+ }
+
+ SocialPostMetadataRow {
+ id: metadataRow
+
+ width: parent.width
+ highlighted: item.highlighted
+ commentCount: item.commentCount
+ likeCount: item._likeCountOverride >= 0 ? item._likeCountOverride : item.likeCount
+ repostCount: item._boostCountOverride >= 0 ? item._boostCountOverride : item.boostCount
+ liked: item.isFavourited
+ reposted: item.isReblogged
+ timeText: item.formattedTime
+ addBottomPadding: previewRow.visible
+ }
+
+ SocialMediaPreviewRow {
+ id: previewRow
+
+ width: parent.width + Theme.horizontalPageMargin // extend to right edge of notification area
+ imageList: item.imageList
+ downloader: item.downloader
+ accountId: item.accountId
+ connectedToNetwork: item.connectedToNetwork
+ highlighted: item.highlighted
+ eventsColumnMaxWidth: item.eventsColumnMaxWidth - item.avatar.width
+ }
+ }
+
+ function actionPostId() {
+ if (item.postId.length > 0) {
+ return item.postId
+ }
+ return model && model.fediverseId ? model.fediverseId.toString() : ""
+ }
+
+ function actionAccountId() {
+ var parsed = Number(item.accountId)
+ return isNaN(parsed) ? -1 : parsed
+ }
+
+ function shareStatusUrl() {
+ return model && model.url ? model.url.toString() : ""
+ }
+
+ function topLevelParent() {
+ var p = item
+ while (p && p.parent) {
+ p = p.parent
+ }
+ return p
+ }
+
+ function openActionMenu() {
+ if (_actionMenu) {
+ _actionMenu.destroy()
+ _actionMenu = null
+ }
+
+ var parentItem = topLevelParent()
+ _actionMenu = actionMenuComponent.createObject(parentItem)
+ if (_actionMenu) {
+ _actionMenu.open(item)
+ }
+ }
+
+ Connections {
+ target: item.postActions ? item.postActions : null
+
+ onActionSucceeded: {
+ if (accountId !== item.actionAccountId() || statusId !== item.actionPostId()) {
+ return
+ }
+
+ if (favouritesCount >= 0) {
+ item._likeCountOverride = favouritesCount
+ }
+ if (reblogsCount >= 0) {
+ item._boostCountOverride = reblogsCount
+ }
+ item._favouritedOverride = favourited ? 1 : 0
+ item._rebloggedOverride = reblogged ? 1 : 0
+ item._contextMenuOpen = false
+
+ if (item._accountDelegate) {
+ item._accountDelegate.sync()
+ }
+ }
+
+ onActionFailed: {
+ if (accountId !== item.actionAccountId() || statusId !== item.actionPostId()) {
+ return
+ }
+ console.warn("Fediverse action failed:", action, errorMessage)
+ item._contextMenuOpen = false
+ }
+ }
+
+ Component {
+ id: actionMenuComponent
+
+ SocialInteractionContextMenu {
+ id: actionMenu
+ z: 10000
+ mapSourceItem: _contentColumn
+ actionEnabled: item.postActions
+ && item.actionPostId().length > 0
+ && item.actionAccountId() >= 0
+ && !item.lockScreenActive
+ && !item.housekeeping
+ interactionItems: [
+ {
+ name: "like",
+ // U+2605 BLACK STAR
+ symbol: "\u2605",
+ active: item.isFavourited,
+ inactiveText: item._favouriteActionText,
+ activeText: item._unfavouriteActionText
+ },
+ {
+ name: "reblog",
+ // U+21BB CLOCKWISE OPEN CIRCLE ARROW
+ symbol: "\u21BB",
+ active: item.isReblogged,
+ inactiveText: item._boostActionText,
+ activeText: item._unboostActionText
+ },
+ {
+ name: "share",
+ // U+260D OPPOSITION (ironic doncha think)
+ symbol: "\u260D",
+ active: false,
+ inactiveText: item._shareActionText,
+ activeText: item._shareActionText
+ }
+ ]
+
+ onInteractionMenuOpened: item._contextMenuOpen = true
+ onInteractionMenuClosed: {
+ item._contextMenuOpen = false
+ destroy()
+ item._actionMenu = null
+ }
+
+ onInteractionTriggered: function(actionName) {
+ if (!actionEnabled) {
+ return
+ }
+ var postId = item.actionPostId()
+ var accountId = item.actionAccountId()
+ if (actionName === "like") {
+ if (item.isFavourited) {
+ item.postActions.unfavourite(accountId, postId)
+ } else {
+ item.postActions.favourite(accountId, postId)
+ }
+ } else if (actionName === "reblog") {
+ if (item.isReblogged) {
+ item.postActions.unboost(accountId, postId)
+ } else {
+ item.postActions.boost(accountId, postId)
+ }
+ } else if (actionName === "share") {
+ var shareUrl = item.shareStatusUrl()
+ if (shareUrl.length === 0) {
+ return
+ }
+ item._shareAction.resources = [{
+ "data": shareUrl,
+ "linkTitle": item._shareLinkTitle,
+ "type": "text/x-url"
+ }]
+ item._shareAction.trigger()
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: openActionMenuTimer
+
+ interval: 0
+ repeat: false
+ onTriggered: {
+ if (item.lockScreenActive) {
+ item._pendingOpenActionMenu = false
+ return
+ }
+ Lipstick.compositor.eventsLayer.setHousekeeping(false)
+ if (item._pendingOpenActionMenu) {
+ item._contextMenuOpen = false
+ item.openActionMenu()
+ }
+ item._pendingOpenActionMenu = false
+ }
+ }
+}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/eventsview-plugin-mastodon.pro b/eventsview-plugins/eventsview-plugin-fediverse/eventsview-plugin-fediverse.pro
index 04be215..e546e9d 100644
--- a/eventsview-plugins/eventsview-plugin-mastodon/eventsview-plugin-mastodon.pro
+++ b/eventsview-plugins/eventsview-plugin-fediverse/eventsview-plugin-fediverse.pro
@@ -3,20 +3,21 @@
# SPDX-License-Identifier: BSD-3-Clause
TEMPLATE = lib
-TARGET = jollaeventsviewmastodonplugin
+TARGET = jollaeventsviewfediverseplugin
TARGET = $$qtLibraryTarget($$TARGET)
-MODULENAME = com/jolla/eventsview/mastodon
+MODULENAME = com/jolla/eventsview/fediverse
TARGETPATH = $$[QT_INSTALL_QML]/$$MODULENAME
+QT -= gui
QT += qml network
CONFIG += plugin link_pkgconfig
PKGCONFIG += socialcache accounts-qt5 libsignon-qt5 sailfishaccounts
include($$PWD/../../common/common.pri)
-TS_FILE = $$OUT_PWD/lipstick-jolla-home-mastodon.ts
-EE_QM = $$OUT_PWD/lipstick-jolla-home-mastodon_eng_en.qm
+TS_FILE = $$OUT_PWD/lipstick-jolla-home-fediverse.ts
+EE_QM = $$OUT_PWD/lipstick-jolla-home-fediverse_eng_en.qm
ts.commands += lupdate $$PWD -ts $$TS_FILE
ts.CONFIG += no_check_exist no_link
@@ -44,15 +45,15 @@ PRE_TARGETDEPS += ts engineering_english
INSTALLS += ts_install engineering_english_install
HEADERS += \
- mastodonpostactions.h \
- mastodonpostsmodel.h
+ fediversepostactions.h \
+ fediversepostsmodel.h
SOURCES += \
- mastodonpostactions.cpp \
- mastodonpostsmodel.cpp \
+ fediversepostactions.cpp \
+ fediversepostsmodel.cpp \
plugin.cpp
-qml.files = mastodon-delegate.qml MastodonFeedItem.qml
+qml.files = fediverse-delegate.qml FediverseFeedItem.qml
qml.path = /usr/share/lipstick/eventfeed/
import.files = qmldir
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
+ }
+}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostactions.cpp b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostactions.cpp
index 371b7dd..2b370f2 100644
--- a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostactions.cpp
+++ b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostactions.cpp
@@ -16,9 +16,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "mastodonpostactions.h"
+#include "fediversepostactions.h"
-#include "mastodonauthutils.h"
+#include "fediverseauthutils.h"
#include <Accounts/Account>
#include <Accounts/AccountService>
@@ -39,36 +39,36 @@
#include <QtDebug>
namespace {
- const char *const MicroblogServiceName = "mastodon-microblog";
+ const char *const MicroblogServiceName = "fediverse-microblog";
}
-MastodonPostActions::MastodonPostActions(QObject *parent)
+FediversePostActions::FediversePostActions(QObject *parent)
: QObject(parent)
, m_accountManager(new Accounts::Manager(this))
{
}
-void MastodonPostActions::favourite(int accountId, const QString &statusId)
+void FediversePostActions::favourite(int accountId, const QString &statusId)
{
performAction(accountId, statusId, QStringLiteral("favourite"));
}
-void MastodonPostActions::unfavourite(int accountId, const QString &statusId)
+void FediversePostActions::unfavourite(int accountId, const QString &statusId)
{
performAction(accountId, statusId, QStringLiteral("unfavourite"));
}
-void MastodonPostActions::boost(int accountId, const QString &statusId)
+void FediversePostActions::boost(int accountId, const QString &statusId)
{
performAction(accountId, statusId, QStringLiteral("reblog"));
}
-void MastodonPostActions::unboost(int accountId, const QString &statusId)
+void FediversePostActions::unboost(int accountId, const QString &statusId)
{
performAction(accountId, statusId, QStringLiteral("unreblog"));
}
-void MastodonPostActions::performAction(int accountId, const QString &statusId, const QString &action)
+void FediversePostActions::performAction(int accountId, const QString &statusId, const QString &action)
{
const QString trimmedStatusId = statusId.trimmed();
if (accountId <= 0 || trimmedStatusId.isEmpty() || action.isEmpty()) {
@@ -116,7 +116,7 @@ void MastodonPostActions::performAction(int accountId, const QString &statusId,
}
QVariantMap signonSessionData = accountService.authData().parameters();
- MastodonAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
+ FediverseAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
connect(session, SIGNAL(response(SignOn::SessionData)),
this, SLOT(signOnResponse(SignOn::SessionData)),
@@ -135,7 +135,7 @@ void MastodonPostActions::performAction(int accountId, const QString &statusId,
session->process(SignOn::SessionData(signonSessionData), mechanism);
}
-void MastodonPostActions::signOnResponse(const SignOn::SessionData &responseData)
+void FediversePostActions::signOnResponse(const SignOn::SessionData &responseData)
{
QObject *sessionObject = sender();
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession *>(sessionObject);
@@ -148,12 +148,12 @@ void MastodonPostActions::signOnResponse(const SignOn::SessionData &responseData
const QString action = session->property("action").toString();
const QString key = actionKey(accountId, statusId, action);
- const QVariantMap data = MastodonAuthUtils::responseDataToMap(responseData);
- const QString accessToken = MastodonAuthUtils::accessToken(data);
+ const QVariantMap data = FediverseAuthUtils::responseDataToMap(responseData);
+ const QString accessToken = FediverseAuthUtils::accessToken(data);
Accounts::Account *account = session->property("account").value<Accounts::Account *>();
const QString apiHost = account
- ? MastodonAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString())
+ ? FediverseAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString())
: QString();
if (accessToken.isEmpty() || apiHost.isEmpty()) {
@@ -167,7 +167,7 @@ void MastodonPostActions::signOnResponse(const SignOn::SessionData &responseData
executeActionRequest(accountId, statusId, action, apiHost, accessToken);
}
-void MastodonPostActions::signOnError(const SignOn::Error &error)
+void FediversePostActions::signOnError(const SignOn::Error &error)
{
QObject *sessionObject = sender();
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession *>(sessionObject);
@@ -185,7 +185,7 @@ void MastodonPostActions::signOnError(const SignOn::Error &error)
releaseSignOnObjects(sessionObject);
}
-void MastodonPostActions::executeActionRequest(int accountId,
+void FediversePostActions::executeActionRequest(int accountId,
const QString &statusId,
const QString &action,
const QString &apiHost,
@@ -212,7 +212,7 @@ void MastodonPostActions::executeActionRequest(int accountId,
connect(reply, SIGNAL(finished()), this, SLOT(actionFinishedHandler()));
}
-void MastodonPostActions::actionFinishedHandler()
+void FediversePostActions::actionFinishedHandler()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
if (!reply) {
@@ -291,7 +291,7 @@ void MastodonPostActions::actionFinishedHandler()
favourited, reblogged);
}
-void MastodonPostActions::releaseSignOnObjects(QObject *sessionObject)
+void FediversePostActions::releaseSignOnObjects(QObject *sessionObject)
{
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession *>(sessionObject);
if (!session) {
@@ -311,7 +311,7 @@ void MastodonPostActions::releaseSignOnObjects(QObject *sessionObject)
}
}
-QString MastodonPostActions::actionKey(int accountId, const QString &statusId, const QString &action) const
+QString FediversePostActions::actionKey(int accountId, const QString &statusId, const QString &action) const
{
return QString::number(accountId) + QLatin1Char(':') + statusId + QLatin1Char(':') + action;
}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostactions.h b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostactions.h
index cfe0c2a..536d339 100644
--- a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostactions.h
+++ b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostactions.h
@@ -16,8 +16,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef MASTODONPOSTACTIONS_H
-#define MASTODONPOSTACTIONS_H
+#ifndef FEDIVERSEPOSTACTIONS_H
+#define FEDIVERSEPOSTACTIONS_H
#include <QtCore/QObject>
#include <QtCore/QSet>
@@ -34,12 +34,12 @@ class Error;
class SessionData;
}
-class MastodonPostActions : public QObject
+class FediversePostActions : public QObject
{
Q_OBJECT
public:
- explicit MastodonPostActions(QObject *parent = 0);
+ explicit FediversePostActions(QObject *parent = 0);
Q_INVOKABLE void favourite(int accountId, const QString &statusId);
Q_INVOKABLE void unfavourite(int accountId, const QString &statusId);
@@ -79,4 +79,4 @@ private:
QSet<QString> m_pendingActions;
};
-#endif // MASTODONPOSTACTIONS_H
+#endif // FEDIVERSEPOSTACTIONS_H
diff --git a/eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.cpp b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.cpp
new file mode 100644
index 0000000..48b3446
--- /dev/null
+++ b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013-2026 Jolla Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "fediversepostsmodel.h"
+
+#include <QtCore/QVariantList>
+
+namespace {
+
+QVariantList imageListForPost(const SocialPost::ConstPtr &post)
+{
+ QVariantList images;
+ if (!post) {
+ return images;
+ }
+
+ const QList<SocialPostImage::ConstPtr> postImages = post->images();
+ for (const SocialPostImage::ConstPtr &image : postImages) {
+ if (!image) {
+ continue;
+ }
+
+ QVariantMap imageMap;
+ imageMap.insert(QStringLiteral("url"), image->url());
+ imageMap.insert(QStringLiteral("type"), image->type() == SocialPostImage::Video
+ ? QStringLiteral("video")
+ : QStringLiteral("image"));
+ images.append(imageMap);
+ }
+
+ return images;
+}
+
+QVariantList accountListForPost(const SocialPost::ConstPtr &post)
+{
+ QVariantList accounts;
+ if (!post) {
+ return accounts;
+ }
+
+ const QList<int> postAccounts = post->accounts();
+ for (int accountId : postAccounts) {
+ accounts.append(accountId);
+ }
+ return accounts;
+}
+
+void appendCommonPostFields(QMap<int, QVariant> *eventMap,
+ const SocialPost::ConstPtr &post,
+ int idRole,
+ int nameRole,
+ int bodyRole,
+ int timestampRole,
+ int iconRole,
+ int imagesRole,
+ int accountsRole)
+{
+ if (!eventMap || !post) {
+ return;
+ }
+
+ eventMap->insert(idRole, post->identifier());
+ eventMap->insert(nameRole, post->name());
+ eventMap->insert(bodyRole, post->body());
+ eventMap->insert(timestampRole, post->timestamp());
+ eventMap->insert(iconRole, post->icon());
+ eventMap->insert(imagesRole, imageListForPost(post));
+ eventMap->insert(accountsRole, accountListForPost(post));
+}
+
+}
+
+FediversePostsModel::FediversePostsModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ connect(&m_database, &AbstractSocialPostCacheDatabase::postsChanged,
+ this, &FediversePostsModel::postsChanged);
+ connect(&m_database, SIGNAL(accountIdFilterChanged()),
+ this, SIGNAL(accountIdFilterChanged()));
+}
+
+int FediversePostsModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return m_data.count();
+}
+
+QVariant FediversePostsModel::data(const QModelIndex &index, int role) const
+{
+ const int row = index.row();
+ if (!index.isValid() || row < 0 || row >= m_data.count()) {
+ return QVariant();
+ }
+
+ return m_data.at(row).value(role);
+}
+
+QHash<int, QByteArray> FediversePostsModel::roleNames() const
+{
+ QHash<int, QByteArray> roleNames;
+ roleNames.insert(FediverseId, "fediverseId");
+ roleNames.insert(Name, "name");
+ roleNames.insert(AccountName, "accountName");
+ roleNames.insert(Acct, "acct");
+ roleNames.insert(Body, "body");
+ roleNames.insert(Timestamp, "timestamp");
+ roleNames.insert(Icon, "icon");
+ roleNames.insert(Images, "images");
+ roleNames.insert(Url, "url");
+ roleNames.insert(Link, "link");
+ roleNames.insert(BoostedBy, "boostedBy");
+ roleNames.insert(RebloggedBy, "rebloggedBy");
+ roleNames.insert(RepliesCount, "repliesCount");
+ roleNames.insert(FavouritesCount, "favouritesCount");
+ roleNames.insert(ReblogsCount, "reblogsCount");
+ roleNames.insert(Favourited, "favourited");
+ roleNames.insert(Reblogged, "reblogged");
+ roleNames.insert(InstanceUrl, "instanceUrl");
+ roleNames.insert(InstanceIconPath, "instanceIconPath");
+ roleNames.insert(Accounts, "accounts");
+ return roleNames;
+}
+
+QVariantList FediversePostsModel::accountIdFilter() const
+{
+ return m_database.accountIdFilter();
+}
+
+void FediversePostsModel::setAccountIdFilter(const QVariantList &accountIds)
+{
+ m_database.setAccountIdFilter(accountIds);
+}
+
+void FediversePostsModel::refresh()
+{
+ m_database.refresh();
+}
+
+void FediversePostsModel::postsChanged()
+{
+ QList<RowData> data;
+ QList<SocialPost::ConstPtr> postsData = m_database.posts();
+ Q_FOREACH (const SocialPost::ConstPtr &post, postsData) {
+ RowData eventMap;
+ const QString accountName = m_database.accountName(post);
+ const QString postUrl = m_database.url(post);
+ const QString boostedBy = m_database.boostedBy(post);
+ const int repliesCount = m_database.repliesCount(post);
+ const int favouritesCount = m_database.favouritesCount(post);
+ const int reblogsCount = m_database.reblogsCount(post);
+ const bool favourited = m_database.favourited(post);
+ const bool reblogged = m_database.reblogged(post);
+
+ appendCommonPostFields(&eventMap, post,
+ FediversePostsModel::FediverseId,
+ FediversePostsModel::Name,
+ FediversePostsModel::Body,
+ FediversePostsModel::Timestamp,
+ FediversePostsModel::Icon,
+ FediversePostsModel::Images,
+ FediversePostsModel::Accounts);
+ eventMap.insert(FediversePostsModel::AccountName, accountName);
+ eventMap.insert(FediversePostsModel::Acct, accountName);
+ eventMap.insert(FediversePostsModel::Url, postUrl);
+ eventMap.insert(FediversePostsModel::Link, postUrl);
+ eventMap.insert(FediversePostsModel::BoostedBy, boostedBy);
+ eventMap.insert(FediversePostsModel::RebloggedBy, boostedBy);
+ eventMap.insert(FediversePostsModel::RepliesCount, repliesCount);
+ eventMap.insert(FediversePostsModel::FavouritesCount, favouritesCount);
+ eventMap.insert(FediversePostsModel::ReblogsCount, reblogsCount);
+ eventMap.insert(FediversePostsModel::Favourited, favourited);
+ eventMap.insert(FediversePostsModel::Reblogged, reblogged);
+ eventMap.insert(FediversePostsModel::InstanceUrl, m_database.instanceUrl(post));
+ eventMap.insert(FediversePostsModel::InstanceIconPath, m_database.instanceIconPath(post));
+ data.append(eventMap);
+ }
+
+ const int oldCount = m_data.count();
+ beginResetModel();
+ m_data = data;
+ endResetModel();
+ if (oldCount != m_data.count()) {
+ emit countChanged();
+ }
+}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.h b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.h
index e30437d..96acae3 100644
--- a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.h
+++ b/eventsview-plugins/eventsview-plugin-fediverse/fediversepostsmodel.h
@@ -16,22 +16,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef MASTODONPOSTSMODEL_H
-#define MASTODONPOSTSMODEL_H
+#ifndef FEDIVERSEPOSTSMODEL_H
+#define FEDIVERSEPOSTSMODEL_H
-#include "mastodonpostsdatabase.h"
+#include "fediversepostsdatabase.h"
#include <QtCore/QAbstractListModel>
#include <QtCore/QMap>
-class MastodonPostsModel: public QAbstractListModel
+class FediversePostsModel: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QVariantList accountIdFilter READ accountIdFilter WRITE setAccountIdFilter NOTIFY accountIdFilterChanged)
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
- enum MastodonPostsRole {
- MastodonId = 0,
+ enum FediversePostsRole {
+ FediverseId = 0,
Name,
AccountName,
Acct,
@@ -49,10 +49,11 @@ public:
Favourited,
Reblogged,
InstanceUrl,
+ InstanceIconPath,
Accounts
};
- explicit MastodonPostsModel(QObject *parent = 0);
+ explicit FediversePostsModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
@@ -73,7 +74,7 @@ private slots:
private:
typedef QMap<int, QVariant> RowData;
QList<RowData> m_data;
- MastodonPostsDatabase m_database;
+ FediversePostsDatabase m_database;
};
-#endif // MASTODONPOSTSMODEL_H
+#endif // FEDIVERSEPOSTSMODEL_H
diff --git a/eventsview-plugins/eventsview-plugin-fediverse/plugin.cpp b/eventsview-plugins/eventsview-plugin-fediverse/plugin.cpp
new file mode 100644
index 0000000..509b602
--- /dev/null
+++ b/eventsview-plugins/eventsview-plugin-fediverse/plugin.cpp
@@ -0,0 +1,27 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <QQmlExtensionPlugin>
+#include <QtQml>
+
+#include "fediversepostactions.h"
+#include "fediversepostsmodel.h"
+
+class JollaEventsviewFediversePlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "com.jolla.eventsview.fediverse")
+
+public:
+ void registerTypes(const char *uri) override
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("com.jolla.eventsview.fediverse"));
+ qmlRegisterType<FediversePostsModel>(uri, 1, 0, "FediversePostsModel");
+ qmlRegisterType<FediversePostActions>(uri, 1, 0, "FediversePostActions");
+ }
+};
+
+#include "plugin.moc"
diff --git a/eventsview-plugins/eventsview-plugin-fediverse/qmldir b/eventsview-plugins/eventsview-plugin-fediverse/qmldir
new file mode 100644
index 0000000..8b25e83
--- /dev/null
+++ b/eventsview-plugins/eventsview-plugin-fediverse/qmldir
@@ -0,0 +1,4 @@
+# Copyright (C) 2013-2026 Jolla Ltd.
+
+module com.jolla.eventsview.fediverse
+plugin jollaeventsviewfediverseplugin
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/MastodonFeedItem.qml b/eventsview-plugins/eventsview-plugin-mastodon/MastodonFeedItem.qml
deleted file mode 100644
index 63b9556..0000000
--- a/eventsview-plugins/eventsview-plugin-mastodon/MastodonFeedItem.qml
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-import QtQuick 2.0
-import Sailfish.Silica 1.0
-import Sailfish.Share 1.0
-import Sailfish.TextLinking 1.0
-import org.nemomobile.lipstick 0.1
-import "shared"
-
-SocialMediaFeedItem {
- id: item
-
- property variant imageList
- property string resolvedStatusUrl: item.stringValue("url", "link", "uri")
- property string postId
- property QtObject postActions
- property int likeCount: item.intValue("favouritesCount", "likeCount", "favoriteCount")
- property int commentCount: item.intValue("repliesCount", "commentCount")
- property int boostCount: item.intValue("reblogsCount", "boostCount", "repostsCount")
- property bool favourited: !!model.favourited
- property bool reblogged: !!model.reblogged
- property int _likeCountOverride: -1
- property int _boostCountOverride: -1
- property int _favouritedOverride: -1
- property int _rebloggedOverride: -1
- property bool isFavourited: _favouritedOverride >= 0 ? _favouritedOverride === 1 : favourited
- property bool isReblogged: _rebloggedOverride >= 0 ? _rebloggedOverride === 1 : reblogged
- readonly property bool housekeeping: Lipstick.compositor.eventsLayer.housekeeping
- readonly property bool lockScreenActive: Lipstick.compositor.lockScreenLayer.deviceIsLocked
- property bool _pendingOpenActionMenu: false
- property bool _contextMenuOpen: false
- property var _actionMenu
- property real _contextMenuHeight: (_contextMenuOpen && _actionMenu) ? _actionMenu.height : 0
-
- property string _booster: model && model.boostedBy ? model.boostedBy.toString() : ""
- property string _displayName: model && model.name ? model.name.toString() : ""
- property string _accountName: model && model.accountName ? model.accountName.toString() : ""
- property string _bodyText: model && model.body ? model.body.toString() : ""
- //: Action label shown in Mastodon interaction menu.
- //% "Share"
- readonly property string _shareActionText: qsTrId("lipstick-jolla-home-la-mastodon_share")
- //: Link title used when sharing a Mastodon post.
- //% "Post from Mastodon"
- readonly property string _shareLinkTitle: qsTrId("lipstick-jolla-home-la-mastodon_share_link_title")
- property var _shareAction: ShareAction {
- title: item._shareActionText
- }
-
- timestamp: model.timestamp
- onRefreshTimeCountChanged: formattedTime = Format.formatDate(model.timestamp, Format.TimeElapsed)
- onLockScreenActiveChanged: {
- if (lockScreenActive && _actionMenu) {
- _actionMenu.close()
- }
- }
- onPressAndHold: function(mouse) {
- if (mouse) {
- mouse.accepted = true
- }
- _pendingOpenActionMenu = !lockScreenActive
- && postActions
- && actionPostId().length > 0
- && actionAccountId() >= 0
- openActionMenuTimer.restart()
- }
- onHousekeepingChanged: {
- if (housekeeping && _pendingOpenActionMenu) {
- Lipstick.compositor.eventsLayer.setHousekeeping(false)
- }
- }
- Component.onDestruction: {
- if (_actionMenu) {
- _actionMenu.destroy()
- _actionMenu = null
- }
- }
-
- avatar.y: item._booster.length > 0
- ? topMargin + boosterIcon.height + Theme.paddingSmall
- : topMargin
- contentHeight: Math.max(content.y + content.height, avatar.y + avatar.height) + bottomMargin + _contextMenuHeight
- topMargin: item._booster.length > 0 ? Theme.paddingMedium : Theme.paddingLarge
- userRemovable: false
-
- Image {
- id: boosterIcon
-
- anchors {
- right: avatar.right
- top: parent.top
- topMargin: item.topMargin
- }
- visible: item._booster.length > 0
- source: "image://theme/icon-s-repost" + (item.highlighted ? "?" + Theme.highlightColor : "")
- }
-
- Text {
- anchors {
- left: content.left
- right: content.right
- verticalCenter: boosterIcon.verticalCenter
- }
- elide: Text.ElideRight
- font.pixelSize: Theme.fontSizeExtraSmall
- color: item.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
- textFormat: Text.PlainText
- visible: text.length > 0
-
- text: item._booster.length > 0
- ? //: Shown above a post that is boosted by another user. %1 = name of user who boosted
- //% "%1 boosted"
- qsTrId("lipstick-jolla-home-la-boosted_by").arg(item._booster)
- : ""
- }
-
- Column {
- id: content
-
- anchors {
- left: avatar.right
- leftMargin: Theme.paddingMedium
- top: avatar.top
- }
- width: parent.width - x
-
- Label {
- width: parent.width
- truncationMode: TruncationMode.Fade
- text: item._displayName
- color: item.highlighted ? Theme.highlightColor : Theme.primaryColor
- textFormat: Text.PlainText
- }
-
- Label {
- width: parent.width
- truncationMode: TruncationMode.Fade
- text: item._accountName.length > 0 && item._accountName.charAt(0) !== "@"
- ? "@" + item._accountName
- : item._accountName
- font.pixelSize: Theme.fontSizeSmall
- color: item.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
- textFormat: Text.PlainText
- }
-
- LinkedText {
- width: parent.width
- elide: Text.ElideRight
- wrapMode: Text.Wrap
- font.pixelSize: Theme.fontSizeSmall
- shortenUrl: true
- color: item.highlighted ? Theme.highlightColor : Theme.primaryColor
- linkColor: Theme.highlightColor
- plainText: item._bodyText
- }
-
- Row {
- id: metadataRow
-
- width: parent.width
- height: previewRow.visible ? implicitHeight + Theme.paddingMedium : implicitHeight // add padding below
- spacing: Theme.paddingSmall
-
- readonly property color passiveColor: item.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
- readonly property color activeColor: Theme.highlightColor
-
- Label {
- font.pixelSize: Theme.fontSizeExtraSmall
- text: "↩ " + item.commentCount
- color: metadataRow.passiveColor
- }
-
- Label {
- font.pixelSize: Theme.fontSizeExtraSmall
- text: "|"
- color: metadataRow.passiveColor
- }
-
- Label {
- font.pixelSize: Theme.fontSizeExtraSmall
- text: "★ " + (item._likeCountOverride >= 0 ? item._likeCountOverride : item.likeCount)
- color: item.isFavourited ? metadataRow.activeColor : metadataRow.passiveColor
- }
-
- Label {
- font.pixelSize: Theme.fontSizeExtraSmall
- text: "|"
- color: metadataRow.passiveColor
- }
-
- Label {
- font.pixelSize: Theme.fontSizeExtraSmall
- text: "↻ " + (item._boostCountOverride >= 0 ? item._boostCountOverride : item.boostCount)
- color: item.isReblogged ? metadataRow.activeColor : metadataRow.passiveColor
- }
-
- Label {
- visible: item.formattedTime.length > 0
- font.pixelSize: Theme.fontSizeExtraSmall
- text: "|"
- color: metadataRow.passiveColor
- }
-
- Label {
- visible: item.formattedTime.length > 0
- width: Math.max(0, metadataRow.width - x)
- truncationMode: TruncationMode.Fade
- font.pixelSize: Theme.fontSizeExtraSmall
- text: item.formattedTime
- color: metadataRow.passiveColor
- }
- }
-
- SocialMediaPreviewRow {
- id: previewRow
-
- width: parent.width + Theme.horizontalPageMargin // extend to right edge of notification area
- imageList: item.imageList
- downloader: item.downloader
- accountId: item.accountId
- connectedToNetwork: item.connectedToNetwork
- highlighted: item.highlighted
- eventsColumnMaxWidth: item.eventsColumnMaxWidth - item.avatar.width
- }
- }
-
- function stringValue() {
- for (var i = 0; i < arguments.length; ++i) {
- var value = model[arguments[i]]
- if (typeof value === "undefined" || value === null) {
- continue
- }
- value = String(value)
- if (value.length > 0) {
- return value
- }
- }
- return ""
- }
-
- function intValue() {
- for (var i = 0; i < arguments.length; ++i) {
- var value = model[arguments[i]]
- if (typeof value === "undefined" || value === null) {
- continue
- }
- var number = Number(value)
- if (!isNaN(number)) {
- return Math.max(0, Math.floor(number))
- }
- }
- return 0
- }
-
- function actionPostId() {
- if (item.postId.length > 0) {
- return item.postId
- }
- return item.stringValue("mastodonId", "statusId", "id", "twitterId")
- }
-
- function actionAccountId() {
- var parsed = Number(item.accountId)
- return isNaN(parsed) ? -1 : parsed
- }
-
- function shareStatusUrl() {
- return item.stringValue("url", "link", "uri")
- }
-
- function topLevelParent() {
- var p = item
- while (p && p.parent) {
- p = p.parent
- }
- return p
- }
-
- function openActionMenu() {
- if (_actionMenu) {
- _actionMenu.destroy()
- _actionMenu = null
- }
-
- var parentItem = topLevelParent()
- _actionMenu = actionMenuComponent.createObject(parentItem)
- if (_actionMenu) {
- _actionMenu.open(item)
- }
- }
-
- Connections {
- target: item.postActions ? item.postActions : null
-
- onActionSucceeded: {
- if (accountId !== item.actionAccountId() || statusId !== item.actionPostId()) {
- return
- }
-
- if (favouritesCount >= 0) {
- item._likeCountOverride = favouritesCount
- }
- if (reblogsCount >= 0) {
- item._boostCountOverride = reblogsCount
- }
- item._favouritedOverride = favourited ? 1 : 0
- item._rebloggedOverride = reblogged ? 1 : 0
- item._contextMenuOpen = false
-
- if (item._accountDelegate) {
- item._accountDelegate.sync()
- }
- }
-
- onActionFailed: {
- if (accountId !== item.actionAccountId() || statusId !== item.actionPostId()) {
- return
- }
- console.warn("Mastodon action failed:", action, errorMessage)
- item._contextMenuOpen = false
- }
- }
-
- Component {
- id: actionMenuComponent
-
- ContextMenu {
- id: actionMenu
- property bool menuOpen: height > 0
- property bool wasOpened: false
- z: 10000
-
- onPositionChanged: {
- horizontalActions.xPos = _contentColumn.mapFromItem(actionMenu, mouse.x, mouse.y).x
- }
-
- onMenuOpenChanged: {
- if (menuOpen) {
- wasOpened = true
- item._contextMenuOpen = true
- } else if (wasOpened) {
- item._contextMenuOpen = false
- destroy()
- item._actionMenu = null
- }
- }
-
- Item {
- id: horizontalActions
-
- // Makes Silica treat this custom row as a context-menu item.
- property int __silica_menuitem
- property bool down
- property bool highlighted
- signal clicked
-
- property real xPos: 0
- property int hoveredIndex: -1
- readonly property bool actionEnabled: item.postActions
- && item.actionPostId().length > 0
- && item.actionAccountId() >= 0
- && !item.lockScreenActive
- && !item.housekeeping
-
- width: parent.width
- height: Theme.itemSizeMedium
-
- onXPosChanged: hoveredIndex = Math.max(0, Math.min(2, Math.floor((xPos * 3) / Math.max(1, width))))
- onDownChanged: if (!down) hoveredIndex = -1
-
- onClicked: {
- xPos = _contentColumn.mapFromItem(actionMenu, actionMenu.mouseX, actionMenu.mouseY).x
- var index = hoveredIndex >= 0 ? hoveredIndex : Math.max(0, Math.min(2, Math.floor((xPos * 3) / Math.max(1, width))))
- if (!actionEnabled) {
- return
- }
- var postId = item.actionPostId()
- var accountId = item.actionAccountId()
- if (index === 0) {
- if (item.isFavourited) {
- item.postActions.unfavourite(accountId, postId)
- } else {
- item.postActions.favourite(accountId, postId)
- }
- } else if (index === 1) {
- if (item.isReblogged) {
- item.postActions.unboost(accountId, postId)
- } else {
- item.postActions.boost(accountId, postId)
- }
- } else {
- var shareUrl = item.shareStatusUrl()
- if (shareUrl.length === 0) {
- return
- }
- item._shareAction.resources = [{
- "data": shareUrl,
- "linkTitle": item._shareLinkTitle,
- "type": "text/x-url"
- }]
- item._shareAction.trigger()
- }
- }
-
- Rectangle {
- anchors.verticalCenter: parent.verticalCenter
- x: (horizontalActions.hoveredIndex >= 0 ? horizontalActions.hoveredIndex : 0) * (parent.width / 3)
- width: parent.width / 3
- height: parent.height
- visible: horizontalActions.down && horizontalActions.hoveredIndex >= 0
- color: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity)
- }
-
- Row {
- anchors.fill: parent
-
- Label {
- width: parent.width / 3
- height: parent.height
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- font.pixelSize: Theme.fontSizeExtraLarge
- text: "★"
- color: horizontalActions.actionEnabled
- ? (item.isFavourited
- ? Theme.highlightColor
- : ((horizontalActions.down && horizontalActions.hoveredIndex === 0)
- || (horizontalActions.highlighted && horizontalActions.hoveredIndex === 0)
- ? Theme.secondaryHighlightColor : Theme.primaryColor))
- : Theme.rgba(Theme.secondaryColor, 0.4)
- }
-
- Label {
- width: parent.width / 3
- height: parent.height
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- font.pixelSize: Theme.fontSizeExtraLarge
- text: "↻"
- color: horizontalActions.actionEnabled
- ? (item.isReblogged
- ? Theme.highlightColor
- : ((horizontalActions.down && horizontalActions.hoveredIndex === 1)
- || (horizontalActions.highlighted && horizontalActions.hoveredIndex === 1)
- ? Theme.secondaryHighlightColor : Theme.primaryColor))
- : Theme.rgba(Theme.secondaryColor, 0.4)
- }
-
- Label {
- width: parent.width / 3
- height: parent.height
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- font.pixelSize: Theme.fontSizeExtraLarge
- text: "\u260D"
- color: horizontalActions.actionEnabled
- ? (((horizontalActions.down && horizontalActions.hoveredIndex === 2)
- || (horizontalActions.highlighted && horizontalActions.hoveredIndex === 2))
- ? Theme.secondaryHighlightColor : Theme.primaryColor)
- : Theme.rgba(Theme.secondaryColor, 0.4)
- }
- }
- }
- }
- }
-
- Timer {
- id: openActionMenuTimer
-
- interval: 0
- repeat: false
- onTriggered: {
- if (item.lockScreenActive) {
- item._pendingOpenActionMenu = false
- return
- }
- Lipstick.compositor.eventsLayer.setHousekeeping(false)
- if (item._pendingOpenActionMenu) {
- item._contextMenuOpen = false
- item.openActionMenu()
- }
- item._pendingOpenActionMenu = false
- }
- }
-}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/mastodon-delegate.qml b/eventsview-plugins/eventsview-plugin-mastodon/mastodon-delegate.qml
deleted file mode 100644
index fac0b89..0000000
--- a/eventsview-plugins/eventsview-plugin-mastodon/mastodon-delegate.qml
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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.mastodon 1.0
-import QtQml.Models 2.1
-import "shared"
-
-SocialMediaAccountDelegate {
- id: delegateItem
-
- //: Mastodon posts
- //% "Posts"
- headerText: qsTrId("lipstick-jolla-home-la-mastodon_posts")
- headerIcon: "image://theme/icon-l-mastodon"
- showRemainingCount: false
-
- services: ["Posts"]
- socialNetwork: 9
- dataType: SocialSync.Posts
- providerName: "mastodon"
-
- MastodonPostActions {
- id: mastodonPostActions
- }
-
- model: MastodonPostsModel {
- onCountChanged: {
- if (count > 0) {
- if (!updateTimer.running) {
- shortUpdateTimer.start()
- }
- } else {
- shortUpdateTimer.stop()
- }
- }
- }
-
- delegate: MastodonFeedItem {
- downloader: delegateItem.downloader
- imageList: delegateItem.variantRole(model, ["images", "mediaAttachments", "media"])
- avatarSource: delegateItem.convertUrl(delegateItem.stringRole(model, ["icon", "avatar", "avatarUrl"]))
- fallbackAvatarSource: delegateItem.stringRole(model, ["icon", "avatar", "avatarUrl"])
- resolvedStatusUrl: delegateItem.authorizeInteractionUrl(model)
- postId: delegateItem.stringRole(model, ["mastodonId", "statusId", "id", "twitterId"])
- postActions: mastodonPostActions
- accountId: delegateItem.firstAccountId(model)
-
- onTriggered: Qt.openUrlExternally(resolvedStatusUrl)
-
- Component.onCompleted: {
- refreshTimeCount = Qt.binding(function() { return delegateItem.refreshTimeCount })
- connectedToNetwork = Qt.binding(function() { return delegateItem.connectedToNetwork })
- eventsColumnMaxWidth = Qt.binding(function() { return delegateItem.eventsColumnMaxWidth })
- }
- }
- //% "Show more in Mastodon"
- expandedLabel: qsTrId("lipstick-jolla-home-la-show-more-in-mastodon")
-
- onHeaderClicked: Qt.openUrlExternally("https://mastodon.social/explore")
- onExpandedClicked: Qt.openUrlExternally("https://mastodon.social/explore")
-
- onViewVisibleChanged: {
- if (viewVisible) {
- delegateItem.resetHasSyncableAccounts()
- delegateItem.model.refresh()
- if (delegateItem.hasSyncableAccounts && !updateTimer.running) {
- shortUpdateTimer.start()
- }
- } else {
- shortUpdateTimer.stop()
- }
- }
-
- onConnectedToNetworkChanged: {
- if (viewVisible) {
- if (!updateTimer.running) {
- shortUpdateTimer.start()
- }
- }
- }
-
- // The Mastodon feed is updated 3 seconds after the feed view becomes visible,
- // unless it has been updated during last 60 seconds. After that it will be updated
- // periodically in every 60 seconds as long as the feed view is visible.
-
- Timer {
- id: shortUpdateTimer
-
- interval: 3000
- onTriggered: {
- delegateItem.sync()
- updateTimer.start()
- }
- }
-
- Timer {
- id: updateTimer
-
- interval: 60000
- repeat: true
- onTriggered: {
- if (delegateItem.viewVisible) {
- delegateItem.sync()
- } else {
- stop()
- }
- }
- }
-
- function variantRole(modelData, roleNames) {
- for (var i = 0; i < roleNames.length; ++i) {
- var value = modelData[roleNames[i]]
- if (typeof value !== "undefined" && value !== null) {
- return value
- }
- }
- return undefined
- }
-
- function stringRole(modelData, roleNames) {
- for (var i = 0; i < roleNames.length; ++i) {
- var value = modelData[roleNames[i]]
- if (typeof value === "undefined" || value === null) {
- continue
- }
- value = String(value)
- if (value.length > 0) {
- return value
- }
- }
- return ""
- }
-
- function statusUrl(modelData) {
- var directUrl = stringRole(modelData, ["url", "link", "uri"])
- if (directUrl.length > 0) {
- return directUrl
- }
-
- var instanceUrl = stringRole(modelData, ["instanceUrl", "serverUrl", "baseUrl"])
- if (instanceUrl.length === 0) {
- instanceUrl = "https://mastodon.social"
- }
- while (instanceUrl.length > 0 && instanceUrl.charAt(instanceUrl.length - 1) === "/") {
- instanceUrl = instanceUrl.slice(0, instanceUrl.length - 1)
- }
-
- var accountName = stringRole(modelData, ["accountName", "acct", "screenName", "username"])
- var statusId = stringRole(modelData, ["mastodonId", "statusId", "id", "twitterId"])
- if (accountName.length > 0 && statusId.length > 0) {
- while (accountName.length > 0 && accountName.charAt(0) === "@") {
- accountName = accountName.substring(1)
- }
- return instanceUrl + "/@" + accountName + "/" + statusId
- }
-
- return instanceUrl + "/explore"
- }
-
- function authorizeInteractionUrl(modelData) {
- var targetUrl = statusUrl(modelData)
- if (targetUrl.length === 0) {
- return targetUrl
- }
-
- var instanceUrl = stringRole(modelData, ["instanceUrl", "serverUrl", "baseUrl"])
- if (instanceUrl.length === 0) {
- return targetUrl
- }
- while (instanceUrl.length > 0 && instanceUrl.charAt(instanceUrl.length - 1) === "/") {
- instanceUrl = instanceUrl.slice(0, instanceUrl.length - 1)
- }
-
- // 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 convertUrl(source) {
- if (source.indexOf("_normal.") !== -1) {
- return source.replace("_normal.", "_bigger.")
- } else if (source.indexOf("_mini.") !== -1) {
- return source.replace("_mini.", "_bigger.")
- }
- return source
- }
-
- function firstAccountId(modelData) {
- var accounts = modelData.accounts
- if (accounts && accounts.length > 0) {
- var accountId = Number(accounts[0])
- if (!isNaN(accountId)) {
- return accountId
- }
- }
- return -1
- }
-}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.cpp b/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.cpp
deleted file mode 100644
index aa98a95..0000000
--- a/eventsview-plugins/eventsview-plugin-mastodon/mastodonpostsmodel.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2013-2026 Jolla Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "mastodonpostsmodel.h"
-#include <QtCore/QVariantMap>
-
-namespace {
-
-static const char *URL_KEY = "url";
-static const char *TYPE_KEY = "type";
-static const char *TYPE_PHOTO = "photo";
-static const char *TYPE_VIDEO = "video";
-
-QVariantMap createImageData(const SocialPostImage::ConstPtr &image)
-{
- QVariantMap imageData;
- imageData.insert(QLatin1String(URL_KEY), image->url());
- switch (image->type()) {
- case SocialPostImage::Video:
- imageData.insert(QLatin1String(TYPE_KEY), QLatin1String(TYPE_VIDEO));
- break;
- default:
- imageData.insert(QLatin1String(TYPE_KEY), QLatin1String(TYPE_PHOTO));
- break;
- }
- return imageData;
-}
-
-}
-
-MastodonPostsModel::MastodonPostsModel(QObject *parent)
- : QAbstractListModel(parent)
-{
- connect(&m_database, &AbstractSocialPostCacheDatabase::postsChanged,
- this, &MastodonPostsModel::postsChanged);
- connect(&m_database, SIGNAL(accountIdFilterChanged()),
- this, SIGNAL(accountIdFilterChanged()));
-}
-
-int MastodonPostsModel::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent)
- return m_data.count();
-}
-
-QVariant MastodonPostsModel::data(const QModelIndex &index, int role) const
-{
- const int row = index.row();
- if (!index.isValid() || row < 0 || row >= m_data.count()) {
- return QVariant();
- }
-
- return m_data.at(row).value(role);
-}
-
-QHash<int, QByteArray> MastodonPostsModel::roleNames() const
-{
- QHash<int, QByteArray> roleNames;
- roleNames.insert(MastodonId, "mastodonId");
- roleNames.insert(Name, "name");
- roleNames.insert(AccountName, "accountName");
- roleNames.insert(Acct, "acct");
- roleNames.insert(Body, "body");
- roleNames.insert(Timestamp, "timestamp");
- roleNames.insert(Icon, "icon");
- roleNames.insert(Images, "images");
- roleNames.insert(Url, "url");
- roleNames.insert(Link, "link");
- roleNames.insert(BoostedBy, "boostedBy");
- roleNames.insert(RebloggedBy, "rebloggedBy");
- roleNames.insert(RepliesCount, "repliesCount");
- roleNames.insert(FavouritesCount, "favouritesCount");
- roleNames.insert(ReblogsCount, "reblogsCount");
- roleNames.insert(Favourited, "favourited");
- roleNames.insert(Reblogged, "reblogged");
- roleNames.insert(InstanceUrl, "instanceUrl");
- roleNames.insert(Accounts, "accounts");
- return roleNames;
-}
-
-QVariantList MastodonPostsModel::accountIdFilter() const
-{
- return m_database.accountIdFilter();
-}
-
-void MastodonPostsModel::setAccountIdFilter(const QVariantList &accountIds)
-{
- m_database.setAccountIdFilter(accountIds);
-}
-
-void MastodonPostsModel::refresh()
-{
- m_database.refresh();
-}
-
-void MastodonPostsModel::postsChanged()
-{
- QList<RowData> data;
- QList<SocialPost::ConstPtr> postsData = m_database.posts();
- Q_FOREACH (const SocialPost::ConstPtr &post, postsData) {
- RowData eventMap;
- const QString accountName = m_database.accountName(post);
- const QString postUrl = m_database.url(post);
- const QString boostedBy = m_database.boostedBy(post);
- const int repliesCount = m_database.repliesCount(post);
- const int favouritesCount = m_database.favouritesCount(post);
- const int reblogsCount = m_database.reblogsCount(post);
- const bool favourited = m_database.favourited(post);
- const bool reblogged = m_database.reblogged(post);
-
- eventMap.insert(MastodonPostsModel::MastodonId, post->identifier());
- eventMap.insert(MastodonPostsModel::Name, post->name());
- eventMap.insert(MastodonPostsModel::AccountName, accountName);
- eventMap.insert(MastodonPostsModel::Acct, accountName);
- eventMap.insert(MastodonPostsModel::Body, post->body());
- eventMap.insert(MastodonPostsModel::Timestamp, post->timestamp());
- eventMap.insert(MastodonPostsModel::Icon, post->icon());
- eventMap.insert(MastodonPostsModel::Url, postUrl);
- eventMap.insert(MastodonPostsModel::Link, postUrl);
- eventMap.insert(MastodonPostsModel::BoostedBy, boostedBy);
- eventMap.insert(MastodonPostsModel::RebloggedBy, boostedBy);
- eventMap.insert(MastodonPostsModel::RepliesCount, repliesCount);
- eventMap.insert(MastodonPostsModel::FavouritesCount, favouritesCount);
- eventMap.insert(MastodonPostsModel::ReblogsCount, reblogsCount);
- eventMap.insert(MastodonPostsModel::Favourited, favourited);
- eventMap.insert(MastodonPostsModel::Reblogged, reblogged);
- eventMap.insert(MastodonPostsModel::InstanceUrl, m_database.instanceUrl(post));
-
- QVariantList images;
- Q_FOREACH (const SocialPostImage::ConstPtr &image, post->images()) {
- images.append(createImageData(image));
- }
- eventMap.insert(MastodonPostsModel::Images, images);
-
- QVariantList accountsVariant;
- Q_FOREACH (int account, post->accounts()) {
- accountsVariant.append(account);
- }
- eventMap.insert(MastodonPostsModel::Accounts, accountsVariant);
- data.append(eventMap);
- }
-
- const int oldCount = m_data.count();
- beginResetModel();
- m_data = data;
- endResetModel();
- if (oldCount != m_data.count()) {
- emit countChanged();
- }
-}
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/plugin.cpp b/eventsview-plugins/eventsview-plugin-mastodon/plugin.cpp
deleted file mode 100644
index 9ade6e2..0000000
--- a/eventsview-plugins/eventsview-plugin-mastodon/plugin.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <QQmlExtensionPlugin>
-#include <QtQml>
-
-#include "mastodonpostactions.h"
-#include "mastodonpostsmodel.h"
-
-class JollaEventsviewMastodonPlugin : public QQmlExtensionPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "com.jolla.eventsview.mastodon")
-
-public:
- void registerTypes(const char *uri) override
- {
- Q_ASSERT(QLatin1String(uri) == QLatin1String("com.jolla.eventsview.mastodon"));
- qmlRegisterType<MastodonPostsModel>(uri, 1, 0, "MastodonPostsModel");
- qmlRegisterType<MastodonPostActions>(uri, 1, 0, "MastodonPostActions");
- }
-};
-
-#include "plugin.moc"
diff --git a/eventsview-plugins/eventsview-plugin-mastodon/qmldir b/eventsview-plugins/eventsview-plugin-mastodon/qmldir
deleted file mode 100644
index 74461ce..0000000
--- a/eventsview-plugins/eventsview-plugin-mastodon/qmldir
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (C) 2013-2026 Jolla Ltd.
-
-module com.jolla.eventsview.mastodon
-plugin jollaeventsviewmastodonplugin
diff --git a/eventsview-plugins/eventsview-plugins.pro b/eventsview-plugins/eventsview-plugins.pro
index 095fd02..bc96c5f 100644
--- a/eventsview-plugins/eventsview-plugins.pro
+++ b/eventsview-plugins/eventsview-plugins.pro
@@ -3,4 +3,4 @@
# SPDX-License-Identifier: BSD-3-Clause
TEMPLATE = subdirs
-SUBDIRS += eventsview-plugin-mastodon
+SUBDIRS += eventsview-plugin-fediverse
diff --git a/icons/svgs/icons/icon-l-fediverse.svg b/icons/svgs/icons/icon-l-fediverse.svg
new file mode 100644
index 0000000..3ff5f76
--- /dev/null
+++ b/icons/svgs/icons/icon-l-fediverse.svg
@@ -0,0 +1,10 @@
+<svg width="75" height="79" viewBox="0 0 75 79" xmlns="http://www.w3.org/2000/svg">
+ <rect width="75" height="79" rx="18" fill="#111111"/>
+ <text
+ x="37.5"
+ y="53"
+ text-anchor="middle"
+ font-family="Noto Sans Symbols 2, Noto Sans Symbols, DejaVu Sans, sans-serif"
+ font-size="46"
+ fill="#ffffff">⁂</text>
+</svg>
diff --git a/icons/svgs/icons/icon-l-mastodon.svg b/icons/svgs/icons/icon-l-mastodon.svg
deleted file mode 100644
index 0f8baeb..0000000
--- a/icons/svgs/icons/icon-l-mastodon.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<svg width="75" height="79" viewBox="0 0 75 79" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M73.8393 17.4898C72.6973 9.00165 65.2994 2.31235 56.5296 1.01614C55.05 0.797115 49.4441 0 36.4582 0H36.3612C23.3717 0 20.585 0.797115 19.1054 1.01614C10.5798 2.27644 2.79399 8.28712 0.904997 16.8758C-0.00358524 21.1056 -0.100549 25.7949 0.0682394 30.0965C0.308852 36.2651 0.355538 42.423 0.91577 48.5665C1.30307 52.6474 1.97872 56.6957 2.93763 60.6812C4.73325 68.042 12.0019 74.1676 19.1233 76.6666C26.7478 79.2728 34.9474 79.7055 42.8039 77.9162C43.6682 77.7151 44.5217 77.4817 45.3645 77.216C47.275 76.6092 49.5123 75.9305 51.1571 74.7385C51.1797 74.7217 51.1982 74.7001 51.2112 74.6753C51.2243 74.6504 51.2316 74.6229 51.2325 74.5948V68.6416C51.2321 68.6154 51.2259 68.5896 51.2142 68.5661C51.2025 68.5426 51.1858 68.522 51.1651 68.5058C51.1444 68.4896 51.1204 68.4783 51.0948 68.4726C51.0692 68.4669 51.0426 68.467 51.0171 68.4729C45.9835 69.675 40.8254 70.2777 35.6502 70.2682C26.7439 70.2682 24.3486 66.042 23.6626 64.2826C23.1113 62.762 22.7612 61.1759 22.6212 59.5646C22.6197 59.5375 22.6247 59.5105 22.6357 59.4857C22.6466 59.4609 22.6633 59.4391 22.6843 59.422C22.7053 59.4048 22.73 59.3929 22.7565 59.3871C22.783 59.3813 22.8104 59.3818 22.8367 59.3886C27.7864 60.5826 32.8604 61.1853 37.9522 61.1839C39.1768 61.1839 40.3978 61.1839 41.6224 61.1516C46.7435 61.008 52.1411 60.7459 57.1796 59.7621C57.3053 59.7369 57.431 59.7154 57.5387 59.6831C65.4861 58.157 73.0493 53.3672 73.8178 41.2381C73.8465 40.7606 73.9184 36.2364 73.9184 35.7409C73.9219 34.0569 74.4606 23.7949 73.8393 17.4898Z" fill="url(#paint0_linear_549_34)"/>
-<path d="M61.2484 27.0263V48.114H52.8916V27.6475C52.8916 23.3388 51.096 21.1413 47.4437 21.1413C43.4287 21.1413 41.4177 23.7409 41.4177 28.8755V40.0782H33.1111V28.8755C33.1111 23.7409 31.0965 21.1413 27.0815 21.1413C23.4507 21.1413 21.6371 23.3388 21.6371 27.6475V48.114H13.2839V27.0263C13.2839 22.7176 14.384 19.2946 16.5843 16.7572C18.8539 14.2258 21.8311 12.926 25.5264 12.926C29.8036 12.926 33.0357 14.5705 35.1905 17.8559L37.2698 21.346L39.3527 17.8559C41.5074 14.5705 44.7395 12.926 49.0095 12.926C52.7013 12.926 55.6784 14.2258 57.9553 16.7572C60.1531 19.2922 61.2508 22.7152 61.2484 27.0263Z" fill="white"/>
-<defs>
-<linearGradient id="paint0_linear_549_34" x1="37.0692" y1="0" x2="37.0692" y2="79" gradientUnits="userSpaceOnUse">
-<stop stop-color="#6364FF"/>
-<stop offset="1" stop-color="#563ACC"/>
-</linearGradient>
-</defs>
-</svg>
diff --git a/rpm/sailfish-account-fediverse.spec b/rpm/sailfish-account-fediverse.spec
new file mode 100644
index 0000000..558ff50
--- /dev/null
+++ b/rpm/sailfish-account-fediverse.spec
@@ -0,0 +1,133 @@
+# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+Name: sailfish-account-fediverse
+License: BSD-3-Clause AND LGPL-2.1-or-later
+Version: 1.0.2
+Release: 1
+Source0: %{name}-%{version}.tar.bz2
+Summary: SailfishOS account plugin for Fediverse
+BuildRequires: qt5-qmake
+BuildRequires: qt5-qttools-linguist
+BuildRequires: sailfish-svg2png
+BuildRequires: pkgconfig(Qt5Core)
+BuildRequires: pkgconfig(Qt5DBus)
+BuildRequires: pkgconfig(Qt5Sql)
+BuildRequires: pkgconfig(Qt5Network)
+BuildRequires: pkgconfig(Qt5Qml)
+BuildRequires: pkgconfig(mlite5)
+BuildRequires: pkgconfig(buteosyncfw5) >= 0.10.0
+BuildRequires: pkgconfig(accounts-qt5)
+BuildRequires: pkgconfig(libsignon-qt5)
+BuildRequires: pkgconfig(socialcache)
+BuildRequires: pkgconfig(libsailfishkeyprovider)
+BuildRequires: pkgconfig(sailfishaccounts)
+BuildRequires: pkgconfig(nemotransferengine-qt5) >= 2.0.0
+BuildRequires: pkgconfig(nemonotifications-qt5)
+Requires: jolla-settings-accounts-extensions-onlinesync
+Requires: qmf-oauth2-plugin >= 0.0.7
+Requires: buteo-syncfw-qt5-msyncd
+Requires: systemd
+Requires: lipstick-jolla-home-qt5-components >= 1.2.50
+Requires: eventsview-extensions
+Requires: sailfishsilica-qt5 >= 1.1.108
+Requires: declarative-transferengine-qt5 >= 0.3.13
+Requires: nemo-transferengine-qt5 >= 2.0.0
+Requires(post): %{_libexecdir}/manage-groups
+Requires(postun): %{_libexecdir}/manage-groups
+
+%description
+%{summary}. Supports displaying current feed in the Events View,
+sharing images, and notifications.
+
+%package -n sailfish-account-fediverse-ts-devel
+Summary: Translation source files for sailfish-account-fediverse
+Requires: %{name} = %{version}-%{release}
+
+%description -n sailfish-account-fediverse-ts-devel
+Translation source files for sailfish-account-fediverse components.
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+%qmake5 "VERSION=%{version}"
+%make_build
+
+%install
+%qmake5_install
+
+%post
+/sbin/ldconfig
+%{_libexecdir}/manage-groups add account-fediverse || :
+systemctl-user try-restart msyncd.service || :
+
+%posttrans
+# Pre-4.6 SailfishOS resolves theme icons from the legacy meegotouch tree.
+# If that theme exists, point it at the packaged silica icons.
+theme_dir=%{_datadir}/themes/sailfish-default
+legacy_dir="$theme_dir/meegotouch"
+if [ -d "$legacy_dir" ]; then
+ for icon in "$theme_dir"/silica/*/icons/icon-l-fediverse.png; do
+ [ -e "$icon" ] || continue
+ scale="$(basename "$(dirname "$(dirname "$icon")")")"
+ target_dir="$legacy_dir/$scale/icons"
+ [ -d "$target_dir" ] || continue
+ ln -sfn "../../../silica/${scale}/icons/icon-l-fediverse.png" \
+ "$target_dir/icon-l-fediverse.png"
+ done
+fi
+
+%postun
+/sbin/ldconfig
+if [ "$1" -eq 0 ]; then
+ theme_dir=%{_datadir}/themes/sailfish-default
+ legacy_dir="$theme_dir/meegotouch"
+ if [ -d "$legacy_dir" ]; then
+ for icon in "$legacy_dir"/*/icons/icon-l-fediverse.png; do
+ [ -L "$icon" ] || continue
+ rm -f "$icon"
+ done
+ fi
+ %{_libexecdir}/manage-groups remove account-fediverse || :
+fi
+
+%files
+%license LICENSES/BSD-3-Clause.txt
+%license LICENSES/LGPL-2.1-or-later.txt
+%{_libdir}/libfediversecommon.so.*
+%exclude %{_libdir}/libfediversecommon.so
+%{_libdir}/libfediversebuteocommon.so.*
+%exclude %{_libdir}/libfediversebuteocommon.so
+%{_datadir}/accounts/providers/fediverse.provider
+%{_datadir}/accounts/services/fediverse-microblog.service
+%{_datadir}/accounts/services/fediverse-notifications.service
+%{_datadir}/accounts/services/fediverse-sharing.service
+%{_datadir}/accounts/ui/FediverseSettingsDisplay.qml
+%{_datadir}/accounts/ui/fediverse.qml
+%{_datadir}/accounts/ui/fediverse-settings.qml
+%{_datadir}/accounts/ui/fediverse-update.qml
+%{_libdir}/qt5/qml/com/jolla/settings/accounts/fediverse/*
+%{_datadir}/translations/settings-accounts-fediverse_eng_en.qm
+%{_datadir}/themes/sailfish-default/silica/*/icons/icon-l-fediverse.png
+%{_libdir}/buteo-plugins-qt5/oopp/libfediverse-posts-client.so
+%config %{_sysconfdir}/buteo/profiles/client/fediverse-posts.xml
+%config %{_sysconfdir}/buteo/profiles/sync/fediverse.Posts.xml
+%{_libdir}/buteo-plugins-qt5/oopp/libfediverse-notifications-client.so
+%config %{_sysconfdir}/buteo/profiles/client/fediverse-notifications.xml
+%config %{_sysconfdir}/buteo/profiles/sync/fediverse.Notifications.xml
+%{_libdir}/qt5/qml/com/jolla/eventsview/fediverse/*
+%{_datadir}/lipstick/eventfeed/fediverse-delegate.qml
+%{_datadir}/lipstick/eventfeed/FediverseFeedItem.qml
+%{_datadir}/translations/lipstick-jolla-home-fediverse_eng_en.qm
+%{_datadir}/translations/lipstick-jolla-home-fediverse-notifications_eng_en.qm
+
+%{_libdir}/nemo-transferengine/plugins/sharing/libfediverseshareplugin.so
+%{_libdir}/nemo-transferengine/plugins/transfer/libfediversetransferplugin.so
+%{_datadir}/nemo-transferengine/plugins/sharing/FediverseSharePost.qml
+
+%files -n sailfish-account-fediverse-ts-devel
+%{_datadir}/translations/source/settings-accounts-fediverse.ts
+%{_datadir}/translations/source/lipstick-jolla-home-fediverse.ts
+%{_datadir}/translations/source/lipstick-jolla-home-fediverse-notifications.ts
diff --git a/rpm/sailfish-account-mastodon.spec b/rpm/sailfish-account-mastodon.spec
deleted file mode 100644
index 923ae8c..0000000
--- a/rpm/sailfish-account-mastodon.spec
+++ /dev/null
@@ -1,133 +0,0 @@
-# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-Name: sailfish-account-mastodon
-License: BSD-3-Clause AND LGPL-2.1-or-later
-Version: 1.0.2
-Release: 1
-Source0: %{name}-%{version}.tar.bz2
-Summary: SailfishOS account plugin for Mastodon
-BuildRequires: qt5-qmake
-BuildRequires: qt5-qttools-linguist
-BuildRequires: sailfish-svg2png
-BuildRequires: pkgconfig(Qt5Core)
-BuildRequires: pkgconfig(Qt5DBus)
-BuildRequires: pkgconfig(Qt5Sql)
-BuildRequires: pkgconfig(Qt5Network)
-BuildRequires: pkgconfig(Qt5Qml)
-BuildRequires: pkgconfig(mlite5)
-BuildRequires: pkgconfig(buteosyncfw5) >= 0.10.0
-BuildRequires: pkgconfig(accounts-qt5)
-BuildRequires: pkgconfig(libsignon-qt5)
-BuildRequires: pkgconfig(socialcache)
-BuildRequires: pkgconfig(libsailfishkeyprovider)
-BuildRequires: pkgconfig(sailfishaccounts)
-BuildRequires: pkgconfig(nemotransferengine-qt5) >= 2.0.0
-BuildRequires: pkgconfig(nemonotifications-qt5)
-Requires: jolla-settings-accounts-extensions-onlinesync
-Requires: qmf-oauth2-plugin >= 0.0.7
-Requires: buteo-syncfw-qt5-msyncd
-Requires: systemd
-Requires: lipstick-jolla-home-qt5-components >= 1.2.50
-Requires: eventsview-extensions
-Requires: sailfishsilica-qt5 >= 1.1.108
-Requires: declarative-transferengine-qt5 >= 0.3.13
-Requires: nemo-transferengine-qt5 >= 2.0.0
-Requires(post): %{_libexecdir}/manage-groups
-Requires(postun): %{_libexecdir}/manage-groups
-
-%description
-%{summary}. Supports displaying current feed in the Events View,
-sharing images, and notifications.
-
-%package -n sailfish-account-mastodon-ts-devel
-Summary: Translation source files for sailfish-account-mastodon
-Requires: %{name} = %{version}-%{release}
-
-%description -n sailfish-account-mastodon-ts-devel
-Translation source files for sailfish-account-mastodon components.
-
-%prep
-%setup -q -n %{name}-%{version}
-
-%build
-%qmake5 "VERSION=%{version}"
-%make_build
-
-%install
-%qmake5_install
-
-%post
-/sbin/ldconfig
-%{_libexecdir}/manage-groups add account-mastodon || :
-systemctl-user try-restart msyncd.service || :
-
-%posttrans
-# Pre-4.6 SailfishOS resolves theme icons from the legacy meegotouch tree.
-# If that theme exists, point it at the packaged silica icons.
-theme_dir=%{_datadir}/themes/sailfish-default
-legacy_dir="$theme_dir/meegotouch"
-if [ -d "$legacy_dir" ]; then
- for icon in "$theme_dir"/silica/*/icons/icon-l-mastodon.png; do
- [ -e "$icon" ] || continue
- scale="$(basename "$(dirname "$(dirname "$icon")")")"
- target_dir="$legacy_dir/$scale/icons"
- [ -d "$target_dir" ] || continue
- ln -sfn "../../../silica/${scale}/icons/icon-l-mastodon.png" \
- "$target_dir/icon-l-mastodon.png"
- done
-fi
-
-%postun
-/sbin/ldconfig
-if [ "$1" -eq 0 ]; then
- theme_dir=%{_datadir}/themes/sailfish-default
- legacy_dir="$theme_dir/meegotouch"
- if [ -d "$legacy_dir" ]; then
- for icon in "$legacy_dir"/*/icons/icon-l-mastodon.png; do
- [ -L "$icon" ] || continue
- rm -f "$icon"
- done
- fi
- %{_libexecdir}/manage-groups remove account-mastodon || :
-fi
-
-%files
-%license LICENSES/BSD-3-Clause.txt
-%license LICENSES/LGPL-2.1-or-later.txt
-%{_libdir}/libmastodoncommon.so.*
-%exclude %{_libdir}/libmastodoncommon.so
-%{_libdir}/libmastodonbuteocommon.so.*
-%exclude %{_libdir}/libmastodonbuteocommon.so
-%{_datadir}/accounts/providers/mastodon.provider
-%{_datadir}/accounts/services/mastodon-microblog.service
-%{_datadir}/accounts/services/mastodon-notifications.service
-%{_datadir}/accounts/services/mastodon-sharing.service
-%{_datadir}/accounts/ui/MastodonSettingsDisplay.qml
-%{_datadir}/accounts/ui/mastodon.qml
-%{_datadir}/accounts/ui/mastodon-settings.qml
-%{_datadir}/accounts/ui/mastodon-update.qml
-%{_libdir}/qt5/qml/com/jolla/settings/accounts/mastodon/*
-%{_datadir}/translations/settings-accounts-mastodon_eng_en.qm
-%{_datadir}/themes/sailfish-default/silica/*/icons/icon-l-mastodon.png
-%{_libdir}/buteo-plugins-qt5/oopp/libmastodon-posts-client.so
-%config %{_sysconfdir}/buteo/profiles/client/mastodon-posts.xml
-%config %{_sysconfdir}/buteo/profiles/sync/mastodon.Posts.xml
-%{_libdir}/buteo-plugins-qt5/oopp/libmastodon-notifications-client.so
-%config %{_sysconfdir}/buteo/profiles/client/mastodon-notifications.xml
-%config %{_sysconfdir}/buteo/profiles/sync/mastodon.Notifications.xml
-%{_libdir}/qt5/qml/com/jolla/eventsview/mastodon/*
-%{_datadir}/lipstick/eventfeed/mastodon-delegate.qml
-%{_datadir}/lipstick/eventfeed/MastodonFeedItem.qml
-%{_datadir}/translations/lipstick-jolla-home-mastodon_eng_en.qm
-%{_datadir}/translations/lipstick-jolla-home-mastodon-notifications_eng_en.qm
-
-%{_libdir}/nemo-transferengine/plugins/sharing/libmastodonshareplugin.so
-%{_libdir}/nemo-transferengine/plugins/transfer/libmastodontransferplugin.so
-%{_datadir}/nemo-transferengine/plugins/sharing/MastodonSharePost.qml
-
-%files -n sailfish-account-mastodon-ts-devel
-%{_datadir}/translations/source/settings-accounts-mastodon.ts
-%{_datadir}/translations/source/lipstick-jolla-home-mastodon.ts
-%{_datadir}/translations/source/lipstick-jolla-home-mastodon-notifications.ts
diff --git a/sailfish-account-mastodon.pro b/sailfish-account-fediverse.pro
index 91befc3..7be0bff 100644
--- a/sailfish-account-mastodon.pro
+++ b/sailfish-account-fediverse.pro
@@ -15,4 +15,4 @@ buteo-plugins.depends = common
transferengine-plugins.depends = common
eventsview-plugins.depends = common
-OTHER_FILES += rpm/sailfish-account-mastodon.spec
+OTHER_FILES += rpm/sailfish-account-fediverse.spec
diff --git a/settings/accounts-translations-plugin/accounts-translations-plugin.pro b/settings/accounts-translations-plugin/accounts-translations-plugin.pro
index aad978f..faa5ae5 100644
--- a/settings/accounts-translations-plugin/accounts-translations-plugin.pro
+++ b/settings/accounts-translations-plugin/accounts-translations-plugin.pro
@@ -3,13 +3,13 @@
# SPDX-License-Identifier: BSD-3-Clause
TEMPLATE = lib
-TARGET = mastodonaccountstranslationsplugin
+TARGET = fediverseaccountstranslationsplugin
TARGET = $$qtLibraryTarget($$TARGET)
-MODULENAME = com/jolla/settings/accounts/mastodon
+MODULENAME = com/jolla/settings/accounts/fediverse
TARGETPATH = $$[QT_INSTALL_QML]/$$MODULENAME
-QT += qml
+QT += qml network
CONFIG += plugin
SOURCES += plugin.cpp
diff --git a/settings/accounts-translations-plugin/plugin.cpp b/settings/accounts-translations-plugin/plugin.cpp
index 4a1c651..e377b6c 100644
--- a/settings/accounts-translations-plugin/plugin.cpp
+++ b/settings/accounts-translations-plugin/plugin.cpp
@@ -5,10 +5,20 @@
*/
#include <QCoreApplication>
+#include <QCryptographicHash>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
#include <QLocale>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
#include <QQmlEngine>
#include <QQmlExtensionPlugin>
+#include <QSaveFile>
+#include <QSet>
+#include <QStandardPaths>
#include <QTranslator>
+#include <QUrl>
#include <QtQml>
class AppTranslator : public QTranslator
@@ -27,10 +37,167 @@ public:
}
};
-class MastodonAccountsTranslationsPlugin : public QQmlExtensionPlugin
+class FediverseInstanceIconCache : public QObject
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "com.jolla.settings.accounts.mastodon")
+public:
+ explicit FediverseInstanceIconCache(QObject *parent = nullptr)
+ : QObject(parent)
+ , m_networkAccessManager(new QNetworkAccessManager(this))
+ {
+ }
+
+ Q_INVOKABLE QString cachedIconPath(const QString &apiHost) const
+ {
+ const QString normalizedHost = normalizeApiHost(apiHost);
+ if (normalizedHost.isEmpty()) {
+ return QString();
+ }
+
+ const QString prefix = iconPrefix(normalizedHost);
+ const QDir dir(cacheDirectory());
+ const QStringList matches = dir.entryList(QStringList() << (prefix + QStringLiteral(".*")), QDir::Files);
+ if (matches.isEmpty()) {
+ return QString();
+ }
+
+ return dir.absoluteFilePath(matches.first());
+ }
+
+ Q_INVOKABLE void cacheIcon(const QString &apiHost, const QString &iconUrl)
+ {
+ const QString normalizedHost = normalizeApiHost(apiHost);
+ const QUrl normalizedUrl = QUrl::fromUserInput(iconUrl);
+ if (normalizedHost.isEmpty() || !normalizedUrl.isValid() || normalizedUrl.scheme().isEmpty()) {
+ emit iconError(apiHost);
+ return;
+ }
+
+ const QString existingPath = cachedIconPath(normalizedHost);
+ if (!existingPath.isEmpty()) {
+ emit iconReady(normalizedHost, existingPath);
+ return;
+ }
+
+ if (m_hostsInFlight.contains(normalizedHost)) {
+ return;
+ }
+
+ QNetworkReply *reply = m_networkAccessManager->get(QNetworkRequest(normalizedUrl));
+ reply->setProperty("apiHost", normalizedHost);
+ connect(reply, &QNetworkReply::finished, this, [this, reply]() { handleReply(reply); });
+ m_hostsInFlight.insert(normalizedHost);
+ }
+
+Q_SIGNALS:
+ void iconReady(const QString &apiHost, const QString &iconPath);
+ void iconError(const QString &apiHost);
+
+private:
+ static QString normalizeApiHost(const QString &rawHost)
+ {
+ QString host = rawHost.trimmed();
+ if (host.isEmpty()) {
+ return QString();
+ }
+ if (!host.startsWith(QLatin1String("https://")) && !host.startsWith(QLatin1String("http://"))) {
+ host.prepend(QStringLiteral("https://"));
+ }
+
+ const QUrl url(host);
+ if (!url.isValid() || url.host().isEmpty()) {
+ return QString();
+ }
+
+ QString normalized = QString::fromLatin1(url.toEncoded(QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment));
+ if (normalized.endsWith(QLatin1Char('/'))) {
+ normalized.chop(1);
+ }
+ return normalized;
+ }
+
+ static QString cacheDirectory()
+ {
+ const QString base = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
+ return base + QStringLiteral("/sailfish-account-fediverse/icons");
+ }
+
+ static QString iconPrefix(const QString &apiHost)
+ {
+ return QString::fromLatin1(QCryptographicHash::hash(apiHost.toUtf8(), QCryptographicHash::Sha1).toHex());
+ }
+
+ static QString extensionForReply(QNetworkReply *reply)
+ {
+ const QString suffix = QFileInfo(reply->url().path()).suffix().trimmed().toLower();
+ if (!suffix.isEmpty()) {
+ return suffix;
+ }
+
+ const QString contentType = QString::fromLatin1(reply->header(QNetworkRequest::ContentTypeHeader).toByteArray()).toLower();
+ if (contentType.contains(QLatin1String("png"))) {
+ return QStringLiteral("png");
+ }
+ if (contentType.contains(QLatin1String("jpeg")) || contentType.contains(QLatin1String("jpg"))) {
+ return QStringLiteral("jpg");
+ }
+ if (contentType.contains(QLatin1String("webp"))) {
+ return QStringLiteral("webp");
+ }
+ if (contentType.contains(QLatin1String("svg"))) {
+ return QStringLiteral("svg");
+ }
+ return QStringLiteral("img");
+ }
+
+ void handleReply(QNetworkReply *reply)
+ {
+ const QString apiHost = reply->property("apiHost").toString();
+ m_hostsInFlight.remove(apiHost);
+
+ const int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ const bool success = reply->error() == QNetworkReply::NoError && httpCode >= 200 && httpCode < 300;
+ const QString extension = extensionForReply(reply);
+ const QByteArray data = reply->readAll();
+ reply->deleteLater();
+
+ if (!success || data.isEmpty()) {
+ emit iconError(apiHost);
+ return;
+ }
+
+ const QString dirPath = cacheDirectory();
+ QDir dir;
+ if (!dir.mkpath(dirPath)) {
+ emit iconError(apiHost);
+ return;
+ }
+
+ const QString prefix = iconPrefix(apiHost);
+ const QDir cacheDir(dirPath);
+ const QStringList matches = cacheDir.entryList(QStringList() << (prefix + QStringLiteral(".*")), QDir::Files);
+ for (const QString &match : matches) {
+ QFile::remove(cacheDir.absoluteFilePath(match));
+ }
+
+ const QString filePath = cacheDir.absoluteFilePath(prefix + QStringLiteral(".") + extension);
+ QSaveFile file(filePath);
+ if (!file.open(QIODevice::WriteOnly) || file.write(data) != data.size() || !file.commit()) {
+ emit iconError(apiHost);
+ return;
+ }
+
+ emit iconReady(apiHost, filePath);
+ }
+
+ QNetworkAccessManager *m_networkAccessManager;
+ QSet<QString> m_hostsInFlight;
+};
+
+class FediverseAccountsTranslationsPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "com.jolla.settings.accounts.fediverse")
public:
void initializeEngine(QQmlEngine *engine, const char *uri) override
@@ -38,18 +205,19 @@ public:
Q_UNUSED(uri)
AppTranslator *engineeringEnglish = new AppTranslator(engine);
- engineeringEnglish->load("settings-accounts-mastodon_eng_en", "/usr/share/translations");
+ engineeringEnglish->load("settings-accounts-fediverse_eng_en", "/usr/share/translations");
AppTranslator *translator = new AppTranslator(engine);
- translator->load(QLocale(), "settings-accounts-mastodon", "-", "/usr/share/translations");
+ translator->load(QLocale(), "settings-accounts-fediverse", "-", "/usr/share/translations");
}
void registerTypes(const char *uri) override
{
- Q_ASSERT(QLatin1String(uri) == QLatin1String("com.jolla.settings.accounts.mastodon"));
- qmlRegisterUncreatableType<MastodonAccountsTranslationsPlugin>(uri, 1, 0,
- "MastodonTranslationPlugin",
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("com.jolla.settings.accounts.fediverse"));
+ qmlRegisterUncreatableType<FediverseAccountsTranslationsPlugin>(uri, 1, 0,
+ "FediverseTranslationPlugin",
QString());
+ qmlRegisterType<FediverseInstanceIconCache>(uri, 1, 0, "FediverseInstanceIconCache");
}
};
diff --git a/settings/accounts-translations-plugin/qmldir b/settings/accounts-translations-plugin/qmldir
index cf96622..69f186b 100644
--- a/settings/accounts-translations-plugin/qmldir
+++ b/settings/accounts-translations-plugin/qmldir
@@ -1,4 +1,4 @@
# Copyright (C) 2013-2026 Jolla Ltd.
-module com.jolla.settings.accounts.mastodon
-plugin mastodonaccountstranslationsplugin
+module com.jolla.settings.accounts.fediverse
+plugin fediverseaccountstranslationsplugin
diff --git a/settings/accounts/accounts.pro b/settings/accounts/accounts.pro
index 37982a3..1c80cf9 100644
--- a/settings/accounts/accounts.pro
+++ b/settings/accounts/accounts.pro
@@ -4,8 +4,8 @@
TEMPLATE = aux
-TS_FILE = $$OUT_PWD/settings-accounts-mastodon.ts
-EE_QM = $$OUT_PWD/settings-accounts-mastodon_eng_en.qm
+TS_FILE = $$OUT_PWD/settings-accounts-fediverse.ts
+EE_QM = $$OUT_PWD/settings-accounts-fediverse_eng_en.qm
ts.commands += lupdate $$PWD/ui -ts $$TS_FILE
ts.CONFIG += no_check_exist no_link
@@ -30,29 +30,29 @@ QMAKE_EXTRA_TARGETS += ts engineering_english
PRE_TARGETDEPS += ts engineering_english
OTHER_FILES += \
- $$PWD/providers/mastodon.provider \
- $$PWD/services/mastodon-microblog.service \
- $$PWD/services/mastodon-notifications.service \
- $$PWD/services/mastodon-sharing.service \
- $$PWD/ui/MastodonSettingsDisplay.qml \
- $$PWD/ui/mastodon.qml \
- $$PWD/ui/mastodon-settings.qml \
- $$PWD/ui/mastodon-update.qml
-
-provider.files += $$PWD/providers/mastodon.provider
+ $$PWD/providers/fediverse.provider \
+ $$PWD/services/fediverse-microblog.service \
+ $$PWD/services/fediverse-notifications.service \
+ $$PWD/services/fediverse-sharing.service \
+ $$PWD/ui/FediverseSettingsDisplay.qml \
+ $$PWD/ui/fediverse.qml \
+ $$PWD/ui/fediverse-settings.qml \
+ $$PWD/ui/fediverse-update.qml
+
+provider.files += $$PWD/providers/fediverse.provider
provider.path = /usr/share/accounts/providers/
services.files += \
- $$PWD/services/mastodon-microblog.service \
- $$PWD/services/mastodon-notifications.service \
- $$PWD/services/mastodon-sharing.service
+ $$PWD/services/fediverse-microblog.service \
+ $$PWD/services/fediverse-notifications.service \
+ $$PWD/services/fediverse-sharing.service
services.path = /usr/share/accounts/services/
ui.files += \
- $$PWD/ui/MastodonSettingsDisplay.qml \
- $$PWD/ui/mastodon.qml \
- $$PWD/ui/mastodon-settings.qml \
- $$PWD/ui/mastodon-update.qml
+ $$PWD/ui/FediverseSettingsDisplay.qml \
+ $$PWD/ui/fediverse.qml \
+ $$PWD/ui/fediverse-settings.qml \
+ $$PWD/ui/fediverse-update.qml
ui.path = /usr/share/accounts/ui/
INSTALLS += provider services ui ts_install engineering_english_install
diff --git a/settings/accounts/providers/mastodon.provider b/settings/accounts/providers/fediverse.provider
index 422c231..bb6e329 100644
--- a/settings/accounts/providers/mastodon.provider
+++ b/settings/accounts/providers/fediverse.provider
@@ -2,11 +2,11 @@
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
<!DOCTYPE provider>
-<provider version="1.0" id="mastodon">
- <translations>/usr/share/translations/settings-accounts-mastodon</translations>
- <name>Mastodon</name>
- <description>Mastodon social network</description>
- <icon>image://theme/icon-l-mastodon</icon>
+<provider version="1.0" id="fediverse">
+ <translations>/usr/share/translations/settings-accounts-fediverse</translations>
+ <name>Fediverse</name>
+ <description>Fediverse social network</description>
+ <icon>image://theme/icon-l-fediverse</icon>
<template>
<group name="auth">
@@ -25,11 +25,11 @@
</group>
</group>
<group name="api">
- <setting name="Host">https://mastodon.social</setting>
+ <setting name="Host">mastodon.social</setting>
</group>
</template>
<tags>
- <tag>user-group:account-mastodon</tag>
+ <tag>user-group:account-fediverse</tag>
</tags>
</provider>
diff --git a/settings/accounts/services/mastodon-microblog.service b/settings/accounts/services/fediverse-microblog.service
index 527f70f..9070ec1 100644
--- a/settings/accounts/services/mastodon-microblog.service
+++ b/settings/accounts/services/fediverse-microblog.service
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<service id="mastodon-microblog">
+<service id="fediverse-microblog">
<type>microblogging</type>
- <translations>/usr/share/translations/settings-accounts-mastodon</translations>
+ <translations>/usr/share/translations/settings-accounts-fediverse</translations>
<name>Posts</name>
- <icon>image://theme/icon-l-mastodon</icon>
- <provider>mastodon</provider>
+ <icon>image://theme/icon-l-fediverse</icon>
+ <provider>fediverse</provider>
<template>
- <setting name="sync_profile_templates" type="as">["mastodon.Posts"]</setting>
+ <setting name="sync_profile_templates" type="as">["fediverse.Posts"]</setting>
<group name="auth">
<setting name="method">oauth2</setting>
<setting name="mechanism">web_server</setting>
@@ -26,7 +26,7 @@
</group>
</group>
<group name="api">
- <setting name="Host">https://mastodon.social</setting>
+ <setting name="Host">mastodon.social</setting>
</group>
</template>
</service>
diff --git a/settings/accounts/services/mastodon-notifications.service b/settings/accounts/services/fediverse-notifications.service
index f5471c9..ea1b59b 100644
--- a/settings/accounts/services/mastodon-notifications.service
+++ b/settings/accounts/services/fediverse-notifications.service
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<service id="mastodon-notifications">
+<service id="fediverse-notifications">
<type>microblogging</type>
- <translations>/usr/share/translations/settings-accounts-mastodon</translations>
+ <translations>/usr/share/translations/settings-accounts-fediverse</translations>
<name>Notifications</name>
- <icon>image://theme/icon-l-mastodon</icon>
- <provider>mastodon</provider>
+ <icon>image://theme/icon-l-fediverse</icon>
+ <provider>fediverse</provider>
<template>
- <setting name="sync_profile_templates" type="as">["mastodon.Notifications"]</setting>
+ <setting name="sync_profile_templates" type="as">["fediverse.Notifications"]</setting>
<group name="auth">
<setting name="method">oauth2</setting>
<setting name="mechanism">web_server</setting>
@@ -26,7 +26,7 @@
</group>
</group>
<group name="api">
- <setting name="Host">https://mastodon.social</setting>
+ <setting name="Host">mastodon.social</setting>
</group>
</template>
</service>
diff --git a/settings/accounts/services/mastodon-sharing.service b/settings/accounts/services/fediverse-sharing.service
index fdf342a..f66f11b 100644
--- a/settings/accounts/services/mastodon-sharing.service
+++ b/settings/accounts/services/fediverse-sharing.service
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -->
<!-- SPDX-License-Identifier: BSD-3-Clause -->
-<service id="mastodon-sharing">
+<service id="fediverse-sharing">
<type>sharing</type>
- <translations>/usr/share/translations/settings-accounts-mastodon</translations>
+ <translations>/usr/share/translations/settings-accounts-fediverse</translations>
<name>Sharing</name>
- <icon>image://theme/icon-l-mastodon</icon>
- <provider>mastodon</provider>
+ <icon>image://theme/icon-l-fediverse</icon>
+ <provider>fediverse</provider>
<template>
<group name="auth">
@@ -25,7 +25,7 @@
</group>
</group>
<group name="api">
- <setting name="Host">https://mastodon.social</setting>
+ <setting name="Host">mastodon.social</setting>
</group>
</template>
</service>
diff --git a/settings/accounts/ui/MastodonSettingsDisplay.qml b/settings/accounts/ui/FediverseSettingsDisplay.qml
index 13ac06c..7494460 100644
--- a/settings/accounts/ui/MastodonSettingsDisplay.qml
+++ b/settings/accounts/ui/FediverseSettingsDisplay.qml
@@ -8,7 +8,7 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import Sailfish.Accounts 1.0
import com.jolla.settings.accounts 1.0
-import com.jolla.settings.accounts.mastodon 1.0
+import com.jolla.settings.accounts.fediverse 1.0
import org.nemomobile.configuration 1.0
StandardAccountSettingsDisplay {
@@ -16,6 +16,10 @@ StandardAccountSettingsDisplay {
settingsModified: true
property bool postsServiceEnabled: false
+ property string instanceTitle: {
+ var value = root.account.configurationValues("")["instance/Title"]
+ return value ? value.toString().trim() : ""
+ }
function refreshDescriptionEditor() {
var description = root.account.configurationValues("")["description"]
@@ -38,11 +42,14 @@ StandardAccountSettingsDisplay {
}
function _providerDisplayName() {
+ if (instanceTitle.length > 0) {
+ return instanceTitle
+ }
+
var providerDisplayName = root.accountProvider && root.accountProvider.displayName
? root.accountProvider.displayName.toString().trim()
: ""
- //% "Mastodon"
- return providerDisplayName.length > 0 ? providerDisplayName : qsTrId("settings-accounts-mastodon-la-provider_name")
+ return providerDisplayName.length > 0 ? providerDisplayName : qsTrId("settings-accounts-fediverse-la-provider_name")
}
onAboutToSaveAccount: {
@@ -70,7 +77,7 @@ StandardAccountSettingsDisplay {
root.account.setConfigurationValue("", "default_credentials_username", editedDescription)
}
- // Keep account list title fixed to provider name.
+ // Keep account list title fixed to the discovered instance title.
root.account.displayName = providerDisplayName
if (eventsSyncSwitch.checked !== root.account.configurationValues("")["FeedViewAutoSync"]) {
@@ -111,23 +118,23 @@ StandardAccountSettingsDisplay {
id: syncServicesRepeater
TextSwitch {
checked: model.enabled
- text: model.serviceName === "mastodon-microblog"
+ text: model.serviceName === "fediverse-microblog"
//% "Posts"
- ? qsTrId("settings-accounts-mastodon-la-service_posts")
- : (model.serviceName === "mastodon-notifications"
+ ? qsTrId("settings-accounts-fediverse-la-service_posts")
+ : (model.serviceName === "fediverse-notifications"
//% "Notifications"
- ? qsTrId("settings-accounts-mastodon-la-service_notifications")
+ ? qsTrId("settings-accounts-fediverse-la-service_notifications")
: model.displayName)
- description: model.serviceName === "mastodon-microblog"
- //% "Show Mastodon posts in the Events view."
- ? qsTrId("settings-accounts-mastodon-la-service_posts_description")
- : (model.serviceName === "mastodon-notifications"
- //% "Show Mastodon notifications."
- ? qsTrId("settings-accounts-mastodon-la-service_notifications_description")
+ description: model.serviceName === "fediverse-microblog"
+ //% "Show Fediverse posts in the Events view."
+ ? qsTrId("settings-accounts-fediverse-la-service_posts_description")
+ : (model.serviceName === "fediverse-notifications"
+ //% "Show Fediverse notifications."
+ ? qsTrId("settings-accounts-fediverse-la-service_notifications_description")
: "")
visible: text.length > 0
onCheckedChanged: {
- if (model.serviceName === "mastodon-microblog") {
+ if (model.serviceName === "fediverse-microblog") {
root.postsServiceEnabled = checked
}
if (checked) {
@@ -142,10 +149,10 @@ StandardAccountSettingsDisplay {
TextSwitch {
id: eventsSyncSwitch
- //% "Sync Mastodon feed automatically"
- text: qsTrId("settings-accounts-mastodon-la-auto_sync_feed")
- //% "Fetch new posts periodically when browsing Events Mastodon feed."
- description: qsTrId("settings-accounts-mastodon-la-auto_sync_feed_description")
+ //% "Sync Fediverse feed automatically"
+ text: qsTrId("settings-accounts-fediverse-la-auto_sync_feed")
+ //% "Fetch new posts periodically when browsing Events Fediverse feed."
+ description: qsTrId("settings-accounts-fediverse-la-auto_sync_feed_description")
enabled: root.postsServiceEnabled
onCheckedChanged: {
diff --git a/settings/accounts/ui/mastodon-settings.qml b/settings/accounts/ui/fediverse-settings.qml
index 0538e44..25e0d99 100644
--- a/settings/accounts/ui/mastodon-settings.qml
+++ b/settings/accounts/ui/fediverse-settings.qml
@@ -13,11 +13,12 @@ AccountSettingsAgent {
id: root
property string accountSubtitle: {
- var description = account.configurationValues("")["description"]
- var detail = description ? description.toString().trim() : ""
+ var instanceDescription = account.configurationValues("")["instance/Description"]
+ var detail = instanceDescription ? instanceDescription.toString().trim() : ""
if (detail.length > 0) {
return detail
}
+
var apiHost = account.configurationValues("")["api/Host"]
var host = apiHost ? apiHost.toString().trim() : ""
host = host.replace(/^https?:\/\//i, "")
@@ -28,6 +29,13 @@ AccountSettingsAgent {
if (host.length > 0) {
return host
}
+
+ var description = account.configurationValues("")["description"]
+ var handle = description ? description.toString().trim() : ""
+ if (handle.length > 0) {
+ return handle
+ }
+
var displayName = account.displayName ? account.displayName.toString().trim() : ""
if (displayName.length > 0) {
return displayName
@@ -89,7 +97,7 @@ AccountSettingsAgent {
description: root.accountSubtitle
}
- MastodonSettingsDisplay {
+ FediverseSettingsDisplay {
id: settingsDisplay
anchors.top: header.bottom
accountManager: root.accountManager
diff --git a/settings/accounts/ui/mastodon-update.qml b/settings/accounts/ui/fediverse-update.qml
index 2485a83..fe75089 100644
--- a/settings/accounts/ui/mastodon-update.qml
+++ b/settings/accounts/ui/fediverse-update.qml
@@ -8,7 +8,7 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import Sailfish.Accounts 1.0
import com.jolla.settings.accounts 1.0
-import com.jolla.settings.accounts.mastodon 1.0
+import com.jolla.settings.accounts.fediverse 1.0
AccountCredentialsAgent {
id: root
@@ -16,11 +16,12 @@ AccountCredentialsAgent {
property bool _started
readonly property string callbackUri: "http://ipv4.jolla.com/online/status.html"
+ readonly property string defaultServerHost: "mastodon.social"
function normalizeApiHost(rawHost) {
var host = rawHost ? rawHost.trim() : ""
if (host.length === 0) {
- host = "https://mastodon.social"
+ host = defaultServerHost
}
host = host.replace(/^https?:\/\//i, "")
@@ -31,7 +32,7 @@ AccountCredentialsAgent {
host = host.replace(/\/+$/, "")
if (host.length === 0) {
- host = "mastodon.social"
+ host = defaultServerHost
}
return "https://" + host.toLowerCase()
}
@@ -68,7 +69,7 @@ AccountCredentialsAgent {
return ""
}
- function _formatMastodonAccountId(accountName, apiHost) {
+ function _formatFediverseAccountId(accountName, apiHost) {
var value = accountName ? accountName.toString().trim() : ""
if (value.length === 0) {
return ""
@@ -99,7 +100,7 @@ AccountCredentialsAgent {
return token ? token.toString().trim() : ""
}
- function _isMastodonAccountId(value) {
+ function _isFediverseAccountId(value) {
var text = value ? value.toString().trim() : ""
return /^@[^@]+@[^@]+$/.test(text)
}
@@ -112,7 +113,7 @@ AccountCredentialsAgent {
function _saveDescription(description) {
if (description.length > 0) {
account.setConfigurationValue("", "description", description)
- if (_isMastodonAccountId(description)) {
+ if (_isFediverseAccountId(description)) {
account.setConfigurationValue("", "default_credentials_username", description)
}
}
@@ -121,9 +122,9 @@ AccountCredentialsAgent {
}
function _updateDescription(responseData) {
- var config = account.configurationValues("mastodon-microblog")
+ var config = account.configurationValues("fediverse-microblog")
var apiHost = normalizeApiHost(_valueFromServiceConfig(config, "api/Host"))
- var description = _formatMastodonAccountId(_extractAccountName(responseData), apiHost)
+ var description = _formatFediverseAccountId(_extractAccountName(responseData), apiHost)
if (description.length > 0) {
_saveDescription(description)
return
@@ -145,7 +146,7 @@ AccountCredentialsAgent {
if (xhr.status >= 200 && xhr.status < 300) {
try {
var response = JSON.parse(xhr.responseText)
- fetchedDescription = _formatMastodonAccountId(_extractAccountName(response), apiHost)
+ fetchedDescription = _formatFediverseAccountId(_extractAccountName(response), apiHost)
} catch (err) {
}
}
@@ -167,7 +168,7 @@ AccountCredentialsAgent {
return
}
- var config = account.configurationValues("mastodon-microblog")
+ var config = account.configurationValues("fediverse-microblog")
var apiHost = normalizeApiHost(_valueFromServiceConfig(config, "api/Host"))
var oauthHost = _valueFromServiceConfig(config, "auth/oauth2/web_server/Host")
if (oauthHost.length === 0) {
@@ -177,8 +178,8 @@ AccountCredentialsAgent {
var clientId = _valueFromServiceConfig(config, "auth/oauth2/web_server/ClientId")
var clientSecret = _valueFromServiceConfig(config, "auth/oauth2/web_server/ClientSecret")
if (clientId.length === 0 || clientSecret.length === 0) {
- //% "Missing Mastodon OAuth client credentials"
- credentialsUpdateError(qsTrId("settings-accounts-mastodon-la-missing_client_credentials"))
+ //% "Missing Fediverse OAuth client credentials"
+ credentialsUpdateError(qsTrId("settings-accounts-fediverse-la-missing_client_credentials"))
return
}
@@ -194,7 +195,7 @@ AccountCredentialsAgent {
"Scope": ["read", "write"],
"RedirectUri": callbackUri
}
- initialPage.prepareAccountCredentialsUpdate(account, root.accountProvider, "mastodon-microblog", sessionData)
+ initialPage.prepareAccountCredentialsUpdate(account, root.accountProvider, "fediverse-microblog", sessionData)
}
Account {
diff --git a/settings/accounts/ui/mastodon.qml b/settings/accounts/ui/fediverse.qml
index 129fda5..3f5968a 100644
--- a/settings/accounts/ui/mastodon.qml
+++ b/settings/accounts/ui/fediverse.qml
@@ -8,7 +8,7 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import Sailfish.Accounts 1.0
import com.jolla.settings.accounts 1.0
-import com.jolla.settings.accounts.mastodon 1.0
+import com.jolla.settings.accounts.fediverse 1.0
AccountCreationAgent {
id: root
@@ -18,10 +18,13 @@ AccountCreationAgent {
property QtObject _accountSetup
property string _pendingApiHost
+ property var _pendingInstanceContext: ({})
property bool _registering
readonly property string callbackUri: "http://ipv4.jolla.com/online/status.html"
- readonly property string defaultApiHost: "https://mastodon.social"
+ readonly property string defaultServerHost: "mastodon.social"
+ readonly property string defaultApiHost: normalizeApiHost(defaultServerHost)
+ readonly property string genericIconPath: "image://theme/icon-l-fediverse"
function normalizeApiHost(rawHost) {
var host = rawHost ? rawHost.trim() : ""
@@ -46,6 +49,27 @@ AccountCreationAgent {
return apiHost.replace(/^https?:\/\//i, "")
}
+ function _trimmedString(value) {
+ return value ? value.toString().trim() : ""
+ }
+
+ function _normalizeResourceUrl(rawUrl, apiHost) {
+ var value = _trimmedString(rawUrl)
+ if (value.length === 0) {
+ return ""
+ }
+ if (/^https?:\/\//i.test(value)) {
+ return value
+ }
+ if (value.indexOf("//") === 0) {
+ return "https:" + value
+ }
+ if (value.charAt(0) === "/") {
+ return apiHost + value
+ }
+ return apiHost + "/" + value.replace(/^\/+/, "")
+ }
+
function _displayName(apiHost) {
return oauthHost(apiHost)
}
@@ -58,6 +82,78 @@ AccountCreationAgent {
return _displayName(defaultApiHost)
}
+ function _instanceContext(apiHost) {
+ var normalizedApiHost = normalizeApiHost(apiHost)
+ var title = _fallbackDisplayName(normalizedApiHost)
+ return {
+ "apiHost": normalizedApiHost,
+ "oauthHost": oauthHost(normalizedApiHost),
+ "instanceTitle": title.length > 0 ? title : qsTrId("settings-accounts-fediverse-la-provider_name"),
+ "instanceDescription": "",
+ "instanceIconUrl": "",
+ "instanceIconPath": instanceIconCache.cachedIconPath(normalizedApiHost)
+ }
+ }
+
+ function _extractInstanceTitle(responseData, apiHost) {
+ var candidates = [
+ responseData ? responseData.title : "",
+ responseData ? responseData.name : "",
+ responseData ? responseData.uri : ""
+ ]
+ for (var i = 0; i < candidates.length; ++i) {
+ var value = _trimmedString(candidates[i])
+ if (value.length > 0) {
+ return value
+ }
+ }
+ return _fallbackDisplayName(apiHost)
+ }
+
+ function _extractInstanceDescription(responseData) {
+ var candidates = [
+ responseData ? responseData.short_description : "",
+ responseData ? responseData.description : "",
+ responseData ? responseData.shortDescription : ""
+ ]
+ for (var i = 0; i < candidates.length; ++i) {
+ var value = _trimmedString(candidates[i])
+ if (value.length > 0) {
+ return value
+ }
+ }
+ return ""
+ }
+
+ function _extractInstanceIconUrl(responseData, apiHost) {
+ if (!responseData) {
+ return ""
+ }
+
+ if (responseData.thumbnail) {
+ if (typeof responseData.thumbnail === "string") {
+ return _normalizeResourceUrl(responseData.thumbnail, apiHost)
+ }
+ if (responseData.thumbnail.url) {
+ return _normalizeResourceUrl(responseData.thumbnail.url, apiHost)
+ }
+ if (responseData.thumbnail.static_url) {
+ return _normalizeResourceUrl(responseData.thumbnail.static_url, apiHost)
+ }
+ }
+
+ if (responseData.icon) {
+ if (typeof responseData.icon === "string") {
+ return _normalizeResourceUrl(responseData.icon, apiHost)
+ }
+ if (responseData.icon.url) {
+ return _normalizeResourceUrl(responseData.icon.url, apiHost)
+ }
+ }
+
+ return ""
+ }
+
function _showRegistrationError(message, busyPage) {
_registering = false
accountCreationError(message)
@@ -79,12 +175,16 @@ AccountCreationAgent {
pageStack.replace(_oauthPage)
}
- function _registerClientApplication(apiHost, busyPage) {
+ function _registerClientApplication(context, busyPage) {
if (_registering) {
return
}
_registering = true
+ if (context.instanceIconUrl.length > 0 && context.instanceIconPath.length === 0) {
+ instanceIconCache.cacheIcon(context.apiHost, context.instanceIconUrl)
+ }
+
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState !== XMLHttpRequest.DONE) {
@@ -92,8 +192,7 @@ AccountCreationAgent {
}
if (xhr.status < 200 || xhr.status >= 300) {
- //% "Failed to register Mastodon app for %1"
- _showRegistrationError(qsTrId("settings-accounts-mastodon-la-register_app_failed").arg(apiHost), busyPage)
+ _showRegistrationError(qsTrId("settings-accounts-fediverse-la-register_app_failed").arg(context.apiHost), busyPage)
return
}
@@ -101,37 +200,80 @@ AccountCreationAgent {
try {
response = JSON.parse(xhr.responseText)
} catch (err) {
- //% "Invalid Mastodon app registration response"
- _showRegistrationError(qsTrId("settings-accounts-mastodon-la-invalid_app_registration_response"), busyPage)
+ _showRegistrationError(qsTrId("settings-accounts-fediverse-la-invalid_app_registration_response"), busyPage)
return
}
if (!response.client_id || !response.client_secret) {
- //% "Mastodon app registration did not return credentials"
- _showRegistrationError(qsTrId("settings-accounts-mastodon-la-app_registration_missing_credentials"), busyPage)
+ _showRegistrationError(qsTrId("settings-accounts-fediverse-la-app_registration_missing_credentials"), busyPage)
return
}
- _showOAuthPage({
- "apiHost": apiHost,
- "oauthHost": oauthHost(apiHost),
- "clientId": response.client_id,
- "clientSecret": response.client_secret
- })
+ context.clientId = response.client_id
+ context.clientSecret = response.client_secret
+ _showOAuthPage(context)
}
var postData = []
- //% "Mastodon in SailfishOS"
- postData.push("client_name=" + encodeURIComponent(qsTrId("settings-accounts-mastodon-la-client_name")))
+ postData.push("client_name=" + encodeURIComponent(qsTrId("settings-accounts-fediverse-la-client_name")))
postData.push("redirect_uris=" + encodeURIComponent(callbackUri))
postData.push("scopes=" + encodeURIComponent("read write"))
postData.push("website=" + encodeURIComponent("https://sailfishos.org"))
- xhr.open("POST", apiHost + "/api/v1/apps")
+ xhr.open("POST", context.apiHost + "/api/v1/apps")
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
xhr.send(postData.join("&"))
}
+ function _discoverInstanceContext(apiHost, busyPage) {
+ var context = _instanceContext(apiHost)
+ _pendingInstanceContext = context
+
+ function continueWithContext() {
+ _pendingInstanceContext = context
+ _registerClientApplication(context, busyPage)
+ }
+
+ function loadEndpoint(paths, index) {
+ if (index >= paths.length) {
+ continueWithContext()
+ return
+ }
+
+ var xhr = new XMLHttpRequest()
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState !== XMLHttpRequest.DONE) {
+ return
+ }
+
+ if (xhr.status >= 200 && xhr.status < 300) {
+ try {
+ var response = JSON.parse(xhr.responseText)
+ context.instanceTitle = _extractInstanceTitle(response, context.apiHost)
+ context.instanceDescription = _extractInstanceDescription(response)
+ context.instanceIconUrl = _extractInstanceIconUrl(response, context.apiHost)
+ if (context.instanceIconUrl.length > 0) {
+ var cachedPath = instanceIconCache.cachedIconPath(context.apiHost)
+ if (cachedPath.length > 0) {
+ context.instanceIconPath = cachedPath
+ }
+ }
+ } catch (err) {
+ }
+ continueWithContext()
+ return
+ }
+
+ loadEndpoint(paths, index + 1)
+ }
+
+ xhr.open("GET", context.apiHost + paths[index])
+ xhr.send()
+ }
+
+ loadEndpoint(["/api/v2/instance", "/api/v1/instance"], 0)
+ }
+
function _extractAccountName(responseData) {
if (!responseData) {
return ""
@@ -160,7 +302,7 @@ AccountCreationAgent {
return ""
}
- function _formatMastodonAccountId(accountName, apiHost) {
+ function _formatFediverseAccountId(accountName, apiHost) {
var value = accountName ? accountName.toString().trim() : ""
if (value.length === 0) {
return ""
@@ -179,7 +321,7 @@ AccountCreationAgent {
return "@" + value + "@" + host
}
- function _isMastodonAccountId(value) {
+ function _isFediverseAccountId(value) {
var text = value ? value.toString().trim() : ""
return /^@[^@]+@[^@]+$/.test(text)
}
@@ -204,7 +346,11 @@ AccountCreationAgent {
"clientId": context.clientId,
"clientSecret": context.clientSecret,
"accessToken": _extractAccessToken(responseData),
- "accountDescription": _formatMastodonAccountId(_extractAccountName(responseData), context.apiHost)
+ "accountDescription": _formatFediverseAccountId(_extractAccountName(responseData), context.apiHost),
+ "instanceTitle": context.instanceTitle,
+ "instanceDescription": context.instanceDescription,
+ "instanceIconUrl": context.instanceIconUrl,
+ "instanceIconPath": context.instanceIconPath
}
_accountSetup = accountSetupComponent.createObject(root, props)
_accountSetup.done.connect(function() {
@@ -212,8 +358,7 @@ AccountCreationAgent {
_goToSettings(accountId)
})
_accountSetup.error.connect(function() {
- //% "Failed to finish Mastodon account setup"
- accountCreationError(qsTrId("settings-accounts-mastodon-la-account_setup_failed"))
+ accountCreationError(qsTrId("settings-accounts-fediverse-la-account_setup_failed"))
})
}
@@ -225,6 +370,20 @@ AccountCreationAgent {
pageStack.replace(_settingsDialog)
}
+ FediverseInstanceIconCache {
+ id: instanceIconCache
+
+ onIconReady: {
+ var normalizedHost = root.normalizeApiHost(apiHost)
+ if (root._pendingInstanceContext.apiHost === normalizedHost) {
+ root._pendingInstanceContext.instanceIconPath = iconPath
+ }
+ if (root._accountSetup && root._accountSetup.apiHost === normalizedHost) {
+ root._accountSetup.updateInstanceIcon(iconPath)
+ }
+ }
+ }
+
initialPage: Dialog {
id: setupDialog
@@ -240,7 +399,6 @@ AccountCreationAgent {
DialogHeader {
id: header
- //% "Sign in"
acceptText: qsTrId("settings-accounts-common-bt-sign_in")
}
@@ -259,19 +417,17 @@ AccountCreationAgent {
id: promptIcon
width: Theme.iconSizeMedium
height: Theme.iconSizeMedium
- source: "image://theme/icon-l-mastodon"
+ source: root.genericIconPath
fillMode: Image.PreserveAspectFit
sourceSize.width: width
sourceSize.height: height
}
- //: Prompt shown in account setup before OAuth sign-in.
Label {
width: parent.width - promptIcon.width - parent.spacing
wrapMode: Text.Wrap
color: Theme.highlightColor
- //% "Enter your Mastodon server, then sign in."
- text: qsTrId("settings-accounts-mastodon-la-enter_server_then_sign_in")
+ text: qsTrId("settings-accounts-fediverse-la-enter_server_then_sign_in")
}
}
@@ -279,9 +435,8 @@ AccountCreationAgent {
id: instanceField
x: Theme.horizontalPageMargin
width: parent.width - x * 2
- //% "Server"
- label: qsTrId("settings-accounts-mastodon-la-server")
- placeholderText: "mastodon.social"
+ label: qsTrId("settings-accounts-fediverse-la-server")
+ placeholderText: root.defaultServerHost
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhUrlCharactersOnly
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: {
@@ -296,11 +451,10 @@ AccountCreationAgent {
Component {
id: busyComponent
AccountBusyPage {
- //% "Preparing Mastodon sign-in..."
- busyDescription: qsTrId("settings-accounts-mastodon-la-preparing_sign_in")
+ busyDescription: qsTrId("settings-accounts-fediverse-la-preparing_sign_in")
onStatusChanged: {
if (status === PageStatus.Active && root._pendingApiHost.length > 0) {
- root._registerClientApplication(root._pendingApiHost, this)
+ root._discoverInstanceContext(root._pendingApiHost, this)
}
}
}
@@ -322,7 +476,7 @@ AccountCreationAgent {
"Scope": ["read", "write"],
"RedirectUri": root.callbackUri
}
- prepareAccountCreation(root.accountProvider, "mastodon-microblog", sessionData)
+ prepareAccountCreation(root.accountProvider, "fediverse-microblog", sessionData)
}
onAccountCreated: {
@@ -347,6 +501,10 @@ AccountCreationAgent {
property string clientSecret
property string accessToken
property string accountDescription
+ property string instanceTitle
+ property string instanceDescription
+ property string instanceIconUrl
+ property string instanceIconPath
property bool hasConfigured
signal done()
@@ -368,31 +526,57 @@ AccountCreationAgent {
}
}
+ function _serviceNames() {
+ return ["fediverse-microblog", "fediverse-notifications", "fediverse-sharing"]
+ }
+
+ function _effectiveInstanceTitle() {
+ var title = root._trimmedString(instanceTitle)
+ return title.length > 0 ? title : qsTrId("settings-accounts-fediverse-la-provider_name")
+ }
+
+ function _effectiveIconPath() {
+ return root._trimmedString(instanceIconPath).length > 0 ? instanceIconPath : root.genericIconPath
+ }
+
+ function _applyIconPath(iconPath) {
+ instanceIconPath = iconPath
+ newAccount.setConfigurationValue("", "iconPath", _effectiveIconPath())
+ var services = _serviceNames()
+ for (var i = 0; i < services.length; ++i) {
+ newAccount.setConfigurationValue(services[i], "iconPath", _effectiveIconPath())
+ }
+ if (hasConfigured) {
+ newAccount.sync()
+ }
+ }
+
+ function updateInstanceIcon(iconPath) {
+ if (root._trimmedString(iconPath).length === 0) {
+ return
+ }
+ _applyIconPath(iconPath)
+ }
+
function configure() {
hasConfigured = true
- var services = ["mastodon-microblog", "mastodon-notifications", "mastodon-sharing"]
- var providerDisplayName = root.accountProvider && root.accountProvider.displayName
- ? root.accountProvider.displayName.toString().trim()
- : ""
- if (providerDisplayName.length === 0) {
- //% "Mastodon"
- providerDisplayName = qsTrId("settings-accounts-mastodon-la-provider_name")
- }
+ var services = _serviceNames()
+ var providerDisplayName = _effectiveInstanceTitle()
newAccount.displayName = providerDisplayName
newAccount.setConfigurationValue("", "api/Host", apiHost)
newAccount.setConfigurationValue("", "FeedViewAutoSync", true)
+ newAccount.setConfigurationValue("", "instance/Title", providerDisplayName)
+ newAccount.setConfigurationValue("", "instance/Description", root._trimmedString(instanceDescription))
+ newAccount.setConfigurationValue("", "instance/IconUrl", root._trimmedString(instanceIconUrl))
+ _applyIconPath(_effectiveIconPath())
+
if (accountDescription.length > 0) {
newAccount.setConfigurationValue("", "description", accountDescription)
- if (root._isMastodonAccountId(accountDescription)) {
+ if (root._isFediverseAccountId(accountDescription)) {
newAccount.setConfigurationValue("", "default_credentials_username", accountDescription)
}
- } else {
- var hostDisplayName = root._fallbackDisplayName(apiHost)
- if (hostDisplayName.length > 0) {
- newAccount.setConfigurationValue("", "description", hostDisplayName)
- }
}
for (var i = 0; i < services.length; ++i) {
@@ -412,6 +596,10 @@ AccountCreationAgent {
newAccount.enableWithService(services[j])
}
+ if (instanceIconUrl.length > 0 && instanceIconPath.length === 0) {
+ instanceIconCache.cacheIcon(apiHost, instanceIconUrl)
+ }
+
if (accountDescription.length > 0 || accessToken.length === 0) {
newAccount.sync()
return
@@ -426,11 +614,11 @@ AccountCreationAgent {
if (xhr.status >= 200 && xhr.status < 300) {
try {
var response = JSON.parse(xhr.responseText)
- var fetchedDescription = root._formatMastodonAccountId(root._extractAccountName(response), apiHost)
+ var fetchedDescription = root._formatFediverseAccountId(root._extractAccountName(response), apiHost)
if (fetchedDescription.length > 0) {
accountDescription = fetchedDescription
newAccount.setConfigurationValue("", "description", fetchedDescription)
- if (root._isMastodonAccountId(fetchedDescription)) {
+ if (root._isFediverseAccountId(fetchedDescription)) {
newAccount.setConfigurationValue("", "default_credentials_username", fetchedDescription)
}
}
@@ -472,7 +660,7 @@ AccountCreationAgent {
id: header
}
- MastodonSettingsDisplay {
+ FediverseSettingsDisplay {
id: settingsDisplay
anchors.top: header.bottom
accountManager: root.accountManager
@@ -488,5 +676,4 @@ AccountCreationAgent {
}
}
}
-
}
diff --git a/transferengine-plugins/mastodonshareplugin/MastodonSharePost.qml b/transferengine-plugins/fediverseshareplugin/FediverseSharePost.qml
index d859d96..d859d96 100644
--- a/transferengine-plugins/mastodonshareplugin/MastodonSharePost.qml
+++ b/transferengine-plugins/fediverseshareplugin/FediverseSharePost.qml
diff --git a/transferengine-plugins/fediverseshareplugin/fediverseplugininfo.cpp b/transferengine-plugins/fediverseshareplugin/fediverseplugininfo.cpp
new file mode 100644
index 0000000..4e04be1
--- /dev/null
+++ b/transferengine-plugins/fediverseshareplugin/fediverseplugininfo.cpp
@@ -0,0 +1,62 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fediverseplugininfo.h"
+#include "fediverseshareservicestatus.h"
+
+FediversePluginInfo::FediversePluginInfo()
+ : SharingPluginInfo()
+ , m_fediverseShareServiceStatus(new FediverseShareServiceStatus(this))
+{
+ m_capabilities << QLatin1String("image/jpeg")
+ << QLatin1String("image/png")
+ << QLatin1String("video/mp4")
+ << QLatin1String("text/x-url")
+ << QLatin1String("text/plain");
+
+ connect(m_fediverseShareServiceStatus, &FediverseShareServiceStatus::serviceReady,
+ this, &FediversePluginInfo::serviceReady);
+ connect(m_fediverseShareServiceStatus, &FediverseShareServiceStatus::serviceError,
+ this, &FediversePluginInfo::infoError);
+}
+
+FediversePluginInfo::~FediversePluginInfo()
+{
+}
+
+QList<SharingMethodInfo> FediversePluginInfo::info() const
+{
+ return m_info;
+}
+
+void FediversePluginInfo::query()
+{
+ m_fediverseShareServiceStatus->queryStatus(FediverseShareServiceStatus::PassiveMode);
+}
+
+void FediversePluginInfo::serviceReady()
+{
+ m_info.clear();
+
+ for (int i = 0; i < m_fediverseShareServiceStatus->count(); ++i) {
+ SharingMethodInfo info;
+
+ const FediverseShareServiceStatus::AccountDetails details = m_fediverseShareServiceStatus->details(i);
+ info.setDisplayName(details.providerName);
+ info.setSubtitle(details.displayName);
+ info.setAccountId(details.accountId);
+
+ info.setMethodId(QLatin1String("Fediverse"));
+ info.setMethodIcon(details.iconPath.isEmpty()
+ ? QLatin1String("image://theme/icon-l-fediverse")
+ : details.iconPath);
+ info.setShareUIPath(QLatin1String("/usr/share/nemo-transferengine/plugins/sharing/FediverseSharePost.qml"));
+ info.setCapabilities(m_capabilities);
+ m_info << info;
+ }
+
+ emit infoReady();
+}
diff --git a/transferengine-plugins/mastodonshareplugin/mastodonplugininfo.h b/transferengine-plugins/fediverseshareplugin/fediverseplugininfo.h
index 80fe552..fdd8fc6 100644
--- a/transferengine-plugins/mastodonshareplugin/mastodonplugininfo.h
+++ b/transferengine-plugins/fediverseshareplugin/fediverseplugininfo.h
@@ -4,21 +4,21 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef MASTODONPLUGININFO_H
-#define MASTODONPLUGININFO_H
+#ifndef FEDIVERSEPLUGININFO_H
+#define FEDIVERSEPLUGININFO_H
#include <sharingplugininfo.h>
#include <QStringList>
-class MastodonShareServiceStatus;
+class FediverseShareServiceStatus;
-class MastodonPluginInfo : public SharingPluginInfo
+class FediversePluginInfo : public SharingPluginInfo
{
Q_OBJECT
public:
- MastodonPluginInfo();
- ~MastodonPluginInfo();
+ FediversePluginInfo();
+ ~FediversePluginInfo();
QList<SharingMethodInfo> info() const;
void query();
@@ -27,9 +27,9 @@ private Q_SLOTS:
void serviceReady();
private:
- MastodonShareServiceStatus *m_mastodonShareServiceStatus;
+ FediverseShareServiceStatus *m_fediverseShareServiceStatus;
QList<SharingMethodInfo> m_info;
QStringList m_capabilities;
};
-#endif // MASTODONPLUGININFO_H
+#endif // FEDIVERSEPLUGININFO_H
diff --git a/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.cpp b/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.cpp
new file mode 100644
index 0000000..18c9c7c
--- /dev/null
+++ b/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.cpp
@@ -0,0 +1,29 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fediverseshareplugin.h"
+#include "fediverseplugininfo.h"
+
+#include <QtPlugin>
+
+FediverseSharePlugin::FediverseSharePlugin()
+ : QObject(), SharingPluginInterface()
+{
+}
+
+FediverseSharePlugin::~FediverseSharePlugin()
+{
+}
+
+SharingPluginInfo *FediverseSharePlugin::infoObject()
+{
+ return new FediversePluginInfo;
+}
+
+QString FediverseSharePlugin::pluginId() const
+{
+ return QLatin1String("Fediverse");
+}
diff --git a/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.h b/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.h
new file mode 100644
index 0000000..0eb7772
--- /dev/null
+++ b/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.h
@@ -0,0 +1,28 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FEDIVERSESHAREPLUGIN_H
+#define FEDIVERSESHAREPLUGIN_H
+
+#include <QtCore/QObject>
+
+#include <sharingplugininterface.h>
+
+class Q_DECL_EXPORT FediverseSharePlugin : public QObject, public SharingPluginInterface
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.sailfishos.share.plugin.fediverse")
+ Q_INTERFACES(SharingPluginInterface)
+
+public:
+ FediverseSharePlugin();
+ ~FediverseSharePlugin();
+
+ SharingPluginInfo *infoObject();
+ QString pluginId() const;
+};
+
+#endif // FEDIVERSESHAREPLUGIN_H
diff --git a/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.pro b/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.pro
index 59fb7e1..a085a30 100644
--- a/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.pro
+++ b/transferengine-plugins/fediverseshareplugin/fediverseshareplugin.pro
@@ -3,28 +3,30 @@
# SPDX-License-Identifier: BSD-3-Clause
TEMPLATE = lib
-TARGET = $$qtLibraryTarget(mastodonshareplugin)
+TARGET = $$qtLibraryTarget(fediverseshareplugin)
CONFIG += plugin
DEPENDPATH += .
INCLUDEPATH += ..
INCLUDEPATH += ../../common
+QT -= gui
+
CONFIG += link_pkgconfig
PKGCONFIG += nemotransferengine-qt5 accounts-qt5 sailfishaccounts libsignon-qt5
-HEADERS += mastodonshareplugin.h \
- mastodonplugininfo.h \
- ../mastodonshareservicestatus.h
+HEADERS += fediverseshareplugin.h \
+ fediverseplugininfo.h \
+ ../fediverseshareservicestatus.h
-SOURCES += mastodonshareplugin.cpp \
- mastodonplugininfo.cpp \
- ../mastodonshareservicestatus.cpp
+SOURCES += fediverseshareplugin.cpp \
+ fediverseplugininfo.cpp \
+ ../fediverseshareservicestatus.cpp
target.path = $$[QT_INSTALL_LIBS]/nemo-transferengine/plugins/sharing
OTHER_FILES += *.qml
-shareui.files = MastodonSharePost.qml
+shareui.files = FediverseSharePost.qml
shareui.path = /usr/share/nemo-transferengine/plugins/sharing
INSTALLS += target shareui
diff --git a/transferengine-plugins/mastodonshareservicestatus.cpp b/transferengine-plugins/fediverseshareservicestatus.cpp
index 2591520..0ab1460 100644
--- a/transferengine-plugins/mastodonshareservicestatus.cpp
+++ b/transferengine-plugins/fediverseshareservicestatus.cpp
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include "mastodonshareservicestatus.h"
-#include "mastodonauthutils.h"
+#include "fediverseshareservicestatus.h"
+#include "fediverseauthutils.h"
#include <Accounts/Account>
#include <Accounts/AccountService>
@@ -21,20 +21,20 @@
#include <QtCore/QVariantMap>
#include <QtDebug>
-MastodonShareServiceStatus::MastodonShareServiceStatus(QObject *parent)
+FediverseShareServiceStatus::FediverseShareServiceStatus(QObject *parent)
: QObject(parent)
, m_auth(new AccountAuthenticator(this))
, m_accountManager(new Accounts::Manager(this))
- , m_serviceName(QStringLiteral("mastodon-sharing"))
+ , m_serviceName(QStringLiteral("fediverse-sharing"))
{
}
-QString MastodonShareServiceStatus::authServiceName() const
+QString FediverseShareServiceStatus::authServiceName() const
{
- return QStringLiteral("mastodon-microblog");
+ return QStringLiteral("fediverse-microblog");
}
-void MastodonShareServiceStatus::signIn(int accountId)
+void FediverseShareServiceStatus::signIn(int accountId)
{
Accounts::Account *account = Accounts::Account::fromId(m_accountManager, accountId, this);
if (!account) {
@@ -78,7 +78,7 @@ void MastodonShareServiceStatus::signIn(int accountId)
QVariantMap signonSessionData = accountService.authData().parameters();
- MastodonAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
+ FediverseAuthUtils::addSignOnSessionParameters(account, &signonSessionData);
connect(session, SIGNAL(response(SignOn::SessionData)),
this, SLOT(signOnResponse(SignOn::SessionData)),
@@ -92,16 +92,16 @@ void MastodonShareServiceStatus::signIn(int accountId)
session->process(SignOn::SessionData(signonSessionData), mechanism);
}
-void MastodonShareServiceStatus::signOnResponse(const SignOn::SessionData &responseData)
+void FediverseShareServiceStatus::signOnResponse(const SignOn::SessionData &responseData)
{
- const QVariantMap data = MastodonAuthUtils::responseDataToMap(responseData);
+ const QVariantMap data = FediverseAuthUtils::responseDataToMap(responseData);
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession *>(sender());
Accounts::Account *account = session->property("account").value<Accounts::Account *>();
SignOn::Identity *identity = session->property("identity").value<SignOn::Identity *>();
const int accountId = account ? account->id() : 0;
- QString accessToken = MastodonAuthUtils::accessToken(data);
+ QString accessToken = FediverseAuthUtils::accessToken(data);
if (accountId > 0 && m_accountIdToDetailsIdx.contains(accountId)) {
AccountDetails &accountDetails(m_accountDetails[m_accountIdToDetailsIdx[accountId]]);
@@ -119,7 +119,7 @@ void MastodonShareServiceStatus::signOnResponse(const SignOn::SessionData &respo
}
}
-void MastodonShareServiceStatus::signOnError(const SignOn::Error &error)
+void FediverseShareServiceStatus::signOnError(const SignOn::Error &error)
{
SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession *>(sender());
Accounts::Account *account = session->property("account").value<Accounts::Account *>();
@@ -147,7 +147,7 @@ void MastodonShareServiceStatus::signOnError(const SignOn::Error &error)
}
}
-void MastodonShareServiceStatus::setAccountDetailsState(int accountId, AccountDetailsState state)
+void FediverseShareServiceStatus::setAccountDetailsState(int accountId, AccountDetailsState state)
{
if (!m_accountIdToDetailsIdx.contains(accountId)) {
return;
@@ -170,22 +170,22 @@ void MastodonShareServiceStatus::setAccountDetailsState(int accountId, AccountDe
if (anyPopulated) {
emit serviceReady();
} else {
- emit serviceError(QStringLiteral("Unable to retrieve Mastodon account credentials"));
+ emit serviceError(QStringLiteral("Unable to retrieve Fediverse account credentials"));
}
}
}
-int MastodonShareServiceStatus::count() const
+int FediverseShareServiceStatus::count() const
{
return m_accountDetails.count();
}
-bool MastodonShareServiceStatus::setCredentialsNeedUpdate(int accountId, const QString &serviceName)
+bool FediverseShareServiceStatus::setCredentialsNeedUpdate(int accountId, const QString &serviceName)
{
return m_auth->setCredentialsNeedUpdate(accountId, serviceName);
}
-void MastodonShareServiceStatus::queryStatus(QueryStatusMode mode)
+void FediverseShareServiceStatus::queryStatus(QueryStatusMode mode)
{
m_accountDetails.clear();
m_accountIdToDetailsIdx.clear();
@@ -237,11 +237,16 @@ void MastodonShareServiceStatus::queryStatus(QueryStatusMode mode)
AccountDetails details;
details.accountId = id;
acc->selectService(Accounts::Service());
- details.apiHost = MastodonAuthUtils::normalizeApiHost(acc->value(QStringLiteral("api/Host")).toString());
+ details.apiHost = FediverseAuthUtils::normalizeApiHost(acc->value(QStringLiteral("api/Host")).toString());
+ const QString instanceTitle = acc->value(QStringLiteral("instance/Title")).toString().trimmed();
+ details.iconPath = acc->value(QStringLiteral("iconPath")).toString().trimmed();
acc->selectService(service);
QUrl apiUrl(details.apiHost);
- details.providerName = apiUrl.host();
+ details.providerName = instanceTitle;
+ if (details.providerName.isEmpty()) {
+ details.providerName = apiUrl.host();
+ }
if (details.providerName.isEmpty()) {
details.providerName = details.apiHost;
if (details.providerName.startsWith(QLatin1String("https://"))) {
@@ -255,7 +260,10 @@ void MastodonShareServiceStatus::queryStatus(QueryStatusMode mode)
}
}
- details.displayName = acc->displayName();
+ details.displayName = acc->value(QStringLiteral("description")).toString().trimmed();
+ if (details.displayName.isEmpty()) {
+ details.displayName = acc->displayName();
+ }
m_accountIdToDetailsIdx.insert(id, m_accountDetails.size());
m_accountDetails.append(details);
@@ -276,7 +284,7 @@ void MastodonShareServiceStatus::queryStatus(QueryStatusMode mode)
}
}
-MastodonShareServiceStatus::AccountDetails MastodonShareServiceStatus::details(int index) const
+FediverseShareServiceStatus::AccountDetails FediverseShareServiceStatus::details(int index) const
{
if (index < 0 || index >= m_accountDetails.size()) {
qWarning() << Q_FUNC_INFO << "Index out of range";
@@ -286,7 +294,7 @@ MastodonShareServiceStatus::AccountDetails MastodonShareServiceStatus::details(i
return m_accountDetails.at(index);
}
-MastodonShareServiceStatus::AccountDetails MastodonShareServiceStatus::detailsByIdentifier(int accountIdentifier) const
+FediverseShareServiceStatus::AccountDetails FediverseShareServiceStatus::detailsByIdentifier(int accountIdentifier) const
{
if (!m_accountIdToDetailsIdx.contains(accountIdentifier)) {
qWarning() << Q_FUNC_INFO << "No details known for account with identifier" << accountIdentifier;
diff --git a/transferengine-plugins/mastodonshareservicestatus.h b/transferengine-plugins/fediverseshareservicestatus.h
index be76c37..a82be17 100644
--- a/transferengine-plugins/mastodonshareservicestatus.h
+++ b/transferengine-plugins/fediverseshareservicestatus.h
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef MASTODONSHARESERVICESTATUS_H
-#define MASTODONSHARESERVICESTATUS_H
+#ifndef FEDIVERSESHARESERVICESTATUS_H
+#define FEDIVERSESHARESERVICESTATUS_H
#include <QtCore/QHash>
#include <QtCore/QObject>
@@ -23,12 +23,12 @@ class Error;
class SessionData;
}
-class MastodonShareServiceStatus : public QObject
+class FediverseShareServiceStatus : public QObject
{
Q_OBJECT
public:
- explicit MastodonShareServiceStatus(QObject *parent = 0);
+ explicit FediverseShareServiceStatus(QObject *parent = 0);
enum QueryStatusMode {
PassiveMode = 0,
@@ -43,6 +43,7 @@ public:
QString displayName;
QString accessToken;
QString apiHost;
+ QString iconPath;
};
AccountDetails details(int index = 0) const;
@@ -78,4 +79,4 @@ private:
QHash<int, AccountDetailsState> m_accountDetailsState;
};
-#endif // MASTODONSHARESERVICESTATUS_H
+#endif // FEDIVERSESHARESERVICESTATUS_H
diff --git a/transferengine-plugins/mastodontransferplugin/mastodonapi.cpp b/transferengine-plugins/fediversetransferplugin/fediverseapi.cpp
index fa973d0..d9de9eb 100644
--- a/transferengine-plugins/mastodontransferplugin/mastodonapi.cpp
+++ b/transferengine-plugins/fediversetransferplugin/fediverseapi.cpp
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include "mastodonapi.h"
-#include "mastodonauthutils.h"
+#include "fediverseapi.h"
+#include "fediverseauthutils.h"
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
@@ -19,18 +19,18 @@
#include <QtDebug>
-MastodonApi::MastodonApi(QNetworkAccessManager *qnam, QObject *parent)
+FediverseApi::FediverseApi(QNetworkAccessManager *qnam, QObject *parent)
: QObject(parent)
, m_cancelRequested(false)
, m_qnam(qnam)
{
}
-MastodonApi::~MastodonApi()
+FediverseApi::~FediverseApi()
{
}
-bool MastodonApi::uploadImage(const QString &filePath,
+bool FediverseApi::uploadImage(const QString &filePath,
const QString &statusText,
const QString &mimeType,
const QString &apiHost,
@@ -43,7 +43,7 @@ bool MastodonApi::uploadImage(const QString &filePath,
}
m_cancelRequested = false;
- m_apiHost = MastodonAuthUtils::normalizeApiHost(apiHost);
+ m_apiHost = FediverseAuthUtils::normalizeApiHost(apiHost);
m_accessToken = accessToken;
m_statusText = statusText;
@@ -83,19 +83,19 @@ bool MastodonApi::uploadImage(const QString &filePath,
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(reply, &QNetworkReply::uploadProgress,
- this, &MastodonApi::uploadProgress);
+ this, &FediverseApi::uploadProgress);
connect(reply, &QNetworkReply::finished,
- this, &MastodonApi::finished);
+ this, &FediverseApi::finished);
return true;
}
-bool MastodonApi::postStatus(const QString &statusText,
+bool FediverseApi::postStatus(const QString &statusText,
const QString &apiHost,
const QString &accessToken)
{
m_cancelRequested = false;
- m_apiHost = MastodonAuthUtils::normalizeApiHost(apiHost);
+ m_apiHost = FediverseAuthUtils::normalizeApiHost(apiHost);
m_accessToken = accessToken;
m_statusText = statusText;
@@ -107,7 +107,7 @@ bool MastodonApi::postStatus(const QString &statusText,
return postStatusInternal(QString());
}
-bool MastodonApi::postStatusInternal(const QString &mediaId)
+bool FediverseApi::postStatusInternal(const QString &mediaId)
{
if (m_statusText.trimmed().isEmpty() && mediaId.isEmpty()) {
qWarning() << Q_FUNC_INFO << "status and media id are empty";
@@ -139,12 +139,12 @@ bool MastodonApi::postStatusInternal(const QString &mediaId)
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(reply, &QNetworkReply::finished,
- this, &MastodonApi::finished);
+ this, &FediverseApi::finished);
return true;
}
-void MastodonApi::cancelUpload()
+void FediverseApi::cancelUpload()
{
if (m_replies.isEmpty()) {
qWarning() << Q_FUNC_INFO << "can't cancel upload";
@@ -158,19 +158,19 @@ void MastodonApi::cancelUpload()
}
}
-void MastodonApi::replyError(QNetworkReply::NetworkError error)
+void FediverseApi::replyError(QNetworkReply::NetworkError error)
{
Q_UNUSED(error)
}
-void MastodonApi::uploadProgress(qint64 sent, qint64 total)
+void FediverseApi::uploadProgress(qint64 sent, qint64 total)
{
if (total > 0) {
emit transferProgressUpdated(sent / static_cast<qreal>(total));
}
}
-void MastodonApi::finished()
+void FediverseApi::finished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !m_replies.contains(reply)) {
@@ -212,7 +212,7 @@ void MastodonApi::finished()
}
if (!postStatusInternal(mediaId)) {
- qWarning() << Q_FUNC_INFO << "unable to create mastodon status";
+ qWarning() << Q_FUNC_INFO << "unable to create fediverse status";
emit transferError();
}
return;
@@ -226,7 +226,7 @@ void MastodonApi::finished()
emit transferError();
}
-void MastodonApi::finishTransfer(QNetworkReply::NetworkError error, int httpCode, const QByteArray &data)
+void FediverseApi::finishTransfer(QNetworkReply::NetworkError error, int httpCode, const QByteArray &data)
{
m_cancelRequested = false;
diff --git a/transferengine-plugins/mastodontransferplugin/mastodonapi.h b/transferengine-plugins/fediversetransferplugin/fediverseapi.h
index df4c87a..a85442c 100644
--- a/transferengine-plugins/mastodontransferplugin/mastodonapi.h
+++ b/transferengine-plugins/fediversetransferplugin/fediverseapi.h
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef MASTODONAPI_H
-#define MASTODONAPI_H
+#ifndef FEDIVERSEAPI_H
+#define FEDIVERSEAPI_H
#include <QtCore/QMap>
#include <QtCore/QObject>
@@ -13,7 +13,7 @@
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
-class MastodonApi : public QObject
+class FediverseApi : public QObject
{
Q_OBJECT
@@ -24,8 +24,8 @@ public:
POST_STATUS
};
- explicit MastodonApi(QNetworkAccessManager *qnam, QObject *parent = 0);
- ~MastodonApi();
+ explicit FediverseApi(QNetworkAccessManager *qnam, QObject *parent = 0);
+ ~FediverseApi();
bool uploadImage(const QString &filePath,
const QString &statusText,
@@ -62,4 +62,4 @@ private:
QString m_statusText;
};
-#endif // MASTODONAPI_H
+#endif // FEDIVERSEAPI_H
diff --git a/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.cpp b/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.cpp
new file mode 100644
index 0000000..bd213f8
--- /dev/null
+++ b/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.cpp
@@ -0,0 +1,31 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fediversetransferplugin.h"
+#include "fediverseuploader.h"
+
+#include <QtPlugin>
+#include <QNetworkAccessManager>
+
+FediverseTransferPlugin::FediverseTransferPlugin()
+ : QObject(), TransferPluginInterface()
+ , m_qnam(new QNetworkAccessManager(this))
+{
+}
+
+FediverseTransferPlugin::~FediverseTransferPlugin()
+{
+}
+
+MediaTransferInterface *FediverseTransferPlugin::transferObject()
+{
+ return new FediverseUploader(m_qnam, this);
+}
+
+QString FediverseTransferPlugin::pluginId() const
+{
+ return QLatin1String("Fediverse");
+}
diff --git a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.h b/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.h
index 4d3baaf..163d23f 100644
--- a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.h
+++ b/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.h
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef MASTODONTRANSFERPLUGIN_H
-#define MASTODONTRANSFERPLUGIN_H
+#ifndef FEDIVERSETRANSFERPLUGIN_H
+#define FEDIVERSETRANSFERPLUGIN_H
#include <QtCore/QObject>
@@ -13,15 +13,15 @@
class QNetworkAccessManager;
-class Q_DECL_EXPORT MastodonTransferPlugin : public QObject, public TransferPluginInterface
+class Q_DECL_EXPORT FediverseTransferPlugin : public QObject, public TransferPluginInterface
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.sailfishos.transfer.plugin.mastodon")
+ Q_PLUGIN_METADATA(IID "org.sailfishos.transfer.plugin.fediverse")
Q_INTERFACES(TransferPluginInterface)
public:
- MastodonTransferPlugin();
- ~MastodonTransferPlugin();
+ FediverseTransferPlugin();
+ ~FediverseTransferPlugin();
MediaTransferInterface *transferObject();
QString pluginId() const;
@@ -30,4 +30,4 @@ private:
QNetworkAccessManager *m_qnam;
};
-#endif // MASTODONTRANSFERPLUGIN_H
+#endif // FEDIVERSETRANSFERPLUGIN_H
diff --git a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.pro b/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.pro
index 422a889..8451dc5 100644
--- a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.pro
+++ b/transferengine-plugins/fediversetransferplugin/fediversetransferplugin.pro
@@ -3,26 +3,27 @@
# SPDX-License-Identifier: BSD-3-Clause
TEMPLATE = lib
-TARGET = $$qtLibraryTarget(mastodontransferplugin)
+TARGET = $$qtLibraryTarget(fediversetransferplugin)
CONFIG += plugin
DEPENDPATH += .
INCLUDEPATH += ..
INCLUDEPATH += ../../common
+QT -= gui
QT += network
CONFIG += link_pkgconfig
PKGCONFIG += nemotransferengine-qt5 accounts-qt5 sailfishaccounts libsignon-qt5
-HEADERS += mastodontransferplugin.h \
- mastodonuploader.h \
- ../mastodonshareservicestatus.h \
- mastodonapi.h
+HEADERS += fediversetransferplugin.h \
+ fediverseuploader.h \
+ ../fediverseshareservicestatus.h \
+ fediverseapi.h
-SOURCES += mastodontransferplugin.cpp \
- mastodonuploader.cpp \
- ../mastodonshareservicestatus.cpp \
- mastodonapi.cpp
+SOURCES += fediversetransferplugin.cpp \
+ fediverseuploader.cpp \
+ ../fediverseshareservicestatus.cpp \
+ fediverseapi.cpp
target.path = $$[QT_INSTALL_LIBS]/nemo-transferengine/plugins/transfer
diff --git a/transferengine-plugins/mastodontransferplugin/mastodonuploader.cpp b/transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp
index 7b87823..7c8766b 100644
--- a/transferengine-plugins/mastodontransferplugin/mastodonuploader.cpp
+++ b/transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include "mastodonuploader.h"
-#include "mastodonapi.h"
+#include "fediverseuploader.h"
+#include "fediverseapi.h"
#include <imageoperation.h>
#include <mediaitem.h>
@@ -16,40 +16,40 @@
#include <QtDebug>
-MastodonUploader::MastodonUploader(QNetworkAccessManager *qnam, QObject *parent)
+FediverseUploader::FediverseUploader(QNetworkAccessManager *qnam, QObject *parent)
: MediaTransferInterface(parent)
, m_api(0)
- , m_mastodonShareServiceStatus(0)
+ , m_fediverseShareServiceStatus(0)
, m_qnam(qnam)
, m_useTmpFile(false)
{
}
-MastodonUploader::~MastodonUploader()
+FediverseUploader::~FediverseUploader()
{
}
-QString MastodonUploader::displayName() const
+QString FediverseUploader::displayName() const
{
- return tr("Mastodon");
+ return tr("Fediverse");
}
-QUrl MastodonUploader::serviceIcon() const
+QUrl FediverseUploader::serviceIcon() const
{
- return QUrl(QStringLiteral("image://theme/icon-l-mastodon"));
+ return QUrl(QStringLiteral("image://theme/icon-l-fediverse"));
}
-bool MastodonUploader::cancelEnabled() const
+bool FediverseUploader::cancelEnabled() const
{
return true;
}
-bool MastodonUploader::restartEnabled() const
+bool FediverseUploader::restartEnabled() const
{
return true;
}
-void MastodonUploader::start()
+void FediverseUploader::start()
{
if (!mediaItem()) {
qWarning() << Q_FUNC_INFO << "NULL MediaItem. Can't continue";
@@ -57,39 +57,39 @@ void MastodonUploader::start()
return;
}
- if (!m_mastodonShareServiceStatus) {
- m_mastodonShareServiceStatus = new MastodonShareServiceStatus(this);
- connect(m_mastodonShareServiceStatus, &MastodonShareServiceStatus::serviceReady,
- this, &MastodonUploader::startUploading);
- connect(m_mastodonShareServiceStatus, &MastodonShareServiceStatus::serviceError,
+ if (!m_fediverseShareServiceStatus) {
+ m_fediverseShareServiceStatus = new FediverseShareServiceStatus(this);
+ connect(m_fediverseShareServiceStatus, &FediverseShareServiceStatus::serviceReady,
+ this, &FediverseUploader::startUploading);
+ connect(m_fediverseShareServiceStatus, &FediverseShareServiceStatus::serviceError,
this, [this] (const QString &) {
transferError();
});
}
- m_mastodonShareServiceStatus->queryStatus();
+ m_fediverseShareServiceStatus->queryStatus();
}
-void MastodonUploader::cancel()
+void FediverseUploader::cancel()
{
if (m_api) {
m_api->cancelUpload();
} else {
- qWarning() << Q_FUNC_INFO << "Can't cancel. NULL MastodonApi object!";
+ qWarning() << Q_FUNC_INFO << "Can't cancel. NULL FediverseApi object!";
}
}
-void MastodonUploader::startUploading()
+void FediverseUploader::startUploading()
{
- if (!m_mastodonShareServiceStatus) {
- qWarning() << Q_FUNC_INFO << "NULL MastodonShareServiceStatus object!";
+ if (!m_fediverseShareServiceStatus) {
+ qWarning() << Q_FUNC_INFO << "NULL FediverseShareServiceStatus object!";
return;
}
const quint32 accountId = mediaItem()->value(MediaItem::AccountId).toInt();
- m_accountDetails = m_mastodonShareServiceStatus->detailsByIdentifier(accountId);
+ m_accountDetails = m_fediverseShareServiceStatus->detailsByIdentifier(accountId);
if (m_accountDetails.accountId <= 0 || m_accountDetails.accessToken.isEmpty()) {
- qWarning() << Q_FUNC_INFO << "Mastodon account details missing for id" << accountId;
+ qWarning() << Q_FUNC_INFO << "Fediverse account details missing for id" << accountId;
transferError();
return;
}
@@ -107,34 +107,34 @@ void MastodonUploader::startUploading()
}
}
-void MastodonUploader::transferFinished()
+void FediverseUploader::transferFinished()
{
setStatus(MediaTransferInterface::TransferFinished);
}
-void MastodonUploader::transferProgress(qreal progress)
+void FediverseUploader::transferProgress(qreal progress)
{
setProgress(progress);
}
-void MastodonUploader::transferError()
+void FediverseUploader::transferError()
{
setStatus(MediaTransferInterface::TransferInterrupted);
qWarning() << Q_FUNC_INFO << "Transfer interrupted";
}
-void MastodonUploader::transferCanceled()
+void FediverseUploader::transferCanceled()
{
setStatus(MediaTransferInterface::TransferCanceled);
}
-void MastodonUploader::credentialsExpired()
+void FediverseUploader::credentialsExpired()
{
const quint32 accountId = mediaItem()->value(MediaItem::AccountId).toInt();
- m_mastodonShareServiceStatus->setCredentialsNeedUpdate(accountId, QStringLiteral("mastodon-sharing"));
+ m_fediverseShareServiceStatus->setCredentialsNeedUpdate(accountId, QStringLiteral("fediverse-sharing"));
}
-void MastodonUploader::setStatus(MediaTransferInterface::TransferStatus status)
+void FediverseUploader::setStatus(MediaTransferInterface::TransferStatus status)
{
const bool finished = (status == TransferCanceled
|| status == TransferInterrupted
@@ -148,7 +148,7 @@ void MastodonUploader::setStatus(MediaTransferInterface::TransferStatus status)
MediaTransferInterface::setStatus(status);
}
-void MastodonUploader::postImage()
+void FediverseUploader::postImage()
{
m_useTmpFile = false;
m_filePath.clear();
@@ -204,7 +204,7 @@ void MastodonUploader::postImage()
}
}
-void MastodonUploader::postStatus()
+void FediverseUploader::postStatus()
{
ensureApi();
@@ -234,19 +234,19 @@ void MastodonUploader::postStatus()
}
}
-void MastodonUploader::ensureApi()
+void FediverseUploader::ensureApi()
{
if (!m_api) {
- m_api = new MastodonApi(m_qnam, this);
- connect(m_api, &MastodonApi::transferProgressUpdated,
- this, &MastodonUploader::transferProgress);
- connect(m_api, &MastodonApi::transferFinished,
- this, &MastodonUploader::transferFinished);
- connect(m_api, &MastodonApi::transferError,
- this, &MastodonUploader::transferError);
- connect(m_api, &MastodonApi::transferCanceled,
- this, &MastodonUploader::transferCanceled);
- connect(m_api, &MastodonApi::credentialsExpired,
- this, &MastodonUploader::credentialsExpired);
+ m_api = new FediverseApi(m_qnam, this);
+ connect(m_api, &FediverseApi::transferProgressUpdated,
+ this, &FediverseUploader::transferProgress);
+ connect(m_api, &FediverseApi::transferFinished,
+ this, &FediverseUploader::transferFinished);
+ connect(m_api, &FediverseApi::transferError,
+ this, &FediverseUploader::transferError);
+ connect(m_api, &FediverseApi::transferCanceled,
+ this, &FediverseUploader::transferCanceled);
+ connect(m_api, &FediverseApi::credentialsExpired,
+ this, &FediverseUploader::credentialsExpired);
}
}
diff --git a/transferengine-plugins/mastodontransferplugin/mastodonuploader.h b/transferengine-plugins/fediversetransferplugin/fediverseuploader.h
index 72d9689..2343145 100644
--- a/transferengine-plugins/mastodontransferplugin/mastodonuploader.h
+++ b/transferengine-plugins/fediversetransferplugin/fediverseuploader.h
@@ -4,24 +4,24 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef MASTODONUPLOADER_H
-#define MASTODONUPLOADER_H
+#ifndef FEDIVERSEUPLOADER_H
+#define FEDIVERSEUPLOADER_H
#include <QtNetwork/QNetworkAccessManager>
#include <mediatransferinterface.h>
-#include "mastodonshareservicestatus.h"
+#include "fediverseshareservicestatus.h"
-class MastodonApi;
+class FediverseApi;
-class MastodonUploader : public MediaTransferInterface
+class FediverseUploader : public MediaTransferInterface
{
Q_OBJECT
public:
- MastodonUploader(QNetworkAccessManager *qnam, QObject *parent = 0);
- ~MastodonUploader();
+ FediverseUploader(QNetworkAccessManager *qnam, QObject *parent = 0);
+ ~FediverseUploader();
QString displayName() const;
QUrl serviceIcon() const;
@@ -48,12 +48,12 @@ private:
void postImage();
void postStatus();
- MastodonApi *m_api;
- MastodonShareServiceStatus *m_mastodonShareServiceStatus;
+ FediverseApi *m_api;
+ FediverseShareServiceStatus *m_fediverseShareServiceStatus;
QNetworkAccessManager *m_qnam;
- MastodonShareServiceStatus::AccountDetails m_accountDetails;
+ FediverseShareServiceStatus::AccountDetails m_accountDetails;
bool m_useTmpFile;
QString m_filePath;
};
-#endif // MASTODONUPLOADER_H
+#endif // FEDIVERSEUPLOADER_H
diff --git a/transferengine-plugins/mastodonshareplugin/mastodonplugininfo.cpp b/transferengine-plugins/mastodonshareplugin/mastodonplugininfo.cpp
deleted file mode 100644
index 919d544..0000000
--- a/transferengine-plugins/mastodonshareplugin/mastodonplugininfo.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "mastodonplugininfo.h"
-#include "mastodonshareservicestatus.h"
-
-MastodonPluginInfo::MastodonPluginInfo()
- : SharingPluginInfo()
- , m_mastodonShareServiceStatus(new MastodonShareServiceStatus(this))
-{
- m_capabilities << QLatin1String("image/jpeg")
- << QLatin1String("image/png")
- << QLatin1String("video/mp4")
- << QLatin1String("text/x-url")
- << QLatin1String("text/plain");
-
- connect(m_mastodonShareServiceStatus, &MastodonShareServiceStatus::serviceReady,
- this, &MastodonPluginInfo::serviceReady);
- connect(m_mastodonShareServiceStatus, &MastodonShareServiceStatus::serviceError,
- this, &MastodonPluginInfo::infoError);
-}
-
-MastodonPluginInfo::~MastodonPluginInfo()
-{
-}
-
-QList<SharingMethodInfo> MastodonPluginInfo::info() const
-{
- return m_info;
-}
-
-void MastodonPluginInfo::query()
-{
- m_mastodonShareServiceStatus->queryStatus(MastodonShareServiceStatus::PassiveMode);
-}
-
-void MastodonPluginInfo::serviceReady()
-{
- m_info.clear();
-
- for (int i = 0; i < m_mastodonShareServiceStatus->count(); ++i) {
- SharingMethodInfo info;
-
- const MastodonShareServiceStatus::AccountDetails details = m_mastodonShareServiceStatus->details(i);
- info.setDisplayName(details.providerName);
- info.setSubtitle(details.displayName);
- info.setAccountId(details.accountId);
-
- info.setMethodId(QLatin1String("Mastodon"));
- info.setMethodIcon(QLatin1String("image://theme/icon-l-mastodon"));
- info.setShareUIPath(QLatin1String("/usr/share/nemo-transferengine/plugins/sharing/MastodonSharePost.qml"));
- info.setCapabilities(m_capabilities);
- m_info << info;
- }
-
- emit infoReady();
-}
diff --git a/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.cpp b/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.cpp
deleted file mode 100644
index 8c139a2..0000000
--- a/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "mastodonshareplugin.h"
-#include "mastodonplugininfo.h"
-
-#include <QtPlugin>
-
-MastodonSharePlugin::MastodonSharePlugin()
- : QObject(), SharingPluginInterface()
-{
-}
-
-MastodonSharePlugin::~MastodonSharePlugin()
-{
-}
-
-SharingPluginInfo *MastodonSharePlugin::infoObject()
-{
- return new MastodonPluginInfo;
-}
-
-QString MastodonSharePlugin::pluginId() const
-{
- return QLatin1String("Mastodon");
-}
diff --git a/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.h b/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.h
deleted file mode 100644
index 04d8412..0000000
--- a/transferengine-plugins/mastodonshareplugin/mastodonshareplugin.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef MASTODONSHAREPLUGIN_H
-#define MASTODONSHAREPLUGIN_H
-
-#include <QtCore/QObject>
-
-#include <sharingplugininterface.h>
-
-class Q_DECL_EXPORT MastodonSharePlugin : public QObject, public SharingPluginInterface
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.sailfishos.share.plugin.mastodon")
- Q_INTERFACES(SharingPluginInterface)
-
-public:
- MastodonSharePlugin();
- ~MastodonSharePlugin();
-
- SharingPluginInfo *infoObject();
- QString pluginId() const;
-};
-
-#endif // MASTODONSHAREPLUGIN_H
diff --git a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp b/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp
deleted file mode 100644
index a843df2..0000000
--- a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "mastodontransferplugin.h"
-#include "mastodonuploader.h"
-
-#include <QtPlugin>
-#include <QNetworkAccessManager>
-
-MastodonTransferPlugin::MastodonTransferPlugin()
- : QObject(), TransferPluginInterface()
- , m_qnam(new QNetworkAccessManager(this))
-{
-}
-
-MastodonTransferPlugin::~MastodonTransferPlugin()
-{
-}
-
-MediaTransferInterface *MastodonTransferPlugin::transferObject()
-{
- return new MastodonUploader(m_qnam, this);
-}
-
-QString MastodonTransferPlugin::pluginId() const
-{
- return QLatin1String("Mastodon");
-}
diff --git a/transferengine-plugins/transferengine-plugins.pro b/transferengine-plugins/transferengine-plugins.pro
index e2503a3..ce1a102 100644
--- a/transferengine-plugins/transferengine-plugins.pro
+++ b/transferengine-plugins/transferengine-plugins.pro
@@ -3,4 +3,4 @@
# SPDX-License-Identifier: BSD-3-Clause
TEMPLATE = subdirs
-SUBDIRS = mastodonshareplugin mastodontransferplugin
+SUBDIRS = fediverseshareplugin fediversetransferplugin