diff --git a/.gitignore b/.gitignore
index e31cfb2..e5f8bc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-
*.user
+README.md
diff --git a/README.md b/README.md
index ca54a60..af9d77a 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,23 @@
-# Tooter [Fork]
+# Tooter β
## About
-Tooter is Mastodon client for Sailfish OS. It is a free, open-source social network. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication.
+Tooter is Mastodon client for [Sailfish OS](https://sailfishos.org).
-This fork is being used to further develop and maintain the Tooter app by dysko (https://github.com/dysk0/harbour-tooter). The development branch 'upstream' is being used for merge pull requests to the original repository. Releases by dysko can be found on the Jolla store and on https://openrepos.net/content/dysko/tooter
+This fork is being used to further develop and maintain the Tooter app by dysko ([harbour-tooter](https://github.com/dysk0/harbour-tooter)).
-Releases from this forked repository (branch 'master') can be found here: https://openrepos.net/content/molan/tooter-v-fork.
+* Releases from this repository (Tooter β from release branch *master*) can be found on [OpenRepos.net](https://openrepos.net/content/molan/tooter-v)
+* Releases by dysko can be found on the Jolla store and on [OpenRepos.net](https://openrepos.net/content/dysko/tooter)
## Build
-Clone / download this repository and import it in your SailfishOS IDE using the harbour-tooter.pro project file. No additional configuration needed.
+Clone / download this repository and import it into your SailfishOS IDE using the harbour-tooter.pro project file. No additional configuration needed.
## Repository branches:
-- master: default (Beta release version, harbour-tooterb)
-- upstream: commits for Tooter release (harbour-tooter)
+* master: release branch which includes specifics for harbour-tooterb (Tooter β)
+* upstream: main development branch which is used to send changes to the upstream repository (harbour-tooter)
## Contributions
-Contributions to this project are very welcome, since there are still many things which can be done for Tooter.
-- please fork the upstream branch if you want to contribute to this project.
+Contributions to this project are very welcome, since there are still many things which can be done for Tooter. If you already know what you want to add or fix, please make a Pull Request (PR) with your proposal. Your PR should include an explanation or a change log summary. Merging will not be allowed until the PR has been reviewed.
+Please fork the [upstream branch](https://github.com/molan-git/harbour-tooter/tree/upstream) if you want to contribute to this project.
## Screenshots
diff --git a/harbour-tooterb.desktop b/harbour-tooterb.desktop
index 74cc312..6511311 100644
--- a/harbour-tooterb.desktop
+++ b/harbour-tooterb.desktop
@@ -4,8 +4,3 @@ X-Nemo-Application-Type=silica-qt5
Icon=harbour-tooterb
Exec=harbour-tooterb
Name=Tooter β
-# translation example:
-# your app name in German locale (de)
-#
-# Remember to comment out the following line, if you do not want to use
-# a different app name in German locale (de).
diff --git a/harbour-tooterb.pro b/harbour-tooterb.pro
index ff9a7c3..cf3b679 100644
--- a/harbour-tooterb.pro
+++ b/harbour-tooterb.pro
@@ -9,15 +9,14 @@
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
-# The name of your application
TARGET = harbour-tooterb
CONFIG += sailfishapp
QT += network dbus sql
+QT += multimedia
CONFIG += link_pkgconfig
-PKGCONFIG += sailfishapp
-PKGCONFIG += \
+PKGCONFIG += sailfishapp \
nemonotifications-qt5
DEFINES += "APPVERSION=\\\"$${SPECVERSION}\\\""
@@ -39,45 +38,44 @@ dbus_services.files = config/ba.dysko.harbour.tooterb.service
interfaces.path = /usr/share/dbus-1/interfaces/
interfaces.files = config/ba.dysko.harbourb.tooterb.xml
-SOURCES += src/harbour-tooterb.cpp
-SOURCES += src/imageuploader.cpp
-SOURCES += src/filedownloader.cpp
-SOURCES += src/notifications.cpp
-SOURCES += src/dbusAdaptor.cpp
-SOURCES += src/dbus.cpp
+SOURCES += src/harbour-tooterb.cpp \
+ src/imageuploader.cpp \
+ src/filedownloader.cpp \
+ src/notifications.cpp \
+ src/dbusAdaptor.cpp \
+ src/dbus.cpp
-HEADERS += src/imageuploader.h
-HEADERS += src/filedownloader.h
-HEADERS += src/notifications.h
-HEADERS += src/dbusAdaptor.h
-HEADERS += src/dbus.h
+HEADERS += src/imageuploader.h \
+ src/filedownloader.h \
+ src/notifications.h \
+ src/dbusAdaptor.h \
+ src/dbus.h
DISTFILES += qml/harbour-tooterb.qml \
+ qml/images/tooterb-cover.svg \
+ qml/pages/ConversationPage.qml \
+ qml/pages/ProfilePage.qml \
+ qml/pages/SettingsPage.qml \
qml/pages/components/InfoBanner.qml \
+ qml/pages/components/MediaFullScreen.qml \
+ qml/pages/components/MyMedia.qml \
+ qml/pages/components/NavigationPanel.qml \
+ qml/pages/components/ProfileImage.qml \
qml/pages/components/VisualContainer.qml \
qml/pages/components/MiniStatus.qml \
qml/pages/components/MiniHeader.qml \
qml/pages/components/ItemUser.qml \
qml/pages/components/MyList.qml \
- qml/pages/components/Navigation.qml \
qml/pages/components/ProfileHeader.qml \
qml/pages/components/MediaBlock.qml \
- qml/pages/components/MyImage.qml \
- qml/pages/components/ImageFullScreen.qml \
qml/cover/CoverPage.qml \
qml/pages/MainPage.qml \
qml/pages/LoginPage.qml \
- qml/pages/Conversation.qml \
- qml/pages/components/Toot.qml \
qml/pages/Browser.qml \
- qml/pages/Profile.qml \
- qml/pages/Settings.qml \
qml/lib/API.js \
- qml/images/notification.svg \
- qml/images/verified.svg \
- qml/images/boosted.svg \
- qml/images/tooterb.svg \
- qml/images/emojiselect.svg \
+ qml/images/icon-s-following \
+ qml/images/icon-s-bookmark \
+ qml/images/icon-m-emoji.svg \
qml/images/icon-m-profile.svg \
qml/images/icon-l-profile.svg \
qml/lib/Mastodon.js \
@@ -97,21 +95,18 @@ SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# following CONFIG line
CONFIG += sailfishapp_i18n
-# German translation is enabled as an example. If you aren't
-# planning to localize your app, remember to comment out the
-# following TRANSLATIONS line. And also do not forget to
-# modify the localized app name in the the .desktop file.
-TRANSLATIONS += translations/harbour-tooterb-de.ts
-TRANSLATIONS += translations/harbour-tooterb-el.ts
-TRANSLATIONS += translations/harbour-tooterb-es.ts
-TRANSLATIONS += translations/harbour-tooterb-fi.ts
-TRANSLATIONS += translations/harbour-tooterb-fr.ts
-TRANSLATIONS += translations/harbour-tooterb-nl.ts
-TRANSLATIONS += translations/harbour-tooterb-nl_BE.ts
-TRANSLATIONS += translations/harbour-tooterb-oc.ts
-TRANSLATIONS += translations/harbour-tooterb-pl.ts
-TRANSLATIONS += translations/harbour-tooterb-ru.ts
-TRANSLATIONS += translations/harbour-tooterb-sr.ts
-TRANSLATIONS += translations/harbour-tooterb-sv.ts
-TRANSLATIONS += translations/harbour-tooterb-zh_CN.ts
-TRANSLATIONS += translations/harbour-tooterb-it.ts
+TRANSLATIONS += translations/harbour-tooterb.ts \
+ translations/harbour-tooterb-de.ts \
+ translations/harbour-tooterb-el.ts \
+ translations/harbour-tooterb-es.ts \
+ translations/harbour-tooterb-fr.ts \
+ translations/harbour-tooterb-it.ts \
+ translations/harbour-tooterb-nl.ts \
+ translations/harbour-tooterb-nl_BE.ts \
+ translations/harbour-tooterb-oc.ts \
+ translations/harbour-tooterb-pl.ts \
+ translations/harbour-tooterb-ru.ts \
+ translations/harbour-tooterb-sr.ts \
+ translations/harbour-tooterb-sv.ts \
+ translations/harbour-tooterb-zh_CN.ts
+
diff --git a/harbour-tooterb.pro.user b/harbour-tooterb.pro.user
index a74221b..3519283 100644
--- a/harbour-tooterb.pro.user
+++ b/harbour-tooterb.pro.user
@@ -1,6 +1,6 @@
-
+
EnvironmentId
@@ -63,6 +63,370 @@
ProjectExplorer.Project.Target.0
+
+ SailfishOS-3.2.1.20-i486 (in Sailfish OS Build Engine)
+ SailfishOS-3.2.1.20-i486 (in Sailfish OS Build Engine)
+ SailfishOS-3.2.1.20-i486
+ 1
+ 1
+ 0
+
+ C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_i486_in_Sailfish_OS_Build_Engine-Debug
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 3
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 2
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_i486_in_Sailfish_OS_Build_Engine-Release
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 3
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 2
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+
+ C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_i486_in_Sailfish_OS_Build_Engine-Profile
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ true
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 3
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 2
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Profile
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 3
+
+
+
+ true
+ Prepare Target
+
+ QmakeProjectManager.MerPrepareTargetStep
+
+
+ true
+ RPM
+
+ QmakeProjectManager.MerRpmDeployStep
+
+ 2
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy As RPM Package
+
+ QmakeProjectManager.MerRpmDeployConfiguration
+
+
+
+
+ true
+ RPM
+
+ QmakeProjectManager.MerRpmBuildStep
+
+
+ true
+ RPM Validation
+
+ QmakeProjectManager.MerRpmValidationStep
+
+ 2
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Build RPM Package For Manual Deployment
+
+ QmakeProjectManager.MerMb2RpmBuildConfiguration
+
+
+
+
+ true
+ Prepare Target
+
+ QmakeProjectManager.MerPrepareTargetStep
+
+
+ true
+ Rsync
+
+ QmakeProjectManager.MerRsyncDeployStep
+
+ 2
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy By Copying Binaries
+
+ QmakeProjectManager.MerRSyncDeployConfiguration
+
+ 3
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ C:/Users/XPAM/Github/Github-App/harbour-tooter
+ false
+ -1
+ 3
+
+ 1
+
+
+ harbour-tooterb (on Sailfish OS Emulator 3.3.0.16)
+ QmakeProjectManager.MerRunConfiguration:C:/Users/XPAM/Github/Github-App/harbour-tooter/harbour-tooterb.pro
+ 1
+
+ false
+
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+
+
+ 1
+
+
+
+ ProjectExplorer.Project.Target.1
SailfishOS-3.3.0.16-armv7hl (in Sailfish OS Build Engine)
SailfishOS-3.3.0.16-armv7hl (in Sailfish OS Build Engine)
@@ -426,7 +790,7 @@
- ProjectExplorer.Project.Target.1
+ ProjectExplorer.Project.Target.2
SailfishOS-3.3.0.16-i486 (in Sailfish OS Build Engine)
SailfishOS-3.3.0.16-i486 (in Sailfish OS Build Engine)
@@ -789,9 +1153,373 @@
1
+
+ ProjectExplorer.Project.Target.3
+
+ SailfishOS-3.2.1.20-armv7hl (in Sailfish OS Build Engine)
+ SailfishOS-3.2.1.20-armv7hl (in Sailfish OS Build Engine)
+ SailfishOS-3.2.1.20-armv7hl
+ 1
+ 1
+ 0
+
+ C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_armv7hl_in_Sailfish_OS_Build_Engine-Debug
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 3
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 2
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_armv7hl_in_Sailfish_OS_Build_Engine-Release
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 3
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 2
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+
+ C:/Users/XPAM/Github/Github-App/build-harbour-tooterb-SailfishOS_3_2_1_20_armv7hl_in_Sailfish_OS_Build_Engine-Profile
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ true
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ false
+
+
+ false
+
+ 3
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Start Build Engine
+
+ Mer.MerSdkStartStep
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ true
+ clean
+
+ false
+
+ 2
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Profile
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 3
+
+
+
+ true
+ Prepare Target
+
+ QmakeProjectManager.MerPrepareTargetStep
+
+
+ true
+ RPM
+
+ QmakeProjectManager.MerRpmDeployStep
+
+ 2
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy As RPM Package
+
+ QmakeProjectManager.MerRpmDeployConfiguration
+
+
+
+
+ true
+ RPM
+
+ QmakeProjectManager.MerRpmBuildStep
+
+
+ true
+ RPM Validation
+
+ QmakeProjectManager.MerRpmValidationStep
+
+ 2
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Build RPM Package For Manual Deployment
+
+ QmakeProjectManager.MerMb2RpmBuildConfiguration
+
+
+
+
+ true
+ Prepare Target
+
+ QmakeProjectManager.MerPrepareTargetStep
+
+
+ true
+ Rsync
+
+ QmakeProjectManager.MerRsyncDeployStep
+
+ 2
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy By Copying Binaries
+
+ QmakeProjectManager.MerRSyncDeployConfiguration
+
+ 3
+
+
+ dwarf
+
+ cpu-cycles
+
+
+ 250
+ -F
+ true
+ 4096
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ kcachegrind
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ C:/Users/XPAM/Github/Github-App/harbour-tooter
+ false
+ -1
+ 3
+
+ 1
+
+
+ harbour-tooterb (on Sailfish OS Emulator 3.3.0.16)
+ QmakeProjectManager.MerRunConfiguration:C:/Users/XPAM/Github/Github-App/harbour-tooter/harbour-tooterb.pro
+ 1
+
+ false
+
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+
+
+ 1
+
+
ProjectExplorer.Project.TargetCount
- 2
+ 4
ProjectExplorer.Project.Updater.FileVersion
diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml
index 2383490..bc5c38f 100644
--- a/qml/cover/CoverPage.qml
+++ b/qml/cover/CoverPage.qml
@@ -30,9 +30,9 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
-
import "../lib/API.js" as Logic
+
CoverBackground {
onStatusChanged: {
switch (status ){
@@ -46,20 +46,21 @@ CoverBackground {
break;
}
}
+
Image {
id: bg
+ source: "../images/tooter-cover.svg"
+ horizontalAlignment: Image.AlignLeft
+ verticalAlignment: Image.AlignBottom
+ fillMode: Image.PreserveAspectFit
anchors {
bottom : parent.bottom
left: parent.left
right: parent.right
top: parent.top
}
- horizontalAlignment: Image.AlignLeft
- verticalAlignment: Image.AlignBottom
- fillMode: Image.PreserveAspectFit
-
- source: "../images/tooterb.svg"
}
+
Timer {
id: timer
interval: 60*1000
@@ -70,33 +71,34 @@ CoverBackground {
Image {
id: iconNot
+ source: "image://theme/icon-s-alarm?" + Theme.highlightColor
anchors {
left: parent.left
top: parent.top
leftMargin: Theme.paddingLarge
topMargin: Theme.paddingLarge
}
- source: "image://theme/icon-s-alarm?" + Theme.highlightColor
}
+
Label {
id: notificationsLbl
+ text: " "
+ color: Theme.highlightColor
anchors {
left: iconNot.right
leftMargin: Theme.paddingMedium
verticalCenter: iconNot.verticalCenter
}
- text: " "
- color: Theme.highlightColor
}
Label {
+ text: "Tooter β"
+ color: Theme.secondaryColor
anchors {
right: parent.right
rightMargin: Theme.paddingLarge
verticalCenter: iconNot.verticalCenter
}
- text: "Tooter β"
- color: Theme.primaryColor
}
signal activateapp(string person, string notice)
@@ -112,8 +114,11 @@ CoverBackground {
CoverAction {
iconSource: "image://theme/icon-cover-new"
onTriggered: {
- pageStack.push(Qt.resolvedUrl("./../pages/Conversation.qml"), {})
- appWindow.activate();
+ pageStack.push(Qt.resolvedUrl("./../pages/ConversationPage.qml"), {
+ headerTitle: qsTr("New Toot"),
+ type: "new"
+ })
+ appWindow.activate()
}
}
}
@@ -135,5 +140,5 @@ CoverBackground {
notificationsLbl.text = notificationsNum;
Logic.conf.notificationLastID = notificationLastID;
}
-}
+}
diff --git a/qml/harbour-tooterb.qml b/qml/harbour-tooterb.qml
index 7b23d5e..60e8399 100644
--- a/qml/harbour-tooterb.qml
+++ b/qml/harbour-tooterb.qml
@@ -33,23 +33,26 @@ import Sailfish.Silica 1.0
import "pages"
import "./lib/API.js" as Logic
-ApplicationWindow
-{
+ApplicationWindow {
id: appWindow
- //initialPage: Component { FirstPage { } }
- cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: defaultAllowedOrientations
+ cover: Qt.resolvedUrl("cover/CoverPage.qml")
Component.onCompleted: {
- var obj = {};
- Logic.mediator.installTo(obj);
- obj.subscribe('confLoaded', function(){
+ var obj = {}
+ Logic.mediator.installTo(obj)
+ obj.subscribe('confLoaded', function() {
console.log('confLoaded');
//console.log(JSON.stringify(Logic.conf))
if (!Logic.conf['notificationLastID'])
- Logic.conf['notificationLastID'] = 0;
+ Logic.conf['notificationLastID'] = 0
+
if (Logic.conf['instance']) {
- Logic.api = new Logic.MastodonAPI({ instance: Logic.conf['instance'], api_user_token: "" });
+ Logic.api = Logic.mastodonAPI({
+ "instance": Logic.conf['instance'],
+ "api_user_token": ""
+ })
}
+
if (Logic.conf['login']) {
//Logic.conf['notificationLastID'] = 0
Logic.api.setConfig("api_user_token", Logic.conf['api_user_token'])
@@ -57,17 +60,12 @@ ApplicationWindow
Logic.api.get('instance', [], function(data) {
console.log(JSON.stringify(data))
pageStack.push(Qt.resolvedUrl("./pages/MainPage.qml"), {})
- });
-
- //
- //
+ })
//pageStack.push(Qt.resolvedUrl("./pages/Conversation.qml"), {})
} else {
pageStack.push(Qt.resolvedUrl("./pages/LoginPage.qml"), {})
}
-
-
- });
+ })
Logic.init()
}
@@ -75,19 +73,18 @@ ApplicationWindow
//Logic.conf.notificationLastID = 0;
Logic.saveData()
}
- Connections
- {
- target: Dbus
- onViewtoot:
- {
- console.log(key, "dbus onViewtoot")
- }
- onActivateapp:
- {
- console.log ("dbus activate app")
- pageStack.pop(pageStack.find( function(page){ return (page._depth === 0) }))
- activate()
- }
- }
-}
+ Connections {
+ target: Dbus
+ onViewtoot: {
+ console.log(key, "dbus onViewtoot")
+ }
+ onActivateapp: {
+ console.log ("dbus activate app")
+ pageStack.pop(pageStack.find( function(page) {
+ return (page._depth === 0)
+ }))
+ activate()
+ }
+ }
+}
diff --git a/qml/images/boosted.svg b/qml/images/boosted.svg
deleted file mode 100644
index 468e2da..0000000
--- a/qml/images/boosted.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
diff --git a/qml/images/emojiselect.svg b/qml/images/icon-m-emoji.svg
similarity index 100%
rename from qml/images/emojiselect.svg
rename to qml/images/icon-m-emoji.svg
diff --git a/qml/images/icon-s-bookmark.svg b/qml/images/icon-s-bookmark.svg
new file mode 100644
index 0000000..f05bf8a
--- /dev/null
+++ b/qml/images/icon-s-bookmark.svg
@@ -0,0 +1,7 @@
+
diff --git a/qml/images/icon-s-follow.svg b/qml/images/icon-s-follow.svg
new file mode 100644
index 0000000..ebcf5ee
--- /dev/null
+++ b/qml/images/icon-s-follow.svg
@@ -0,0 +1,12 @@
+
diff --git a/qml/images/notification.svg b/qml/images/notification.svg
deleted file mode 100644
index 56f1b35..0000000
--- a/qml/images/notification.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/qml/images/tooterb.svg b/qml/images/tooter-cover.svg
similarity index 100%
rename from qml/images/tooterb.svg
rename to qml/images/tooter-cover.svg
diff --git a/qml/images/verified.svg b/qml/images/verified.svg
deleted file mode 100644
index 65d529b..0000000
--- a/qml/images/verified.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
diff --git a/qml/lib/API.js b/qml/lib/API.js
index f930c0c..cfc6fa8 100644
--- a/qml/lib/API.js
+++ b/qml/lib/API.js
@@ -9,6 +9,7 @@ var mediator = (function(){
mediator.channels[channel].push({ context : this, callback : fn });
return this;
};
+
var publish = function(channel){
if(!mediator.channels[channel]) return false;
var args = Array.prototype.slice.call(arguments, 1);
@@ -18,6 +19,7 @@ var mediator = (function(){
};
return this;
};
+
return {
channels : {},
publish : publish,
@@ -28,6 +30,7 @@ var mediator = (function(){
}
};
}());
+
var init = function(){
console.log("db.version: "+db.version);
if(db.version === '') {
@@ -35,7 +38,7 @@ var init = function(){
tx.executeSql('CREATE TABLE IF NOT EXISTS settings ('
+ ' key TEXT UNIQUE, '
+ ' value TEXT '
- +');');
+ + ');');
//tx.executeSql('INSERT INTO settings (key, value) VALUES (?, ?)', ["conf", "{}"]);
});
db.changeVersion('', '0.1', function(tx) {
@@ -88,21 +91,22 @@ var tootParser = function(data){
ret.display_name = data.account.display_name
ret.avatar_static = data.account.avatar_static
-
ret.favourited = data.favourited ? true : false
- ret.favourites_count = data.favourites_count ? data.favourites_count : 0
+ ret.status_favourites_count = data.favourites_count ? data.favourites_count : 0
ret.reblog = data.reblog ? true : false
ret.reblogged = data.reblogged ? true : false
- ret.reblogs_count = data.reblogs_count ? data.reblogs_count : false
+ ret.status_reblogs_count = data.reblogs_count ? data.reblogs_count : false
+
+ ret.bookmarked = data.bookmarked ? true : false
ret.muted = data.muted ? true : false
ret.sensitive = data.sensitive ? true : false
ret.visibility = data.visibility ? data.visibility : false
-
console.log(ret)
}
+
var test = 1;
Qt.include("Mastodon.js")
@@ -161,6 +165,7 @@ var notifier = function(item){
key: item.id
}
break;
+
case "follow":
msg = {
urgency: "critical",
@@ -182,6 +187,7 @@ var notifier = function(item){
key: item.id
}
break;
+
case "mention":
msg = {
urgency: "critical",
@@ -193,6 +199,7 @@ var notifier = function(item){
key: item.id
}
break;
+
default:
//console.log(JSON.stringify(messageObject.data))
return;
diff --git a/qml/lib/Mastodon.js b/qml/lib/Mastodon.js
index 8a8e4c6..97b5bcc 100644
--- a/qml/lib/Mastodon.js
+++ b/qml/lib/Mastodon.js
@@ -3,17 +3,19 @@
// do whatever you want with it
// but please don't hurt it (and keep this header)
-var MastodonAPI = function(config) {
+var mastodonAPI = function(config) {
var apiBase = config.instance + "/api/v1/";
return {
setConfig: function (key, value) {
// modify initial config afterwards
config[key] = value;
},
+
getConfig: function(key) {
//get config key
return config[key];
},
+
get: function (endpoint) {
// for GET API calls
// can be called with two or three parameters
@@ -56,8 +58,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() { // Call a function when the state changes.
- if (http.readyState == 4) {
- if (http.status == 200) {
+ if (http.readyState === 4) {
+ if (http.status === 200) {
console.log("Successful GET API request to " +apiBase+endpoint);
callback(JSON.parse(http.response),http.status)
} else {
@@ -67,6 +69,7 @@ var MastodonAPI = function(config) {
}
http.send();
},
+
post: function (endpoint) {
// for POST API calls
var postData, callback;
@@ -91,8 +94,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() { // Call a function when the state changes.
- if (http.readyState == 4) {
- if (http.status == 200) {
+ if (http.readyState === 4) {
+ if (http.status === 200) {
console.log("Successful POST API request to " +apiBase+endpoint);
callback(JSON.parse(http.response),http.status)
} else {
@@ -113,6 +116,7 @@ var MastodonAPI = function(config) {
}
});*/
},
+
delete: function (endpoint, callback) {
// for DELETE API calls.
$.ajax({
@@ -125,6 +129,7 @@ var MastodonAPI = function(config) {
}
});
},
+
stream: function (streamType, onData) {
// Event Stream Support
// websocket streaming is undocumented. i had to reverse engineer the fucking web client.
@@ -132,7 +137,7 @@ var MastodonAPI = function(config) {
// user for your local home TL and notifications
// public for your federated TL
// public:local for your home TL
- // hashtag&tag=fuckdonaldtrump for the stream of #fuckdonaldtrump
+ // hashtag&tag=mastodonrocks for the stream of #mastodonrocks
// callback gets called whenever new data ist recieved
// callback { event: (eventtype), payload: {mastodon object as described in the api docs} }
// eventtype could be notification (=notification) or update (= new toot in TL)
@@ -147,12 +152,10 @@ var MastodonAPI = function(config) {
onData(event);
};
es.onmessage = listener;
-
-
},
+
registerApplication: function (client_name, redirect_uri, scopes, website, callback) {
//register a new application
-
// OAuth Auth flow:
// First register the application
// 2) get a access code from a user (using the link, generation function below!)
@@ -180,8 +183,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() { // Call a function when the state changes.
- if (http.readyState == 4) {
- if (http.status == 200) {
+ if (http.readyState === 4) {
+ if (http.status === 200) {
console.log("Registered Application: " + http.response);
callback(http.response)
} else {
@@ -191,10 +194,12 @@ var MastodonAPI = function(config) {
}
http.send(params);
},
+
generateAuthLink: function (client_id, redirect_uri, responseType, scopes) {
return config.instance + "/oauth/authorize?client_id=" + client_id + "&redirect_uri=" + redirect_uri +
"&response_type=" + responseType + "&scope=" + scopes.join("+");
},
+
getAccessTokenFromAuthCode: function (client_id, client_secret, redirect_uri, code, callback) {
/*$.ajax({
url: config.instance + "/oauth/token",
@@ -221,8 +226,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() { // Call a function when the state changes.
- if (http.readyState == 4) {
- if (http.status == 200) {
+ if (http.readyState === 4) {
+ if (http.status === 200) {
console.log("Got Token: " + http.response);
callback(http.response)
} else {
@@ -236,7 +241,7 @@ var MastodonAPI = function(config) {
};
// node.js
-if (typeof module !== 'undefined') { module.exports = MastodonAPI; };
+if (typeof module !== 'undefined') { module.exports = mastodonAPI; };
String.prototype.replaceAll = function(search, replacement) {
var target = this;
diff --git a/qml/lib/Worker.js b/qml/lib/Worker.js
index 8b53e8c..1373fb0 100644
--- a/qml/lib/Worker.js
+++ b/qml/lib/Worker.js
@@ -1,5 +1,8 @@
Qt.include("Mastodon.js")
+
+
var loadImages = true;
+
WorkerScript.onMessage = function(msg) {
console.log("Action > " + msg.action)
console.log("Model > " + msg.model)
@@ -7,27 +10,31 @@ WorkerScript.onMessage = function(msg) {
console.log("Conf > " + JSON.stringify(msg.conf))
console.log("Params > " + JSON.stringify(msg.params))
- // order notifications in ASC order
+ /** order notifications in ASC order */
function orderNotifications(items){
- for (var i = items.length-1; i > 0; i--){
+ for (var i = items.length-1; i > 0; i--) {
if (items[i].id > 0 ) //msg.conf.notificationLastID)
WorkerScript.sendMessage({ 'fireNotification': true, "data": items[i]})
}
}
- if (!msg.conf || !msg.conf.login){
+ /** Logged-in status */
+ if (!msg.conf || !msg.conf.login) {
console.log("Not loggedin")
return;
}
+
+ /** Load images */
if (typeof msg.conf['loadImages'] !== "undefined")
loadImages = msg.conf['loadImages']
- var API = MastodonAPI({ instance: msg.conf.instance, api_user_token: msg.conf.api_user_token});
+ /** POST statuses */
+ var API = mastodonAPI({ instance: msg.conf.instance, api_user_token: msg.conf.api_user_token});
if (msg.method === "POST"){
API.post(msg.action, msg.params, function(data) {
if (msg.bgAction){
console.log(JSON.stringify(data))
- } else if (msg.action === "statuses"){
+ } else if (msg.action === "statuses") {
// status posted
if(msg.model){
var item = parseToot(data);
@@ -59,7 +66,7 @@ WorkerScript.onMessage = function(msg) {
} else if(msg.action === "notifications") {
// notification
- //console.log("Is notification... parsing...")
+ console.log("Get notification list")
console.log(JSON.stringify(data[i]))
item = parseNotification(data[i]);
items.push(item)
@@ -69,7 +76,9 @@ WorkerScript.onMessage = function(msg) {
console.log("ancestors")
for (var j = 0; j < data[i].length; j ++) {
item = parseToot(data[i][j]);
- item['id'] = item['status_id']
+ item['id'] = item['status_id'];
+ if (typeof item['attachments'] === "undefined")
+ item['attachments'] = [];
items.push(item)
console.log(JSON.stringify(data[i][j]))
}
@@ -78,7 +87,7 @@ WorkerScript.onMessage = function(msg) {
//console.log(JSON.stringify(i))
} else if(msg.action.indexOf("statuses") >-1 && msg.action.indexOf("context") >-1 && i === "descendants") {
- // status ancestors toots - conversation
+ // status descendants toots - conversation
console.log("descendants")
for (var j = 0; j < data[i].length; j ++) {
item = parseToot(data[i][j]);
@@ -91,16 +100,18 @@ WorkerScript.onMessage = function(msg) {
addDataToModel (msg.model, "append", items);
items = [];
- } else if (data[i].hasOwnProperty("content")){
- //console.log("Is toot... parsing...")
+ } else if (data[i].hasOwnProperty("content")){
+ //console.log("Get Toot")
item = parseToot(data[i]);
item['id'] = item['status_id']
items.push(item)
+
} else {
- WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i]})
+ WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i] })
}
}
}
+
if(msg.model && items.length)
addDataToModel(msg.model, msg.mode, items)
/*if(msg.action === "notifications")
@@ -108,40 +119,53 @@ WorkerScript.onMessage = function(msg) {
});
}
-
-
//WorkerScript.sendMessage({ 'notifyNewItems': length - i })
-function addDataToModel (model, mode, items){
+function addDataToModel (model, mode, items) {
var length = items.length;
console.log("Fetched > " +length)
if (mode === "append") {
model.append(items)
} else if (mode === "prepend") {
- for(var i = length-1; i >= 0 ; i--){
+ for(var i = length-1; i >= 0 ; i--) {
model.insert(0,items[i])
}
}
-
model.sync()
}
-function parseAccounts(collection, prefix, data){
- var res = collection;
+/** Function: Get Account Data */
+function parseAccounts(collection, prefix, data) {
+
+ var res = collection;
+ // Base attributes
res[prefix + 'account_id'] = data["id"]
res[prefix + 'account_username'] = data["username"]
res[prefix + 'account_acct'] = data["acct"]
+ res[prefix + 'account_url'] = data["url"]
+ // Display attributes
res[prefix + 'account_display_name'] = data["display_name"]
- res[prefix + 'account_discoverable'] = data["discoverable"]
- res[prefix + 'account_locked'] = data["locked"]
- res[prefix + 'account_created_at'] = data["created_at"]
+ res[prefix + 'account_note'] = data["note"]
res[prefix + 'account_avatar'] = data["avatar"]
res[prefix + 'account_header'] = data["header"]
+ res[prefix + 'account_locked'] = data["locked"]
+ //res[prefix + 'account_emojis'] = data["emojis"]
+ res[prefix + 'account_discoverable'] = data["discoverable"]
+ // Statistical attributes
+ res[prefix + 'account_created_at'] = data["created_at"]
+ res[prefix + 'account_statuses_count'] = data["statuses_count"]
+ res[prefix + 'account_followers_count'] = data["followers_count"]
+ res[prefix + 'account_following_count'] = data["following_count"]
+ // Optional attributes
+ //res[prefix + 'account_fields'] = data["fields"]
+ res[prefix + 'account_bot'] = data["bot"]
+ res[prefix + 'account_group'] = data["group"]
- // console.log(JSON.stringify(res))
+ //console.log(JSON.stringify(res))
return (res);
}
+/** Function: Get Notification Data */
function parseNotification(data){
//console.log(JSON.stringify(data))
var item = {
@@ -150,50 +174,49 @@ function parseNotification(data){
attachments: []
};
switch (item['type']){
+
case "mention":
if (!data.status) {
- break;
+ break;
}
-
item = parseToot(data.status)
- item['typeIcon'] = "image://theme/icon-s-retweet"
item['typeIcon'] = "image://theme/icon-s-alarm"
- item['type'] = "mention";
+ item['type'] = "mention"
break;
+
case "reblog":
if (!data.status) {
break;
}
-
item = parseToot(data.status)
item = parseAccounts(item, "reblog_", data["account"])
item = parseAccounts(item, "", data["status"]["account"])
- item['status_reblog'] = true;
- item['type'] = "reblog";
+ item['status_reblog'] = true
+ item['type'] = "reblog"
item['typeIcon'] = "image://theme/icon-s-retweet"
break;
+
case "favourite":
if (!data.status) {
break;
}
-
item = parseToot(data.status)
item = parseAccounts(item, "reblog_", data["account"])
item = parseAccounts(item, "", data["status"]["account"])
- item['status_reblog'] = true;
+ item['status_reblog'] = true
+ item['type'] = "favourite"
item['typeIcon'] = "image://theme/icon-s-favorite"
- item['type'] = "favourite";
- //item['retweetScreenName'] = item['reblog_account_username'];
break;
+
case "follow":
item['type'] = "follow";
item = parseAccounts(item, "", data["account"])
item = parseAccounts(item, "reblog_", data["account"])
- item['content'] = data['account']['note']
- item['typeIcon'] = "image://theme/icon-s-installed"
- item['attachments'] = []
-
+ //item['content'] = data['account']['note']
+ item['typeIcon'] = "../../images/icon-s-follow.svg"
+ //item['attachments'] = []
break;
+
default:
item['typeIcon'] = "image://theme/icon-s-sailfish"
}
@@ -204,6 +227,7 @@ function parseNotification(data){
return item;
}
+/** Function: */
function collect() {
var ret = {};
var len = arguments.length;
@@ -216,70 +240,81 @@ function collect() {
}
return ret;
}
-function getDate(dateStr){
+
+/** Function: Get Status date */
+function getDate(dateStr) {
var ts = new Date(dateStr);
return new Date(ts.getFullYear(), ts.getMonth(), ts.getDate(), 0, 0, 0)
}
-function parseToot (data){
+
+/** Function: Get Status data */
+function parseToot (data) {
var i = 0;
var item = {};
item['type'] = "toot"
item['highlight'] = false
item['status_id'] = data["id"]
- item['status_uri'] = data["uri"]
- item['status_url'] = data["url"]
- item['status_in_reply_to_id'] = data["in_reply_to_id"]
- item['status_in_reply_to_account_id'] = data["in_reply_to_account_id"]
- item['status_reblog'] = data["reblog"] ? true : false
- item['status_content'] = data["content"]
- item['status_created_at'] = item['created_at'] = new Date(data["created_at"]);
- item['section'] = getDate(data["created_at"]);
- item['reblogs_count'] = data["reblogs_count"]
- item['favourites_count'] = data["favourites_count"]
- item['reblogged'] = data["reblogged"]
- item['favourited'] = data["favourited"]
- item['bookmarked'] = data["bookmarked"]
+ item['status_created_at'] = item['created_at'] = new Date(data["created_at"])
item['status_sensitive'] = data["sensitive"]
item['status_spoiler_text'] = data["spoiler_text"]
item['status_visibility'] = data["visibility"]
+ item['status_language'] = data["language"]
+ item['status_uri'] = data["uri"]
+ item['status_url'] = data["url"]
+ item['status_replies_count'] = data["replies_count"]
+ item['status_reblogs_count'] = data["reblogs_count"]
+ item['status_favourites_count'] = data["favourites_count"]
+ item['status_favourited'] = data["favourited"]
+ item['status_reblogged'] = data["reblogged"]
+ item['status_bookmarked'] = data["bookmarked"]
+ item['status_content'] = data["content"]
+ item['attachments'] = data['media_attachments']
+ item['status_in_reply_to_id'] = data["in_reply_to_id"]
+ item['status_in_reply_to_account_id'] = data["in_reply_to_account_id"]
+ item['status_reblog'] = data["reblog"] ? true : false
+ item['section'] = getDate(data["created_at"])
- if(item['status_reblog']){
+ /** If Toot is a Reblog */
+ if(item['status_reblog']) {
item['type'] = "reblog";
item['typeIcon'] = "image://theme/icon-s-retweet"
- item['status_id'] = data["reblog"]["id"];
- item['status_spoiler_text'] = data["reblog"]["spoiler_text"]
+ item['status_id'] = data["reblog"]["id"]
item['status_sensitive'] = data["reblog"]["sensitive"]
- item['emojis'] = data["reblog"]["emojis"];
+ item['status_spoiler_text'] = data["reblog"]["spoiler_text"]
+ item['status_replies_count'] = data["reblog"]["replies_count"]
+ item['status_reblogs_count'] = data["reblog"]["reblogs_count"]
+ item['status_favourites_count'] = data["reblog"]["favourites_count"]
item = parseAccounts(item, "", data['reblog']["account"])
item = parseAccounts(item, "reblog_", data["account"])
} else {
item = parseAccounts(item, "", data["account"])
}
+
+ /** Replace HTML content in Toots */
item['content'] = data['content']
- .replaceAll('', '')
- .replaceAll('', '')
- .replaceAll('', '')
- .replaceAll('class=""', '');
+ .replaceAll('', '')
+ .replaceAll('', '')
+ .replaceAll('', '')
+ .replaceAll('class=""', '');
+
+ /** Media attachements in Toots */
item['attachments'] = [];
-
-
-
-
- for(i = 0; i < data['media_attachments'].length ; i++){
+ for(i = 0; i < data['media_attachments'].length; i++) {
var attachments = data['media_attachments'][i];
item['content'] = item['content'].replaceAll(attachments['text_url'], '')
var tmp = {
- id: attachments['id'],
id: attachments['id'],
type: attachments['type'],
url: attachments['remote_url'] && typeof attachments['remote_url'] == "string" ? attachments['remote_url'] : attachments['url'] ,
- preview_url: loadImages ? attachments['preview_url'] : ''
+ preview_url: loadImages ? attachments['preview_url'] : ''
}
item['attachments'].push(tmp)
}
- if(item['status_reblog']){
- for(i = 0; i < data['reblog']['media_attachments'].length ; i++){
+
+ /** Media attachements in Reblogs */
+ if(item['status_reblog']) {
+ for(i = 0; i < data['reblog']['media_attachments'].length ; i++) {
var attachments = data['reblog']['media_attachments'][i];
item['content'] = item['content'].replaceAll(attachments['text_url'], '')
var tmp = {
@@ -291,20 +326,22 @@ function parseToot (data){
item['attachments'].push(tmp)
}
}
+
return addEmojis(item, data);
}
-function addEmojis(item, data){
+/** Function: Display custom Emojis in Toots */
+function addEmojis(item, data) {
var emoji, i;
- for (i = 0; i < data["emojis"].length; i++){
+ for (i = 0; i < data["emojis"].length; i++) {
emoji = data["emojis"][i];
- item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "")
+ item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "")
//console.log(JSON.stringify(data["emojis"][i]))
}
if (data["reblog"])
- for (i = 0; i < data["reblog"]["emojis"].length; i++){
+ for (i = 0; i < data["reblog"]["emojis"].length; i++) {
emoji = data["reblog"]["emojis"][i];
- item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "")
+ item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "")
}
return item;
diff --git a/qml/pages/Conversation.qml b/qml/pages/Conversation.qml
deleted file mode 100644
index 14ecbb5..0000000
--- a/qml/pages/Conversation.qml
+++ /dev/null
@@ -1,646 +0,0 @@
-import QtQuick 2.0
-import Sailfish.Silica 1.0
-import harbour.tooterb.Uploader 1.0
-import "../lib/API.js" as Logic
-import "./components/"
-
-
-Page {
- id: conversationPage
- property string headerTitle: ""
- property string type
- property alias title: header.title
- property alias description: header.description
- property alias avatar: header.image
- property string suggestedUser: ""
- property ListModel suggestedModel
- property string toot_id: ""
- property string toot_url: ""
- property int tootMaxChar: 500;
- property ListModel mdl
- allowedOrientations: Orientation.All
- onSuggestedUserChanged: {
- console.log(suggestedUser)
- suggestedModel = Qt.createQmlObject(
- 'import QtQuick 2.0; ListModel { }',
- Qt.application, 'InternalQmlObject'
- )
- predictionList.visible = false
- if (suggestedUser.length > 0) {
- var msg = {
- "action": 'accounts/search',
- "method": 'GET',
- "model": suggestedModel,
- "mode": "append",
- "params": [{
- "name": "q",
- "data": suggestedUser
- }],
- "conf": Logic.conf
- }
- worker.sendMessage(msg)
- predictionList.visible = true
- }
- }
-
- InfoBanner {
- id: sentBanner
- }
-
- ListModel {
- id: mediaModel
- onCountChanged: {
- btnAddImage.enabled = mediaModel.count < 4
- }
- }
-
- WorkerScript {
- id: worker
- source: "../lib/Worker.js"
- onMessage: {
- console.log(JSON.stringify(messageObject))
- }
- }
-
- ProfileHeader {
- id: header
- visible: false
- }
- SilicaListView {
- id: conversationList
- header: PageHeader {
- title: headerTitle // pageTitle pushed from MainPage.qml or VisualContainer.qml
- }
- clip: true
- anchors {
- top: parent.top
- bottom: panel.top
- left: parent.left
- right: parent.right
- }
- model: mdl
- section {
- property: 'section'
- delegate: SectionHeader {
- height: Theme.itemSizeExtraSmall
- text: Format.formatDate(section, Formatter.DateMedium)
- }
- }
- delegate: VisualContainer {
- }
- onCountChanged: {
- if (mdl)
- for (var i = 0; i < mdl.count; i++) {
- if (mdl.get(i).status_id === toot_id) {
- console.log(mdl.get(i).status_id)
- positionViewAtIndex(i, ListView.Center)
- }
- }
- }
- PullDownMenu {
- visible: type == "reply" && toot_url != ""
- /* MenuItem {
- text: qsTr("Open in Browser")
- onClicked: Qt.openUrlExternally(toot_url);
- } */
- // ! url isn't always fetched. Needs a solution.
- MenuItem {
- text: qsTr("Copy Link to Clipboard")
- onClicked: Clipboard.text = toot_url;
- }
- }
- }
- Rectangle {
- id: predictionList
- visible: false
- anchors.bottom: panel.top
- anchors.left: parent.left
- anchors.right: panel.right
- height: suggestedModel.count > 6 ? Theme.itemSizeMedium * 6 : Theme.itemSizeMedium * suggestedModel.count
- color: Theme.highlightDimmerColor
-
- SilicaListView {
- anchors.fill: parent
- model: suggestedModel
- clip: true
- delegate: ItemUser {
- onClicked: {
- var start = toot.cursorPosition
- while (toot.text[start] !== "@" && start > 0) {
- start--
- }
- textOperations.text = toot.text
- textOperations.cursorPosition = toot.cursorPosition
- textOperations.moveCursorSelection(start - 1, TextInput.SelectWords)
- toot.text = textOperations.text.substring(0, textOperations.selectionStart)
- + ' @'
- + model.account_acct
- + ' '
- + textOperations.text.substring(textOperations.selectionEnd).trim()
-
- toot.cursorPosition = toot.text.indexOf('@' + model.account_acct)
- }
- }
- onCountChanged: {
- positionViewAtIndex(suggestedModel.count - 1, ListView.End)
- }
- }
- }
-
- DockedPanel {
- id: panel
- open: true
- onExpandedChanged: {
- if (!expanded) {
- show()
- }
- }
-
- width: parent.width
- height: progressBar.height + toot.height + (mediaModel.count ? uploadedImages.height : 0)
- + btnContentWarning.height + Theme.paddingMedium
- + (warningContent.visible ? warningContent.height : 0)
- dock: Dock.Bottom
- Rectangle {
- width: parent.width
- height: progressBar.height
- color: Theme.highlightBackgroundColor
- opacity: 0.2
- anchors {
- left: parent.left
- right: parent.right
- top: parent.top
- }
- }
- Rectangle {
- id: progressBar
- width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0
- height: Theme.itemSizeSmall * 0.05
- color: Theme.highlightBackgroundColor
- opacity: 0.7
- anchors {
- left: parent.left
- top: parent.top
- }
- }
-
- TextField {
- id: warningContent
- visible: false
- height: visible ? implicitHeight : 0
- anchors {
- top: parent.top
- topMargin: Theme.paddingMedium
- left: parent.left
- right: parent.right
- }
- autoScrollEnabled: true
- labelVisible: false
- font.pixelSize: Theme.fontSizeSmall
- placeholderText: qsTr("Write your warning here")
- placeholderColor: palette.highlightColor
- color: palette.highlightColor
- horizontalAlignment: Text.AlignLeft
- EnterKey.onClicked: {
- //tweet()
- }
- }
- TextInput {
- id: textOperations
- visible: false
- }
-
- TextArea {
- id: toot
- anchors {
- top: warningContent.bottom
- topMargin: Theme.paddingMedium
- left: parent.left
- right: parent.right
- rightMargin: Theme.paddingLarge * 2
- }
- autoScrollEnabled: true
- labelVisible: false
- //focus: true
- text: description !== "" && (description.charAt(0) == '@'
- || description.charAt(
- 0) == '#') ? description + ' ' : ''
- height: Math.max(270, Math.min(900, implicitHeight))
- horizontalAlignment: Text.AlignLeft
- placeholderText: qsTr("What's on your mind?")
- font.pixelSize: Theme.fontSizeSmall
- EnterKey.onClicked: {
- //tweet()
- }
- onTextChanged: {
- textOperations.text = toot.text
- textOperations.cursorPosition = toot.cursorPosition
- textOperations.selectWord()
- textOperations.select(
- textOperations.selectionStart ? textOperations.selectionStart - 1 : 0,
- textOperations.selectionEnd)
- //console.log(textOperations.text.substr(textOperations.selectionStart, textOperations.selectionEnd))
- console.log(toot.text.length)
- suggestedUser = ""
- if (textOperations.selectedText.charAt(0) === "@") {
- suggestedUser = textOperations.selectedText.trim().substring(1)
- }
- }
- }
- IconButton {
- id: btnSmileys
- property string selection
- onSelectionChanged: {
- console.log(selection)
- }
-
- anchors {
- top: warningContent.bottom
- bottom: bottom.top
- right: parent.right
- rightMargin: Theme.paddingSmall
- }
- opacity: 0.8
- icon.source: "../../qml/images/emojiselect.svg" + (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
- onClicked: pageStack.push(firstWizardPage)
- }
- SilicaGridView {
- id: uploadedImages
- width: parent.width
- anchors.top: bottom.toot
- anchors.bottom: parent.bottom
- height: mediaModel.count ? Theme.itemSizeSmall : 0
- model: mediaModel
- cellWidth: uploadedImages.width / 4
- cellHeight: Theme.itemSizeSmall
- delegate: BackgroundItem {
- id: myDelegate
- width: uploadedImages.cellWidth
- height: uploadedImages.cellHeight
- RemorseItem {
- id: remorse
- }
- Image {
- anchors.fill: parent
- fillMode: Image.PreserveAspectCrop
- source: model.preview_url
- }
-
- onClicked: {
- var idx = index
- console.log(idx)
- //mediaModel.remove(idx)
- remorse.execute(myDelegate, qsTr("Delete"), function () {
- mediaModel.remove(idx)
- })
- }
- }
- add: Transition {
- NumberAnimation {
- property: "opacity"
- from: 0
- to: 1.0
- duration: 800
- }
- }
-
- remove: Transition {
- NumberAnimation {
- property: "opacity"
- from: 1.0
- to: 0
- duration: 800
- }
- }
- displaced: Transition {
- NumberAnimation {
- properties: "x,y"
- duration: 800
- easing.type: Easing.InOutBack
- }
- }
- }
- IconButton {
- id: btnContentWarning
- anchors {
- top: toot.bottom
- topMargin: -Theme.paddingSmall * 1.5
- left: parent.left
- leftMargin: Theme.paddingMedium
- }
- icon.source: "image://theme/icon-s-warning?"
- + (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
- onClicked: warningContent.visible = !warningContent.visible
- }
- IconButton {
- id: btnAddImage
- enabled: mediaModel.count < 4
- anchors {
- top: toot.bottom
- topMargin: -Theme.paddingSmall * 1.5
- left: btnContentWarning.right
- leftMargin: Theme.paddingSmall
- }
- icon.source: "image://theme/icon-s-attach?"
- + (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
- onClicked: {
- btnAddImage.enabled = false
- var once = true
- var imagePicker = pageStack.push("Sailfish.Pickers.ImagePickerPage", {"allowedOrientations": Orientation.All})
- imagePicker.selectedContentChanged.connect(function () {
- var imagePath = imagePicker.selectedContent
- console.log(imagePath)
- imageUploader.setUploadUrl(Logic.conf.instance + "/api/v1/media")
- imageUploader.setFile(imagePath)
- imageUploader.setAuthorizationHeader(Logic.conf.api_user_token)
- imageUploader.upload()
- })
- }
- }
- ImageUploader {
- id: imageUploader
-
- onProgressChanged: {
- console.log("progress " + progress)
- uploadProgress.width = parent.width * progress
- }
-
- onSuccess: {
- uploadProgress.width = 0
- console.log(replyData)
-
- mediaModel.append(JSON.parse(replyData))
- }
-
- onFailure: {
- uploadProgress.width = 0
- btnAddImage.enabled = true
- console.log(status)
- console.log(statusText)
- }
- }
- ComboBox {
- id: privacy
- anchors {
- top: toot.bottom
- topMargin: -Theme.paddingSmall * 1.5
- left: btnAddImage.right
- right: btnSend.left
- }
- menu: ContextMenu {
- MenuItem {
- text: qsTr("Public")
- }
- MenuItem {
- text: qsTr("Unlisted")
- }
- MenuItem {
- text: qsTr("Followers-only")
- }
- MenuItem {
- text: qsTr("Direct")
- }
- }
- }
-
- IconButton {
- id: btnSend
- icon.source: "image://theme/icon-m-send?"
- + (pressed ? Theme.highlightColor : Theme.primaryColor)
- anchors {
- top: toot.bottom
- topMargin: -Theme.paddingSmall * 1.5
- right: parent.right
- rightMargin: Theme.paddingSmall
- }
- enabled: toot.text !== "" && toot.text.length < tootMaxChar && uploadProgress.width == 0
- onClicked: {
- var visibility = ["public", "unlisted", "private", "direct"]
- var media_ids = []
- for (var k = 0; k < mediaModel.count; k++) {
- console.log(mediaModel.get(k).id)
- media_ids.push(mediaModel.get(k).id)
- }
-
- var msg = {
- "action": 'statuses',
- "method": 'POST',
- "model": mdl,
- "mode": "append",
- "params": {
- "status": toot.text,
- "visibility": visibility[privacy.currentIndex],
- "media_ids": media_ids
- },
- "conf": Logic.conf
- }
- if (toot_id)
- msg.params['in_reply_to_id'] = (toot_id) + ""
-
- if (warningContent.visible && warningContent.text.length > 0) {
- msg.params['sensitive'] = 1
- msg.params['spoiler_text'] = warningContent.text
- }
-
- worker.sendMessage(msg)
- warningContent.text = ""
- toot.text = ""
- mediaModel.clear();
- sentBanner.showText(qsTr("Toot sent!"))
- }
- }
-
- Rectangle {
- id: uploadProgress
- color: Theme.highlightBackgroundColor
- anchors.bottom: parent.bottom
- anchors.left: parent.left
- height: 3
- }
- }
- Component.onCompleted: {
- toot.cursorPosition = toot.text.length
- if (mdl.count > 0) {
- var setIndex = 0
- switch (mdl.get(0).status_visibility) {
- case "unlisted":
- setIndex = 1
- break
- case "private":
- setIndex = 2
- break
- case "direct":
- privacy.enabled = false
- setIndex = 3
- break
- default:
- privacy.enabled = true
- setIndex = 0
- }
- privacy.currentIndex = setIndex
- }
-
- console.log(JSON.stringify())
-
- worker.sendMessage({
- "action": 'statuses/' + mdl.get(0).status_id + '/context',
- "method": 'GET',
- "model": mdl,
- "params": { },
- "conf": Logic.conf
- })
- }
- Component {
- id: firstWizardPage
-
- Dialog {
- id: emoticonsDialog
- canAccept: false //selector.currentIndex >= 0
-
- //acceptDestination: conversationPage
- onAcceptPendingChanged: {
- if (acceptPending) {
-
- // Tell the destination page what the selected category is
- // acceptDestinationInstance.category = selector.value
- }
- }
-
- SilicaGridView {
- id: gridView
- anchors.fill: parent
- cellWidth: gridView.width / 6
- cellHeight: cellWidth
- header: PageHeader {
- title: qsTr("Emojis")
- description: qsTr("Tap to insert")
- }
- model: ListModel {
- ListElement { section: "smileys"; glyph: "😁" }
- ListElement { section: "smileys"; glyph: "😂" }
- ListElement { section: "smileys"; glyph: "😃" }
- ListElement { section: "smileys"; glyph: "😄" }
- ListElement { section: "smileys"; glyph: "😅" }
- ListElement { section: "smileys"; glyph: "😆" }
- ListElement { section: "smileys"; glyph: "😉" }
- ListElement { section: "smileys"; glyph: "😊" }
- ListElement { section: "smileys"; glyph: "😋" }
- ListElement { section: "smileys"; glyph: "😌" }
- ListElement { section: "smileys"; glyph: "😍" }
- ListElement { section: "smileys"; glyph: "😏" }
- ListElement { section: "smileys"; glyph: "😒" }
- ListElement { section: "smileys"; glyph: "😓" }
- ListElement { section: "smileys"; glyph: "😔" }
- ListElement { section: "smileys"; glyph: "😖" }
- ListElement { section: "smileys"; glyph: "😘" }
- ListElement { section: "smileys"; glyph: "😚" }
- ListElement { section: "smileys"; glyph: "😜" }
- ListElement { section: "smileys"; glyph: "😝" }
- ListElement { section: "smileys"; glyph: "😞" }
- ListElement { section: "smileys"; glyph: "😠" }
- ListElement { section: "smileys"; glyph: "😡" }
- ListElement { section: "smileys"; glyph: "😢" }
- ListElement { section: "smileys"; glyph: "😣" }
- ListElement { section: "smileys"; glyph: "😤" }
- ListElement { section: "smileys"; glyph: "😥" }
- ListElement { section: "smileys"; glyph: "😨" }
- ListElement { section: "smileys"; glyph: "😩" }
- ListElement { section: "smileys"; glyph: "😪" }
- ListElement { section: "smileys"; glyph: "😫" }
- ListElement { section: "smileys"; glyph: "😭" }
- ListElement { section: "smileys"; glyph: "😰" }
- ListElement { section: "smileys"; glyph: "😱" }
- ListElement { section: "smileys"; glyph: "😲" }
- ListElement { section: "smileys"; glyph: "😳" }
- ListElement { section: "smileys"; glyph: "😵" }
- ListElement { section: "smileys"; glyph: "😷" }
- ListElement { section: "smileys"; glyph: "😸" }
- ListElement { section: "smileys"; glyph: "😹" }
- ListElement { section: "smileys"; glyph: "😺" }
- ListElement { section: "smileys"; glyph: "😻" }
- ListElement { section: "smileys"; glyph: "😼" }
- ListElement { section: "smileys"; glyph: "😽" }
- ListElement { section: "smileys"; glyph: "😾" }
- ListElement { section: "smileys"; glyph: "😿" }
- ListElement { section: "smileys"; glyph: "🙀" }
- ListElement { section: "smileys"; glyph: "🙅" }
- ListElement { section: "smileys"; glyph: "🙆" }
- ListElement { section: "smileys"; glyph: "🙇" }
- ListElement { section: "smileys"; glyph: "🙈" }
- ListElement { section: "smileys"; glyph: "🙉" }
- ListElement { section: "smileys"; glyph: "🙊" }
- ListElement { section: "smileys"; glyph: "🙋" }
- ListElement { section: "smileys"; glyph: "🙌" }
- ListElement { section: "smileys"; glyph: "🙍" }
- ListElement { section: "smileys"; glyph: "🙎" }
- ListElement { section: "smileys"; glyph: "🙏" }
-
- ListElement { section: "Transport and map"; glyph: "🚀" }
- ListElement { section: "Transport and map"; glyph: "🚃" }
- ListElement { section: "Transport and map"; glyph: "🚀" }
- ListElement { section: "Transport and map"; glyph: "🚄" }
- ListElement { section: "Transport and map"; glyph: "🚅" }
- ListElement { section: "Transport and map"; glyph: "🚇" }
- ListElement { section: "Transport and map"; glyph: "🚉" }
- ListElement { section: "Transport and map"; glyph: "🚌" }
- ListElement { section: "Transport and map"; glyph: "🚏" }
- ListElement { section: "Transport and map"; glyph: "🚑" }
- ListElement { section: "Transport and map"; glyph: "🚒" }
- ListElement { section: "Transport and map"; glyph: "🚓" }
- ListElement { section: "Transport and map"; glyph: "🚕" }
- ListElement { section: "Transport and map"; glyph: "🚗" }
- ListElement { section: "Transport and map"; glyph: "🚙" }
- ListElement { section: "Transport and map"; glyph: "🚚" }
- ListElement { section: "Transport and map"; glyph: "🚢" }
- ListElement { section: "Transport and map"; glyph: "🚨" }
- ListElement { section: "Transport and map"; glyph: "🚩" }
- ListElement { section: "Transport and map"; glyph: "🚪" }
- ListElement { section: "Transport and map"; glyph: "🚫" }
- ListElement { section: "Transport and map"; glyph: "🚬" }
- ListElement { section: "Transport and map"; glyph: "🚭" }
- ListElement { section: "Transport and map"; glyph: "🚲" }
- ListElement { section: "Transport and map"; glyph: "🚶" }
- ListElement { section: "Transport and map"; glyph: "🚹" }
- ListElement { section: "Transport and map"; glyph: "🚺" }
- ListElement { section: "Transport and map"; glyph: "🚻" }
- ListElement { section: "Transport and map"; glyph: "🚼" }
- ListElement { section: "Transport and map"; glyph: "🚽" }
- ListElement { section: "Transport and map"; glyph: "🚾" }
- ListElement { section: "Transport and map"; glyph: "🛀" }
-
- ListElement { section: "Horoscope Signs"; glyph: "♈" }
- ListElement { section: "Horoscope Signs"; glyph: "♉" }
- ListElement { section: "Horoscope Signs"; glyph: "♊" }
- ListElement { section: "Horoscope Signs"; glyph: "♋" }
- ListElement { section: "Horoscope Signs"; glyph: "♌" }
- ListElement { section: "Horoscope Signs"; glyph: "♍" }
- ListElement { section: "Horoscope Signs"; glyph: "♎" }
- ListElement { section: "Horoscope Signs"; glyph: "♏" }
- ListElement { section: "Horoscope Signs"; glyph: "♐" }
- ListElement { section: "Horoscope Signs"; glyph: "♑" }
- ListElement { section: "Horoscope Signs"; glyph: "♒" }
- ListElement { section: "Horoscope Signs"; glyph: "♓" }
- }
- delegate: BackgroundItem {
- width: gridView.cellWidth
- height: gridView.cellHeight
- Label {
- anchors.centerIn: parent
- color: (highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
- font.pixelSize: Theme.fontSizeLarge
- text: glyph
- }
- onClicked: {
- var cursorPosition = toot.cursorPosition
- toot.text = toot.text.substring(
- 0, cursorPosition) + model.glyph + toot.text.substring(
- cursorPosition)
- toot.cursorPosition = cursorPosition + model.glyph.length
- emoticonsDialog.canAccept = true
- emoticonsDialog.accept()
- }
- }
- }
- }
- }
-}
diff --git a/qml/pages/ConversationPage.qml b/qml/pages/ConversationPage.qml
new file mode 100644
index 0000000..f641278
--- /dev/null
+++ b/qml/pages/ConversationPage.qml
@@ -0,0 +1,585 @@
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import harbour.tooterb.Uploader 1.0
+import "../lib/API.js" as Logic
+import "./components/"
+
+
+Page {
+ id: conversationPage
+
+ property ListModel suggestedModel
+ property ListModel mdl
+ property int tootMaxChar: 500
+ property bool bot: false //otherwise ReferenceError ProfileHeader.qml
+ property bool followed_by: false //otherwise ReferenceError ProfileHeader.qml
+ property bool locked: false //otherwise ReferenceError ProfileHeader.qml
+ property bool group: false //otherwise ReferenceError ProfileHeader.qml
+ property string type
+ property string username: ""
+ property string headerTitle: ""
+ property string suggestedUser: ""
+ property string status_id: ""
+ property string status_url: ""
+ property string status_uri: ""
+ property string status_link:
+ if (status_url === "") {
+ var test = status_uri.split("/")
+ console.log(status_uri)
+ console.log(JSON.stringify(test))
+ console.log(JSON.stringify(test.length))
+ if (test.length === 8 && (test[7] === "activity")) {
+ var urialt = status_uri.replace("activity", "")
+ status_link = urialt
+ }
+ else status_link = status_uri
+ } else status_link = status_url
+
+ allowedOrientations: Orientation.All
+ onSuggestedUserChanged: {
+ console.log(suggestedUser)
+ suggestedModel = Qt.createQmlObject( 'import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject' )
+ predictionList.visible = false
+ if (suggestedUser.length > 0) {
+ var msg = {
+ "action": 'accounts/search',
+ "method": 'GET',
+ "model": suggestedModel,
+ "mode": "append",
+ "params": [{
+ "name": "q",
+ "data": suggestedUser
+ }],
+ "conf": Logic.conf
+ }
+ worker.sendMessage(msg)
+ predictionList.visible = true
+ }
+ }
+
+ ListModel {
+ id: mediaModel
+ onCountChanged: {
+ btnAddImage.enabled = mediaModel.count < 4
+ }
+ }
+
+ WorkerScript {
+ id: worker
+ source: "../lib/Worker.js"
+ onMessage: { console.log(JSON.stringify(messageObject)) }
+ }
+
+ SilicaListView {
+ id: myList
+
+ header: PageHeader {
+ title: headerTitle // pageTitle pushed from MainPage.qml or VisualContainer.qml
+ }
+ clip: true
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: if (panel.open == true) {
+ panel.top
+ } else {
+ hiddenPanel.top
+ }
+ model: mdl
+ section {
+ property: 'section'
+ delegate: SectionHeader {
+ height: Theme.itemSizeExtraSmall
+ text: Format.formatDate(section, Formatter.DateMedium)
+ }
+ }
+ delegate: VisualContainer {}
+ onCountChanged: {
+ if (mdl)
+ for (var i = 0; i < mdl.count; i++) {
+ if (mdl.get(i).status_id === status_id) {
+ console.log(mdl.get(i).status_id)
+ positionViewAtIndex(i, ListView.Center)
+ }
+ }
+ }
+
+ PullDownMenu {
+ id: pulleyConversation
+ visible: type === "reply"
+
+ MenuItem {
+ text: qsTr("Open in Browser")
+ onClicked: {
+ Qt.openUrlExternally(status_link)
+ }
+ }
+
+ MenuItem {
+ //: Use the translation of "Copy Link" for a shorter PullDownMenu label
+ text: qsTr("Copy Link to Clipboard")
+ onClicked: Clipboard.text = status_link
+ }
+
+ MenuItem {
+ //: "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ text: !panel.open ? qsTr("Reply") : qsTr("Hide Reply")
+ visible: type == "reply"
+ onClicked: !panel.open ? panel.open = true : panel.open = false
+ }
+ }
+ }
+
+ Rectangle {
+ id: predictionList
+ visible: false
+ color: Theme.highlightDimmerColor
+ height: parent.height - panel.height - (Theme.paddingLarge * 4.5)
+ anchors {
+ left: panel.left
+ right: panel.right
+ bottom: panel.open == true ? panel.top : hiddenPanel.top
+ }
+
+ SilicaListView {
+ id: predictionResults
+ rotation: 180 // shows best matching result on the bottom
+ anchors.fill: parent
+ model: suggestedModel
+ clip: true
+ quickScroll: false
+ delegate: ItemUser {
+ rotation: 180
+ onClicked: {
+ var start = toot.cursorPosition
+ while (toot.text[start] !== "@" && start > 0) {
+ start--
+ }
+ textOperations.text = toot.text
+ textOperations.cursorPosition = toot.cursorPosition
+ textOperations.moveCursorSelection(start - 1, TextInput.SelectWords)
+ toot.text = textOperations.text.substring(0, textOperations.selectionStart)
+ + ' @'
+ + model.account_acct
+ + ' '
+ + textOperations.text.substring(textOperations.selectionEnd).trim()
+ toot.cursorPosition = toot.text.indexOf('@' + model.account_acct)
+ }
+ }
+ onCountChanged: {
+ if (count > 0) {
+ positionViewAtBeginning(suggestedModel.count - 1, ListView.Beginning)
+ }
+ }
+
+ VerticalScrollDecorator {}
+ }
+ }
+
+ DockedPanel {
+ id: panel
+ width: parent.width
+ height: progressBar.height + toot.height + (mediaModel.count ? uploadedImages.height : 0) + btnContentWarning.height + Theme.paddingMedium + (warningContent.visible ? warningContent.height : 0)
+ dock: Dock.Bottom
+ open: true
+
+ Rectangle {
+ id: progressBarBg
+ width: parent.width
+ height: progressBar.height
+ color: Theme.highlightBackgroundColor
+ opacity: 0.2
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: parent.top
+ }
+ }
+
+ Rectangle {
+ id: progressBar
+ width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0
+ height: Theme.itemSizeSmall * 0.05
+ color: Theme.highlightBackgroundColor
+ opacity: 0.7
+ anchors {
+ left: parent.left
+ top: parent.top
+ }
+ }
+
+ TextField {
+ id: warningContent
+ visible: false
+ height: visible ? implicitHeight : 0
+ autoScrollEnabled: true
+ labelVisible: false
+ font.pixelSize: Theme.fontSizeSmall
+ //: placeholderText in Toot content warning panel
+ placeholderText: qsTr("Write your warning here")
+ placeholderColor: palette.highlightColor
+ color: palette.highlightColor
+ horizontalAlignment: Text.AlignLeft
+ EnterKey.onClicked: {}
+ anchors {
+ top: parent.top
+ topMargin: Theme.paddingMedium
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ TextInput {
+ id: textOperations
+ visible: false
+ }
+
+ TextArea {
+ id: toot
+ autoScrollEnabled: true
+ labelVisible: false
+ //: placeholderText in Toot text panel
+ placeholderText: qsTr("What's on your mind?")
+ font.pixelSize: Theme.fontSizeSmall
+ text: username !== "" && (username.charAt(0) === '@'
+ || username.charAt(
+ 0) === '#') ? username + ' ' : ''
+ height: if (type !== "reply") {
+ isPortrait ? Math.max(conversationPage.height / 3, Math.min(conversationPage.height * 0.65, implicitHeight)) : Math.max(conversationPage.height / 2, Math.min(conversationPage.height * 0.65, implicitHeight))
+ }
+ else {
+ isPortrait ? Math.max(conversationPage.height / 4, Math.min(conversationPage.height * 0.65, implicitHeight)) : Math.max(conversationPage.height / 2.5, Math.min(conversationPage.height * 0.65, implicitHeight))
+ }
+ horizontalAlignment: Text.AlignLeft
+ anchors {
+ top: warningContent.bottom
+ topMargin: Theme.paddingMedium
+ left: parent.left
+ right: parent.right
+ rightMargin: Theme.paddingLarge * 2
+ }
+ EnterKey.onClicked: {}
+ onTextChanged: {
+ textOperations.text = toot.text
+ textOperations.cursorPosition = toot.cursorPosition
+ textOperations.selectWord()
+ textOperations.select(
+ textOperations.selectionStart ? textOperations.selectionStart - 1 : 0,
+ textOperations.selectionEnd)
+ console.log(toot.text.length)
+ suggestedUser = ""
+ if (textOperations.selectedText.charAt(0) === "@") {
+ suggestedUser = textOperations.selectedText.trim().substring(1)
+ }
+ }
+ }
+
+ IconButton {
+ id: btnSmileys
+
+ property string selection
+
+ opacity: 0.7
+ icon {
+ source: "../../qml/images/icon-m-emoji.svg?"
+ color: Theme.secondaryColor
+ width: Theme.iconSizeSmallPlus
+ fillMode: Image.PreserveAspectFit
+ }
+ anchors {
+ top: warningContent.bottom
+ bottom: bottom.top
+ right: parent.right
+ rightMargin: Theme.paddingSmall
+ }
+ onSelectionChanged: { console.log(selection) }
+ onClicked: pageStack.push(emojiDialog)
+ }
+
+ SilicaGridView {
+ id: uploadedImages
+ width: parent.width
+ anchors.top: bottom.toot
+ anchors.bottom: parent.bottom
+ height: mediaModel.count ? Theme.itemSizeExtraLarge : 0
+ model: mediaModel
+ cellWidth: uploadedImages.width / 4
+ cellHeight: isPortrait ? cellWidth : Theme.itemSizeExtraLarge
+ delegate: BackgroundItem {
+ id: myDelegate
+ width: uploadedImages.cellWidth
+ height: uploadedImages.cellHeight
+ RemorseItem {
+ id: remorse
+ cancelText: ""
+ }
+
+ Image {
+ anchors.fill: parent
+ fillMode: Image.PreserveAspectCrop
+ source: model.preview_url
+ }
+ onClicked: {
+ var idx = index
+ console.log(idx)
+ //mediaModel.remove(idx)
+ remorse.execute(myDelegate, "", function () {
+ mediaModel.remove(idx)
+ })
+ }
+ }
+ add: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 0
+ to: 1.0
+ duration: 800
+ }
+ }
+ remove: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 1.0
+ to: 0
+ duration: 800
+ }
+ }
+ displaced: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ duration: 800
+ easing.type: Easing.InOutBack
+ }
+ }
+ }
+
+ IconButton {
+ id: btnContentWarning
+ icon.source: "image://theme/icon-s-warning?" + ( pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor) )
+ onClicked: warningContent.visible = !warningContent.visible
+ anchors {
+ top: toot.bottom
+ topMargin: -Theme.paddingSmall * 1.5
+ left: parent.left
+ leftMargin: Theme.paddingMedium
+ }
+ }
+
+ IconButton {
+ id: btnAddImage
+ enabled: mediaModel.count < 4
+ icon.source: "image://theme/icon-s-attach?" + ( pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor) )
+ anchors {
+ top: toot.bottom
+ topMargin: -Theme.paddingSmall * 1.5
+ left: btnContentWarning.right
+ leftMargin: Theme.paddingSmall
+ }
+ onClicked: {
+ btnAddImage.enabled = false
+ var once = true
+ var imagePicker = pageStack.push("Sailfish.Pickers.ImagePickerPage", { "allowedOrientations": Orientation.All })
+ imagePicker.selectedContentChanged.connect(function () {
+ var imagePath = imagePicker.selectedContent
+ console.log(imagePath)
+ imageUploader.setUploadUrl(Logic.conf.instance + "/api/v1/media")
+ imageUploader.setFile(imagePath)
+ imageUploader.setAuthorizationHeader(Logic.conf.api_user_token)
+ imageUploader.upload()
+ })
+ }
+ }
+
+ ImageUploader {
+ id: imageUploader
+ onProgressChanged: {
+ console.log("progress " + progress)
+ uploadProgress.width = parent.width * progress
+ }
+ onSuccess: {
+ uploadProgress.width = 0
+ console.log(replyData)
+ mediaModel.append(JSON.parse(replyData))
+ }
+ onFailure: {
+ uploadProgress.width = 0
+ btnAddImage.enabled = true
+ console.log(status)
+ console.log(statusText)
+ }
+ }
+
+ ComboBox {
+ id: privacy
+ menu: ContextMenu {
+ MenuItem {
+ text: qsTr("Public")
+ }
+ MenuItem {
+ text: qsTr("Unlisted")
+ }
+ MenuItem {
+ text: qsTr("Followers-only")
+ }
+ MenuItem {
+ text: qsTr("Direct")
+ }
+ }
+ anchors {
+ top: toot.bottom
+ topMargin: -Theme.paddingSmall * 1.5
+ left: btnAddImage.right
+ right: btnSend.left
+ }
+ }
+
+ IconButton {
+ id: btnSend
+ icon.source: "image://theme/icon-m-send?" + (pressed ? Theme.highlightColor : Theme.primaryColor)
+ enabled: toot.text !== "" && toot.text.length < tootMaxChar && uploadProgress.width == 0
+ anchors {
+ top: toot.bottom
+ topMargin: -Theme.paddingSmall * 1.5
+ right: parent.right
+ rightMargin: Theme.paddingSmall
+ }
+ onClicked: {
+ var visibility = ["public", "unlisted", "private", "direct"]
+ var media_ids = []
+ for (var k = 0; k < mediaModel.count; k++) {
+ console.log(mediaModel.get(k).id)
+ media_ids.push(mediaModel.get(k).id)
+ }
+ var msg = {
+ "action": 'statuses',
+ "method": 'POST',
+ "model": mdl,
+ "mode": "append",
+ "params": {
+ "status": toot.text,
+ "visibility": visibility[privacy.currentIndex],
+ "media_ids": media_ids
+ },
+ "conf": Logic.conf
+ }
+ if (status_id)
+ msg.params['in_reply_to_id'] = (status_id) + ""
+
+ if (warningContent.visible && warningContent.text.length > 0) {
+ msg.params['sensitive'] = 1
+ msg.params['spoiler_text'] = warningContent.text
+ }
+
+ worker.sendMessage(msg)
+ warningContent.text = ""
+ toot.text = ""
+ mediaModel.clear()
+ sentBanner.showText(qsTr("Toot sent!"))
+ }
+ }
+
+ Rectangle {
+ id: uploadProgress
+ color: Theme.highlightBackgroundColor
+ height: Theme.itemSizeSmall * 0.05
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ toot.cursorPosition = toot.text.length
+ if (mdl.count > 0) {
+ var setIndex = 0
+ switch (mdl.get(0).status_visibility) {
+ case "unlisted":
+ setIndex = 1
+ break
+ case "private":
+ setIndex = 2
+ break
+ case "direct":
+ privacy.enabled = false
+ setIndex = 3
+ break
+ default:
+ privacy.enabled = true
+ setIndex = 0
+ }
+ privacy.currentIndex = setIndex
+ }
+
+ console.log(JSON.stringify())
+
+ worker.sendMessage({
+ "action": 'statuses/' + mdl.get(0).status_id + '/context',
+ "method": 'GET',
+ "model": mdl,
+ "params": { },
+ "conf": Logic.conf
+ })
+ }
+
+ BackgroundItem {
+ id: hiddenPanel
+ visible: !panel.open
+ height: Theme.paddingLarge * 0.7
+ width: parent.width
+ opacity: enabled ? 0.6 : 0.0
+ Behavior on opacity { FadeAnimator { duration: 400 } }
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ bottom: parent.bottom
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: panel.open = !panel.open
+ }
+
+ Rectangle {
+ id: hiddenPanelBackground
+ width: parent.width
+ height: parent.height
+ color: Theme.highlightBackgroundColor
+ opacity: 0.4
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ id: progressBarBackground
+ width: parent.width
+ height: progressBarHiddenPanel.height
+ color: Theme.highlightBackgroundColor
+ opacity: 0.2
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ Rectangle {
+ id: progressBarHiddenPanel
+ width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0
+ height: Theme.itemSizeSmall * 0.05
+ color: Theme.highlightBackgroundColor
+ opacity: 0.7
+ anchors {
+ top: parent.top
+ left: parent.left
+ }
+ }
+
+ }
+
+ EmojiSelect {
+ id: emojiDialog
+ }
+
+ InfoBanner {
+ id: sentBanner
+ }
+}
diff --git a/qml/pages/LoginPage.qml b/qml/pages/LoginPage.qml
index b1d2064..5227d13 100644
--- a/qml/pages/LoginPage.qml
+++ b/qml/pages/LoginPage.qml
@@ -1,33 +1,3 @@
-/*
- Copyright (C) 2013 Jolla Ltd.
- Contact: Thomas Perl
- All rights reserved.
-
- You may use this file under the terms of BSD license as follows:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Jolla Ltd nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
import QtQuick 2.0
import QtWebKit 3.0
import Sailfish.Silica 1.0
@@ -61,86 +31,82 @@ Page {
focus: true
label: qsTr("Enter a valid Mastodon instance URL")
text: "https://"
- placeholderText: "https://mastodon.social"
width: parent.width
validator: RegExpValidator { regExp: /^(ftp|http|https):\/\/[^ "]+$/ }
EnterKey.enabled: instance.acceptableInput;
EnterKey.highlighted: instance.acceptableInput;
EnterKey.iconSource: "image://theme/icon-m-accept"
EnterKey.onClicked: {
- Logic.api = new Logic.MastodonAPI({ instance: instance.text, api_user_token: "" });
+ Logic.api = Logic.mastodonAPI({ instance: instance.text, api_user_token: "" });
Logic.api.registerApplication("Tooter",
- 'http://localhost/harbour-tooter', // redirect uri, we will need this later on
- ["read", "write", "follow"], //scopes
- "http://grave-design.com/harbour-tooter", //website on the login screen
- function(data) {
+ 'http://localhost/harbour-tooter', // redirect uri, we will need this later on
+ ["read", "write", "follow"], //scopes
+ "http://grave-design.com/harbour-tooter", //website on the login screen
+ function(data) {
- console.log(data)
- var conf = JSON.parse(data)
- conf.instance = instance.text;
- conf.login = false;
+ console.log(data)
+ var conf = JSON.parse(data)
+ conf.instance = instance.text;
+ conf.login = false;
- /*conf['login'] = false;
- conf['mastodon_client_id'] = data['mastodon_client_id'];
- conf['mastodon_client_secret'] = data['mastodon_client_secret'];
- conf['mastodon_client_redirect_uri'] = data['mastodon_client_redirect_uri'];
- delete Logic.conf;*/
- Logic.conf = conf;
- console.log(JSON.stringify(conf))
- console.log(JSON.stringify(Logic.conf))
- // we got our application
+ /*conf['login'] = false;
+ conf['mastodon_client_id'] = data['mastodon_client_id'];
+ conf['mastodon_client_secret'] = data['mastodon_client_secret'];
+ conf['mastodon_client_redirect_uri'] = data['mastodon_client_redirect_uri'];
+ delete Logic.conf;*/
+ Logic.conf = conf;
+ console.log(JSON.stringify(conf))
+ console.log(JSON.stringify(Logic.conf))
+ // we got our application
- // our user to it!
- var url = Logic.api.generateAuthLink(Logic.conf["client_id"],
- Logic.conf["redirect_uri"],
- "code", // oauth method
- ["read", "write", "follow"] //scopes
- );
- console.log(url)
- webView.url = url
- webView.visible = true
- }
- );
+ // our user to it!
+ var url = Logic.api.generateAuthLink(Logic.conf["client_id"],
+ Logic.conf["redirect_uri"],
+ "code", // oauth method
+ ["read", "write", "follow"] //scopes
+ );
+ console.log(url)
+ webView.url = url
+ webView.visible = true
+ }
+ );
}
}
+
Label {
+ id: serviceDescr
+ text: qsTr("Mastodon is a free, open-source social network. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Pick a server that you trust — whichever you choose, you can interact with everyone else. Anyone can run their own Mastodon instance and participate in the social network seamlessly.")
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.highlightColor
+ wrapMode: Text.WordWrap
+ width: parent.width
anchors {
- left: parent.left
- right: parent.right
topMargin: Theme.paddingMedium
+ left: parent.left
leftMargin: Theme.horizontalPageMargin
+ right: parent.right
rightMargin: Theme.horizontalPageMargin
}
-
- width: parent.width
- wrapMode: Text.WordWrap
- color: Theme.highlightColor
- font.pixelSize: Theme.fontSizeExtraSmall
- text: qsTr("Mastodon is a free, open-source social network. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Pick a server that you trust — whichever you choose, you can interact with everyone else. Anyone can run their own Mastodon instance and participate in the social network seamlessly.")
}
-
-
}
-
}
SilicaWebView {
id: webView
visible: false
+ opacity: 0
anchors {
top: parent.top
left: parent.left
right: parent.right
bottom: parent.bottom
}
-
- opacity: 0
onLoadingChanged: {
console.log(url)
if (
(url+"").substr(0, 37) === 'http://localhost/harbour-tooter?code=' ||
(url+"").substr(0, 38) === 'https://localhost/harbour-tooter?code='
- ) {
+ ) {
visible = false;
var vars = {};
@@ -151,22 +117,22 @@ Page {
console.log(authCode)
Logic.api.getAccessTokenFromAuthCode(
- Logic.conf["client_id"],
- Logic.conf["client_secret"],
- Logic.conf["redirect_uri"],
- authCode,
- function(data) {
- // AAAND DATA CONTAINS OUR TOKEN!
- console.log(data)
- data = JSON.parse(data)
- console.log(JSON.stringify(data))
- console.log(JSON.stringify(data.access_token))
- Logic.conf["api_user_token"] = data.access_token
- Logic.conf["login"] = true;
- Logic.api.setConfig("api_user_token", Logic.conf["api_user_token"])
- pageStack.replace(Qt.resolvedUrl("MainPage.qml"), {})
- }
- )
+ Logic.conf["client_id"],
+ Logic.conf["client_secret"],
+ Logic.conf["redirect_uri"],
+ authCode,
+ function(data) {
+ // AAAND DATA CONTAINS OUR TOKEN!
+ console.log(data)
+ data = JSON.parse(data)
+ console.log(JSON.stringify(data))
+ console.log(JSON.stringify(data.access_token))
+ Logic.conf["api_user_token"] = data.access_token
+ Logic.conf["login"] = true;
+ Logic.api.setConfig("api_user_token", Logic.conf["api_user_token"])
+ pageStack.replace(Qt.resolvedUrl("MainPage.qml"), {})
+ }
+ )
}
@@ -185,6 +151,7 @@ Page {
}
FadeAnimation on opacity {}
+
PullDownMenu {
MenuItem {
text: qsTr("Reload")
@@ -193,4 +160,3 @@ Page {
}
}
}
-
diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml
index e273c23..0ce3be1 100644
--- a/qml/pages/MainPage.qml
+++ b/qml/pages/MainPage.qml
@@ -1,33 +1,3 @@
-/*
- Copyright (C) 2013 Jolla Ltd.
- Contact: Thomas Perl
- All rights reserved.
-
- You may use this file under the terms of BSD license as follows:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Jolla Ltd nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
import QtQuick 2.0
import Sailfish.Silica 1.0
import "../lib/API.js" as Logic
@@ -36,19 +6,21 @@ import "./components/"
Page {
id: mainPage
- property bool isFirstPage: true
- property bool isTablet: true; //Screen.sizeCategory >= Screen.Large
- // The effective value will be restricted by ApplicationWindow.allowedOrientations
+ property bool isFirstPage: true
+ property bool isTablet: true //Screen.sizeCategory >= Screen.Large
+
allowedOrientations: Orientation.All
+ // Docked Navigation panel
DockedPanel {
id: infoPanel
open: true
- width: mainPage.isPortrait ? parent.width : Theme.itemSizeLarge
- height: mainPage.isPortrait ? Theme.itemSizeLarge : parent.height
- dock: mainPage.isPortrait ? Dock.Bottom : Dock.Right
- Navigation {
+ width: isPortrait ? parent.width : Theme.itemSizeLarge
+ height: isPortrait ? Theme.itemSizeLarge : parent.height
+ dock: isPortrait ? Dock.Bottom : Dock.Right
+
+ NavigationPanel {
id: navigation
isPortrait: !mainPage.isPortrait
onSlideshowShow: {
@@ -60,66 +32,79 @@ Page {
VisualItemModel {
id: visualModel
- MyList{
- id: tlHome;
+
+ MyList {
+ id: tlHome
title: qsTr("Home")
type: "timelines/home"
mdl: Logic.modelTLhome
- width: parent.itemWidth
+ width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge
height: parent.itemHeight
- onOpenDrawer: infoPanel.open = setDrawer
+ onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true
}
- MyList{
- id: tlNotifications;
+
+ MyList {
+ id: tlNotifications
title: qsTr("Notifications")
type: "notifications"
notifier: true
mdl: Logic.modelTLnotifications
- width: parent.itemWidth
+ width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge
height: parent.itemHeight
- onOpenDrawer: infoPanel.open = setDrawer
+ onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true
}
- MyList{
- id: tlLocal;
+
+ MyList {
+ id: tlLocal
title: qsTr("Local")
type: "timelines/public?local=true"
//params: ["local", true]
mdl: Logic.modelTLlocal
- width: parent.itemWidth
+ width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge
height: parent.itemHeight
- onOpenDrawer: infoPanel.open = setDrawer
+ onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true
}
- MyList{
- id: tlPublic;
+
+ MyList {
+ id: tlPublic
title: qsTr("Federated")
type: "timelines/public"
mdl: Logic.modelTLpublic
- width: parent.itemWidth
+ width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge
height: parent.itemHeight
- onOpenDrawer: infoPanel.open = setDrawer
+ onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true
}
+
Item {
- id: tlSearch;
- width: parent.itemWidth
- height: parent.itemHeight
+ id: tlSearch
+
property ListModel mdl: ListModel {}
- property string search;
+ property string search
+
+ width: isPortrait ? parent.itemWidth : parent.itemWidth - Theme.itemSizeLarge
+ height: parent.itemHeight
onSearchChanged: {
console.log(search)
loader.sourceComponent = loading
- loader.sourceComponent = search.charAt(0) === "@" ? userListComponent : tagListComponent
+ if (search.charAt(0) === "@") {
+ loader.sourceComponent = userListComponent
+ } else if (search.charAt(0) === "#") {
+ loader.sourceComponent = tagListComponent
+ } else loader.sourceComponent = wordListComponent
}
Loader {
id: loader
anchors.fill: parent
}
+
Column {
id: headerContainer
width: tlSearch.width
PageHeader {
title: qsTr("Search")
}
+
SearchField {
id: searchField
width: parent.width
@@ -133,6 +118,7 @@ Page {
}
}
}
+
Component {
id: loading
BusyIndicator {
@@ -141,6 +127,7 @@ Page {
running: true
}
}
+
Component {
id: tagListComponent
MyList {
@@ -148,7 +135,7 @@ Page {
mdl: ListModel {}
width: parent.width
height: parent.height
- onOpenDrawer: infoPanel.open = setDrawer
+ onOpenDrawer: isPortrait ? infoPanel.open = setDrawer : infoPanel.open = true
anchors.fill: parent
currentIndex: -1 // otherwise currentItem will steal focus
header: Item {
@@ -165,6 +152,7 @@ Page {
}
}
}
+
Component {
id: userListComponent
MyList {
@@ -185,15 +173,24 @@ Page {
delegate: ItemUser {
onClicked: {
- pageStack.push(Qt.resolvedUrl("Profile.qml"), {
+ pageStack.push(Qt.resolvedUrl("ProfilePage.qml"), {
"display_name": model.account_display_name,
"username": model.account_acct,
"user_id": model.account_id,
"profileImage": model.account_avatar,
- "profileBackground": model.account_header
+ "profileBackground": model.account_header,
+ "note": model.account_note,
+ "url": model.account_url,
+ "followers_count": model.account_followers_count,
+ "following_count": model.account_following_count,
+ "statuses_count": model.account_statuses_count,
+ "locked": model.account_locked,
+ "bot": model.account_bot,
+ "group": model.account_group
})
}
}
+
Component.onCompleted: {
view2.type = "accounts/search"
view2.params = []
@@ -203,11 +200,33 @@ Page {
}
}
+ Component {
+ id: wordListComponent
+ MyList {
+ id: view3
+ mdl: ListModel {}
+ width: parent.width
+ height: parent.height
+ onOpenDrawer: infoPanel.open = setDrawer
+ anchors.fill: parent
+ currentIndex: -1 // otherwise currentItem will steal focus
+ header: Item {
+ id: header
+ width: headerContainer.width
+ height: headerContainer.height
+ Component.onCompleted: headerContainer.parent = header
+ }
+
+ delegate: VisualContainer
+ Component.onCompleted: {
+ view3.type = "timelines/tag/"+tlSearch.search
+ view3.loadData("append")
+ }
+ }
+ }
}
-
}
-
SlideshowView {
id: slideshow
width: parent.width
@@ -215,44 +234,41 @@ Page {
itemWidth: isTablet ? Math.round(parent.width) : parent.width
itemHeight: height
clip: true
+ model: visualModel
onCurrentIndexChanged: {
navigation.slideshowIndexChanged(currentIndex)
}
-
anchors {
fill: parent
- leftMargin: 0
top: parent.top
- topMargin: 0
- rightMargin: mainPage.isPortrait ? 0 : infoPanel.visibleSize
- bottomMargin: mainPage.isPortrait ? infoPanel.visibleSize : 0
+ rightMargin: isPortrait ? 0 : infoPanel.visibleSize
+ bottomMargin: isPortrait ? infoPanel.visibleSize : 0
}
- model: visualModel
Component.onCompleted: {
}
}
IconButton {
- anchors {
- right: (mainPage.isPortrait ? parent.right : infoPanel.left)
- bottom: (mainPage.isPortrait ? infoPanel.top : parent.bottom)
- margins: {
- left: Theme.paddingLarge
- bottom: Theme.paddingLarge
- }
- }
-
- id: newTweet
+ id: newToot
width: Theme.iconSizeLarge
height: width
visible: !isPortrait ? true : !infoPanel.open
icon.source: "image://theme/icon-l-add"
+ anchors {
+ right: (mainPage.isPortrait ? parent.right : infoPanel.left)
+ rightMargin: isPortrait ? Theme.paddingLarge : Theme.paddingLarge * 0.8
+ bottom: (mainPage.isPortrait ? infoPanel.top : parent.bottom)
+ bottomMargin: Theme.paddingLarge
+ }
onClicked: {
- pageStack.push(Qt.resolvedUrl("Conversation.qml"), {headerTitle: qsTr("New Toot"), type: "new"})
+ pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
+ headerTitle: qsTr("New Toot"),
+ type: "new"
+ })
}
}
- function onLinkActivated(href){
+ function onLinkActivated(href) {
var test = href.split("/")
console.log(href)
console.log(JSON.stringify(test))
@@ -268,11 +284,11 @@ Page {
navigation.navigateTo('search')
} else {
- Qt.openUrlExternally(href);
+ Qt.openUrlExternally(href)
}
}
+
Component.onCompleted: {
console.log("aaa")
}
}
-
diff --git a/qml/pages/Profile.qml b/qml/pages/Profile.qml
deleted file mode 100644
index 1d6692c..0000000
--- a/qml/pages/Profile.qml
+++ /dev/null
@@ -1,305 +0,0 @@
-import QtQuick 2.0
-import Sailfish.Silica 1.0
-import "../lib/API.js" as Logic
-import "./components/"
-import QtGraphicalEffects 1.0
-
-Page {
- property ListModel tweets;
- property string display_name : "";
- property string username : "";
- property string profileImage : "";
- property int user_id;
- property int statuses_count;
- property int following_count;
- property int followers_count;
- property int favourites_count;
- property int reblogs_count;
- property int count_moments;
- property string profileBackground: "";
- property string note: "";
- property string url: "";
- property bool locked : false;
- property date created_at;
- property bool following : false;
- property bool requested : false;
- property bool followed_by : false;
- property bool blocking : false;
- property bool muting : false;
- property bool domain_blocking : false;
-
-
- WorkerScript {
- id: worker
- source: "../lib/Worker.js"
- onMessage: {
- console.log(JSON.stringify(messageObject))
- if(messageObject.action.indexOf("accounts/search") > -1 ){
- user_id = messageObject.data.id
- followers_count = messageObject.data.followers_count
- following_count = messageObject.data.following_count
- username = messageObject.data.acct
- display_name = messageObject.data.display_name
- profileImage = messageObject.data.avatar_static
- profileBackground = messageObject.data.header_static
-
- var msg = {
- 'action' : "accounts/relationships/",
- 'params' : [ {name: "id", data: user_id}],
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- list.loadData("prepend")
- }
-
- if(messageObject.action === "accounts/relationships/"){
- console.log(JSON.stringify(messageObject))
- following= messageObject.data.following
- requested= messageObject.data.requested
- followed_by= messageObject.data.followed_by
- blocking= messageObject.data.blocking
- muting= messageObject.data.muting
- domain_blocking= messageObject.data.domain_blocking
- }
- switch (messageObject.key) {
- case 'followers_count':
- followers_count = messageObject.data
- break;
- case 'following_count':
- following_count = messageObject.data
- break;
- case 'acct':
- // line below was commented out, reason unknown
- // username = messageObject.data
- break;
- case 'locked':
- locked = messageObject.data
- break;
- case 'created_at':
- created_at = messageObject.data
- break;
- case 'statuses_count':
- statuses_count = messageObject.data
- break;
- case 'note':
- note = messageObject.data
- break;
- case 'url':
- url = messageObject.data
- break;
- case 'following':
- following = messageObject.data
- followers_count = followers_count + (following ? 1 : - 1)
- break;
- case 'muting':
- muting = messageObject.data
- break;
- case 'muting':
- muting = messageObject.data
- break;
- case 'blocking':
- blocking = messageObject.data
- followers_count = followers_count + (blocking ? -1 : 0)
- break;
- case 'followed_by':
- followed_by = messageObject.data
- break;
- }
- }
- }
- // The effective value will be restricted by ApplicationWindow.allowedOrientations
- allowedOrientations: Orientation.All
- Component.onCompleted: {
- var msg;
-
- if (user_id) {
- msg = {
- 'action' : "accounts/relationships/",
- 'params' : [ {name: "id", data: user_id}],
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- msg = {
- 'action' : "accounts/"+user_id,
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- } else {
- var instance = Logic.conf['instance'].split("//")
- msg = {
- 'action' : "accounts/search?limit=1&q="+username.replace("@"+instance[1], ""),
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- }
- }
-
-
- MyList {
- id: list
- header: ProfileHeader {
- id: header
- title: display_name
- description: username
- image: profileImage
- bg: profileBackground
- }
-
- anchors {
- top: parent.top
- bottom: expander.top
- left: parent.left
- right: parent.right
- }
- clip: true
-
- mdl: ListModel {}
- type: "accounts/"+user_id+"/statuses"
- vars: {}
- conf: Logic.conf
- }
-
- ExpandingSectionGroup {
- id: expander
- //currentIndex: 0
- anchors {
- bottom: parent.bottom
- left: parent.left
- right: parent.right
- }
- ExpandingSection {
- title: qsTr("Summary")
- content.sourceComponent: Column {
- spacing: Theme.paddingMedium
- anchors.bottomMargin: Theme.paddingLarge
- DetailItem {
- visible: followers_count ? true : false
- label: qsTr("Followers")
- value: followers_count
- }
- DetailItem {
- visible: following_count ? true : false
- label: qsTr("Following")
- value: (following_count)
- }
- DetailItem {
- visible: statuses_count ? true : false
- label: qsTr("Statuses")
- value: (statuses_count)
- }
- DetailItem {
- visible: favourites_count ? true : false
- label: qsTr("Favourites")
- value: (favourites_count)
- }
-
- Column {
- spacing: Theme.paddingMedium
- anchors.horizontalCenter: parent.horizontalCenter
- Button {
- id: btnFollow
- text: (following ? qsTr("Unfollow") : (requested ? qsTr("Follow request sent!") : qsTr("Follow")))
- onClicked: {
- var msg = {
- 'method' : 'POST',
- 'params' : [],
- 'action' : "accounts/" + user_id + (following ? '/unfollow':'/follow'),
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- }
- }
- Button {
- id: btnMute
- text: (muting ? qsTr("Unmute") : qsTr("Mute"))
- onClicked: {
- var msg = {
- 'method' : 'POST',
- 'params' : [],
- 'action' : "accounts/" + user_id + (muting ? '/unmute':'/mute'),
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- }
- }
- Button {
- id: btnBlock
- text: (blocking ? qsTr("Unblock") : qsTr("Block") )
- onClicked: {
- var msg = {
- 'method' : 'POST',
- 'params' : [],
- 'action' : "accounts/" + user_id + (blocking ? '/unblock':'/block'),
- 'conf' : Logic.conf
- };
- worker.sendMessage(msg);
- }
- }
- }
- Label {
- text: " "
- }
- }
-
- }
- ExpandingSection {
- title: qsTr("Bio")
- content.sourceComponent: Column {
- spacing: Theme.paddingMedium
- anchors.bottomMargin: Theme.paddingLarge
- Text {
- x: Theme.horizontalPageMargin
- width: parent.width - ( 2 * Theme.horizontalPageMargin )
- id: txtnote
- text: note
- font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.secondaryColor
- linkColor: Theme.secondaryHighlightColor
- wrapMode: Text.Wrap
- anchors {
- horizontalCenter: parent.horizontalCenter
- }
- onLinkActivated: {
- var test = link.split("/")
- console.log(link)
- console.log(JSON.stringify(test))
- console.log(JSON.stringify(test.length))
-
- if (test.length === 5 && (test[3] === "tags" || test[3] === "tag") ) {
- pageStack.pop(pageStack.find(function(page) {
- var check = page.isFirstPage === true;
- if (check)
- page.onLinkActivated(link)
- return check;
- }));
- send(link)
-
- // function still missing for user accounts
- // } else if (test.length === 4 && test[3][0] === "@" ) {
-
- } else {
- Qt.openUrlExternally(link);
- }
- }
-
- }
- Column {
- spacing: Theme.paddingMedium
- anchors.horizontalCenter: parent.horizontalCenter
- Button {
- text: qsTr("Open Profile in Browser")
- onClicked: {
- Qt.openUrlExternally(url);
- }
- }
- }
- Label {
- text: " "
- }
- }
- }
- }
-
-
-
-}
diff --git a/qml/pages/ProfilePage.qml b/qml/pages/ProfilePage.qml
new file mode 100644
index 0000000..efb5b21
--- /dev/null
+++ b/qml/pages/ProfilePage.qml
@@ -0,0 +1,360 @@
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import QtGraphicalEffects 1.0
+import "../lib/API.js" as Logic
+import "./components/"
+
+
+Page {
+ id: profilePage
+
+ property ListModel tweets
+ property string display_name: ""
+ property string username: ""
+ property string profileImage: ""
+ property string profileBackground: ""
+ property string note: ""
+ property string url: ""
+ property string user_id: ""
+ property int statuses_count
+ property int following_count
+ property int followers_count
+ property bool locked: false
+ property bool bot: false
+ property bool group: false
+ property bool following: false
+ property bool followed_by: false
+ property bool requested: false
+ property bool blocking: false
+ property bool muting: false
+ property bool domain_blocking: false
+ property date created_at
+
+ WorkerScript {
+ id: worker
+ source: "../lib/Worker.js"
+ onMessage: {
+ console.log(JSON.stringify(messageObject))
+ if(messageObject.action.indexOf("accounts/search") > -1 ){
+ user_id = messageObject.data.id
+ followers_count = messageObject.data.followers_count
+ following_count = messageObject.data.following_count
+ username = messageObject.data.acct
+ display_name = messageObject.data.display_name
+ profileImage = messageObject.data.avatar_static
+ profileBackground = messageObject.data.header_static
+
+ var msg = {
+ 'action' : "accounts/relationships/",
+ 'params' : [ {name: "id", data: user_id}],
+ 'conf' : Logic.conf
+ };
+ worker.sendMessage(msg);
+ list.loadData("prepend")
+ }
+
+ if(messageObject.action === "accounts/relationships/"){
+ console.log(JSON.stringify(messageObject))
+ following = messageObject.data.following
+ requested = messageObject.data.requested
+ followed_by = messageObject.data.followed_by
+ blocking = messageObject.data.blocking
+ muting = messageObject.data.muting
+ domain_blocking = messageObject.data.domain_blocking
+ }
+ switch (messageObject.key) {
+ case 'followers_count':
+ followers_count = messageObject.data
+ break;
+ case 'following_count':
+ following_count = messageObject.data
+ break;
+ /* case 'acct':
+ username = messageObject.data
+ break; */
+ case 'created_at':
+ created_at = messageObject.data
+ break;
+ case 'statuses_count':
+ statuses_count = messageObject.data
+ break;
+ case 'note':
+ note = messageObject.data
+ break;
+ case 'url':
+ url = messageObject.data
+ break;
+ case 'following':
+ following = messageObject.data
+ followers_count = followers_count + (following ? 1 : - 1)
+ break;
+ case 'muting':
+ muting = messageObject.data
+ break;
+ case 'blocking':
+ blocking = messageObject.data
+ // followers_count = followers_count + (blocking ? -1 : 0)
+ break;
+ }
+ }
+ }
+
+ // The effective value will be restricted by ApplicationWindow.allowedOrientations
+ allowedOrientations: Orientation.All
+ Component.onCompleted: {
+ var msg
+
+ if (user_id) {
+ msg = {
+ 'action' : "accounts/relationships/",
+ 'params' : [ {name: "id", data: user_id} ],
+ 'conf' : Logic.conf
+ }
+ worker.sendMessage(msg)
+
+ } else {
+ var instance = Logic.conf['instance'].split("//")
+ msg = {
+ 'action' : "accounts/search?limit=1&q="+username.replace("@"+instance[1], ""),
+ 'conf' : Logic.conf
+ }
+ worker.sendMessage(msg)
+ }
+ }
+
+ MyList {
+ id: list
+ header: ProfileHeader {
+ id: profileHeader
+ title: display_name
+ description: username
+ image: profileImage
+ bg: profileBackground
+ }
+ clip: true
+ mdl: ListModel {}
+ type: "accounts/"+user_id+"/statuses"
+ vars: {}
+ conf: Logic.conf
+ anchors {
+ top: parent.top
+ bottom: profileExpander.top
+ left: parent.left
+ right: parent.right
+ }
+ }
+
+ // ProfilePage ExpandingSection
+ ExpandingSectionGroup {
+ id: profileExpander
+ anchors.bottom: parent.bottom
+
+ ExpandingSection {
+ id: expandingSection1
+ title:
+ //: If there's no good translation for "About", use "Details" (in details about profile).
+ qsTr("About")
+ content.sourceComponent: Column {
+ spacing: Theme.paddingLarge
+
+ Item {
+ id: txtContainer
+ width: parent.width
+ height: profilePage.isPortrait ? Math.min( txtNote.height, parent.height * 0.5 ) : Math.min( txtNote.height, parent.height * 0.2 )
+ visible: {
+ if ((note.text === "") || ( note.text === "" )) {
+ false
+ } else {
+ true
+ }
+ }
+
+ SilicaFlickable {
+ id: txtFlickable
+ contentWidth: parent.width
+ contentHeight: txtNote.height
+ anchors.fill: parent
+ clip: true
+
+ VerticalScrollDecorator {}
+
+ Label {
+ id: txtNote
+ text: note
+ textFormat: Text.StyledText
+ color: Theme.secondaryHighlightColor
+ font.pixelSize: Theme.fontSizeExtraSmall
+ linkColor: Theme.secondaryColor
+ wrapMode: Text.Wrap
+ width: parent.width - ( 2 * Theme.horizontalPageMargin )
+ anchors.horizontalCenter: parent.horizontalCenter
+ onLinkActivated: {
+ var test = link.split("/")
+ console.log(link)
+ console.log(JSON.stringify(test))
+ console.log(JSON.stringify(test.length))
+ if (test.length === 5 && (test[3] === "tags" || test[3] === "tag") ) {
+ pageStack.pop(pageStack.find(function(page) {
+ var check = page.isFirstPage === true;
+ if (check)
+ page.onLinkActivated(link)
+ return check;
+ }));
+ send(link)
+ } else if (test.length === 4 && test[3][0] === "@" ) {
+ pageStack.pop(pageStack.find(function(page) {
+ var check = page.isFirstPage === true;
+ if (check)
+ page.onLinkActivated(link)
+ return check;
+ }));
+ } else {
+ Qt.openUrlExternally(link);
+ }
+ }
+ }
+ }
+ }
+
+ Item { // dummy item for spacing
+ height: Theme.paddingSmall
+ }
+
+ Row {
+ id: statsRow
+ spacing: Theme.paddingLarge
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.leftMargin: Theme.paddingLarge
+ anchors.rightMargin: Theme.paddingLarge
+
+ Label {
+ id: txtFollowers
+ visible: true //followers_count ? true : false
+ text: followers_count+" "+
+ //: Will show as: "35 Followers"
+ qsTr("Followers")
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.primaryColor
+ wrapMode: Text.Wrap
+ }
+
+ Label {
+ id: txtFollowing
+ visible: true //following_count ? true : false
+ text: following_count+" "+
+ //: Will show as: "23 Following"
+ qsTr("Following")
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.primaryColor
+ wrapMode: Text.Wrap
+ }
+
+ Label {
+ id: txtStatuses
+ visible: true //statuses_count ? true : false
+ text: statuses_count+" "+
+ //: Will show as: "115 Statuses"
+ qsTr("Statuses")
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: pressed ? Theme.highlightColor : Theme.primaryColor
+ wrapMode: Text.Wrap
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: expandingSection1.expanded = false
+ }
+
+ }
+ }
+
+ Item { // dummy item for spacing
+ height: Theme.paddingSmall
+ }
+
+ ButtonLayout {
+ id: btnLayout
+ Button {
+ id: btnMention
+ preferredWidth: Theme.buttonWidthSmall
+ text: qsTr("Mention")
+ onClicked: {
+ pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
+ headerTitle: qsTr("Mention"),
+ description: "@"+username,
+ type: "new"
+ })
+ }
+ }
+
+ Button {
+ id: btnFollow
+ preferredWidth: Theme.buttonWidthSmall
+ text: (following ?
+ //: Is a button. Keep it as short as possible.
+ qsTr("Unfollow") : (requested ?
+ //: Is a button. Keep it as short as possible.
+ qsTr("Requested") :
+ //: Is a button. Keep it as short as possible.
+ qsTr("Follow")))
+ color: (following ? highlightColor : (requested ? palette.errorColor : palette.primaryColor))
+ onClicked: {
+ var msg = {
+ 'method' : 'POST',
+ 'params' : [],
+ 'action' : "accounts/" + user_id + (following ? '/unfollow':'/follow'),
+ 'conf' : Logic.conf
+ };
+ worker.sendMessage(msg);
+ }
+ }
+
+ Button {
+ id: btnMute
+ preferredWidth: Theme.buttonWidthSmall
+ text: (muting ?
+ //: Is a button. Keep it as short as possible.
+ qsTr("Unmute") :
+ //: Is a button. Keep it as short as possible.
+ qsTr("Mute"))
+ color: (muting ? palette.errorColor : palette.primaryColor)
+ onClicked: {
+ var msg = {
+ 'method' : 'POST',
+ 'params' : [],
+ 'action' : "accounts/" + user_id + (muting ? '/unmute':'/mute'),
+ 'conf' : Logic.conf
+ };
+ worker.sendMessage(msg);
+ }
+ }
+
+ Button {
+ id: btnBlock
+ preferredWidth: Theme.buttonWidthSmall
+ text: (blocking ?
+ //: Is a button. Keep it as short as possible.
+ qsTr("Unblock") :
+ //: Is a button. Keep it as short as possible.
+ qsTr("Block") )
+ color: (blocking ? palette.errorColor : palette.primaryColor)
+ onClicked: {
+ var msg = {
+ 'method' : 'POST',
+ 'params' : [],
+ 'action' : "accounts/" + user_id + (blocking ? '/unblock':'/block'),
+ 'conf' : Logic.conf
+ }
+ worker.sendMessage(msg)
+ }
+ }
+ }
+
+ Rectangle { // dummy item for spacing
+ height: Theme.paddingSmall
+ width: parent.width
+ opacity: 0
+ }
+ }
+ }
+ }
+}
diff --git a/qml/pages/Settings.qml b/qml/pages/Settings.qml
deleted file mode 100644
index 88a3651..0000000
--- a/qml/pages/Settings.qml
+++ /dev/null
@@ -1,200 +0,0 @@
-import QtQuick 2.0
-import Sailfish.Silica 1.0
-import "../lib/API.js" as Logic
-
-Page {
- SilicaFlickable {
- anchors.fill: parent
- contentHeight: column.height + Theme.paddingLarge
- contentWidth: parent.width
- RemorsePopup { id: remorsePopup }
-
-
- VerticalScrollDecorator {}
- Column {
- id: column
- spacing: Theme.paddingSmall
- width: parent.width
- PageHeader {
- title: qsTr("Settings")
- }
- Column {
- // No spacing in this column
- width: parent.width
- IconTextSwitch {
- id: removeAccount
- text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account")
- description: Logic.conf['login'] ? qsTr("Deauthorize this app and remove your account") : qsTr("Authorize this app to access your Mastodon account")
- icon.source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add"
-
-
- onCheckedChanged: {
- remorsePopup.execute(removeAccount.text, function() {
- busy = true;
- checked = false;
- timer1.start();
- if (Logic.conf['login']) {
- Logic.conf['login'] = false
- Logic.conf['instance'] = null;
- Logic.conf['api_user_token'] = null;
- }
- pageStack.push(Qt.resolvedUrl("LoginPage.qml"))
- })
- }
-
- /* busy = true;
- checked = false;
- timer1.start()
-
- }*/
- Timer {
- id: timer1
- interval: 4700
- onTriggered: parent.busy = false
- }
- }
- IconTextSwitch {
- //enabled: false
- checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages']
- text: qsTr("Load images in toots")
- description: qsTr("Disable this option if you want to preserve your data connection")
- icon.source: "image://theme/icon-m-image"
- onClicked: {
- Logic.conf['loadImages'] = checked
- }
- }
- IconTextSwitch {
- text: qsTr("Translate")
- description: qsTr("Use Transifex to help with app translation to your language")
- icon.source: "image://theme/icon-m-font-size"
- onCheckedChanged: {
- busy = true;
- checked = false;
- Qt.openUrlExternally("https://www.transifex.com/dysko/tooter/");
- timer2.start()
- }
- Timer {
- id: timer2
- interval: 4700
- onTriggered: parent.busy = false
- }
- }
- }
- SectionHeader {
- text: qsTr("Credits")
- }
-
- Column {
- width: parent.width
- anchors {
- left: parent.left
- right: parent.right
- rightMargin: Theme.horizontalPageMargin
- }
- Repeater {
- model: ListModel {
- ListElement {
- name: "Duško Angirević"
- desc: qsTr("UI/UX design and development")
- mastodon: "dysko@mastodon.social"
- mail: ""
- }
- ListElement {
- name: "Miodrag Nikolić"
- desc: qsTr("Visual identity")
- mastodon: ""
- mail: "micotakis@gmail.com"
- }
- ListElement {
- name: "Molan"
- desc: qsTr("Development and translations")
- mastodon: ""
- mail: "mol_an@sunrise.ch"
- }
- ListElement {
- name: "Quentin PAGÈS / Quenti ♏"
- desc: qsTr("Occitan & French translation")
- mastodon: "Quenti@framapiaf.org"
- mail: ""
- }
- ListElement {
- name: "Luchy Kon / dashinfantry"
- desc: qsTr("Chinese translation")
- mastodon: ""
- mail: "dashinfantry@gmail.com"
- }
- ListElement {
- name: "André Koot"
- desc: qsTr("Dutch translation")
- mastodon: "meneer@mastodon.social"
- mail: "https://twitter.com/meneer"
- }
- ListElement {
- name: "CarmenFdez"
- desc: qsTr("Spanish translation")
- mastodon: ""
- mail: ""
- }
- ListElement {
- name: "Mohamed-Touhami MAHDI"
- desc: qsTr("Added README file")
- mastodon: "dragnucs@touha.me"
- mail: "touhami@touha.me"
- }
- }
-
- Item {
- width: parent.width
- height: Theme.itemSizeMedium
- IconButton {
- id: btn
- anchors {
- verticalCenter: parent.verticalCenter
- right: parent.right
- }
- icon.source: "image://theme/" + (model.mastodon !== "" ? "icon-m-contact" : "icon-m-mail") + "?" + (pressed
- ? Theme.highlightColor
- : Theme.primaryColor)
- onClicked: {
- if (model.mastodon !== ""){
- var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
- pageStack.push(Qt.resolvedUrl("Conversation.qml"), {
- toot_id: 0,
- title: model.name,
- description: '@'+model.mastodon,
- avatar: "",
- mdl: m,
- type: "reply"
- })
- } else {
- Qt.openUrlExternally("mailto:"+model.mail);
- }
- }
- }
- Column {
- anchors {
- verticalCenter: parent.verticalCenter
- left: parent.left
- leftMargin: Theme.horizontalPageMargin
- right: btn.left
- rightMargin: Theme.paddingMedium
- }
-
- Label {
- id: lblName
- text: model.name
- color: Theme.secondaryColor
- font.pixelSize: Theme.fontSizeSmall
- }
- Label {
- text: model.desc
- color: Theme.secondaryHighlightColor
- font.pixelSize: Theme.fontSizeExtraSmall
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml
new file mode 100644
index 0000000..ea9277b
--- /dev/null
+++ b/qml/pages/SettingsPage.qml
@@ -0,0 +1,246 @@
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import "../lib/API.js" as Logic
+
+
+Page {
+ id: settingsPage
+ allowedOrientations: Orientation.All
+
+ SilicaFlickable {
+ contentHeight: column.height + Theme.paddingLarge
+ contentWidth: parent.width
+ anchors.fill: parent
+
+ RemorsePopup { id: remorsePopup }
+
+ VerticalScrollDecorator {}
+
+ Column {
+ id: column
+ spacing: Theme.paddingMedium
+ width: parent.width
+
+ PageHeader {
+ title: qsTr("Settings")
+ }
+
+ SectionHeader { text: qsTr("Options")}
+
+ IconTextSwitch {
+ text: qsTr("Load Images in Toots")
+ description: qsTr("Disable this option if you want to preserve your data connection")
+ icon.source: "image://theme/icon-m-image"
+ checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages']
+ onClicked: {
+ Logic.conf['loadImages'] = checked
+ }
+ }
+
+ SectionHeader { text: qsTr("Account") }
+
+ Item {
+ id: removeAccount
+ width: parent.width
+ height: txtRemoveAccount.height + btnRemoveAccount.height + Theme.paddingLarge
+ anchors {
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin
+ right: parent.right
+ rightMargin: Theme.paddingLarge
+ }
+
+ Icon {
+ id: icnRemoveAccount
+ color: Theme.highlightColor
+ width: Theme.iconSizeMedium
+ fillMode: Image.PreserveAspectFit
+ source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add"
+ anchors.right: parent.right
+ }
+
+ Column {
+ id: clnRemoveAccount
+ spacing: Theme.paddingMedium
+ anchors {
+ left: parent.left
+ right: icnRemoveAccount.left
+ }
+
+ Button {
+ id: btnRemoveAccount
+ text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account")
+ preferredWidth: Theme.buttonWidthMedium
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: {
+ remorsePopup.execute(btnRemoveAccount.text, function() {
+ if (Logic.conf['login']) {
+ Logic.conf['login'] = false
+ Logic.conf['instance'] = null;
+ Logic.conf['api_user_token'] = null;
+ }
+ pageStack.push(Qt.resolvedUrl("LoginPage.qml"))
+ })
+ }
+
+ Timer {
+ id: timer1
+ interval: 4700
+ onTriggered: parent.busy = false
+ }
+ }
+
+ Label {
+ id: txtRemoveAccount
+ text: Logic.conf['login'] ? qsTr("Deauthorize this app from using your account and remove account data from phone") : qsTr("Authorize this app to access your Mastodon account")
+ font.pixelSize: Theme.fontSizeExtraSmall
+ wrapMode: Text.Wrap
+ color: Theme.highlightColor
+ width: parent.width - Theme.paddingMedium
+ anchors.left: parent.left
+ }
+ }
+ }
+
+ SectionHeader {
+ text: qsTr("Translate")
+ }
+
+ LinkedLabel {
+ id: translateLbl
+ //: Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ text: qsTr("Use")+" "+"Transifex"+" "+qsTr("to help with app translation to your language.")
+ textFormat: Text.StyledText
+ color: Theme.highlightColor
+ linkColor: Theme.primaryColor
+ font.family: Theme.fontFamilyHeading
+ font.pixelSize: Theme.fontSizeExtraSmall
+ wrapMode: Text.Wrap
+ anchors {
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin
+ right: parent.right
+ rightMargin: Theme.paddingLarge
+ }
+ }
+
+ SectionHeader {
+ //: Translation alternative: "Development"
+ text: qsTr("Credits")
+ }
+
+ Column {
+ width: parent.width
+ anchors {
+ left: parent.left
+ right: parent.right
+ rightMargin: Theme.paddingLarge
+ }
+
+ Repeater {
+ model: ListModel {
+
+ ListElement {
+ name: "Duško Angirević"
+ desc: qsTr("UI/UX design and development")
+ mastodon: "dysko@mastodon.social"
+ mail: ""
+ }
+
+ ListElement {
+ name: "Molan"
+ desc: qsTr("Development and translations")
+ mastodon: "molan@fosstodon.org"
+ mail: ""
+ }
+
+ ListElement {
+ name: "Miodrag Nikolić"
+ desc: qsTr("Visual identity")
+ mastodon: ""
+ mail: "micotakis@gmail.com"
+ }
+
+ ListElement {
+ name: "Quentin PAGÈS / Quenti ♏"
+ desc: qsTr("Occitan & French translation")
+ mastodon: "Quenti@framapiaf.org"
+ mail: ""
+ }
+
+ ListElement {
+ name: "Luchy Kon / dashinfantry"
+ desc: qsTr("Chinese translation")
+ mastodon: ""
+ mail: "dashinfantry@gmail.com"
+ }
+
+ ListElement {
+ name: "André Koot"
+ desc: qsTr("Dutch translation")
+ mastodon: "meneer@mastodon.social"
+ mail: "https://twitter.com/meneer"
+ }
+
+ ListElement {
+ name: "CarmenFdez"
+ desc: qsTr("Spanish translation")
+ mastodon: ""
+ mail: ""
+ }
+ }
+
+ Item {
+ width: parent.width
+ height: Theme.itemSizeMedium
+
+ IconButton {
+ id: btn
+ icon.source: "image://theme/" + (model.mastodon !== "" ? "icon-m-outline-chat" : "icon-m-mail") + "?" + (pressed
+ ? Theme.highlightColor : Theme.primaryColor)
+ anchors {
+ verticalCenter: parent.verticalCenter
+ right: parent.right
+ }
+ onClicked: {
+ if (model.mastodon !== ""){
+ var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
+ pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
+ headerTitle: "Mention",
+ description: '@'+model.mastodon,
+ type: "new"
+ })
+ } else {
+ Qt.openUrlExternally("mailto:"+model.mail);
+ }
+ }
+ }
+
+ Column {
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin
+ right: btn.left
+ rightMargin: Theme.paddingMedium
+ }
+
+ Label {
+ id: lblName
+ text: model.name
+ color: Theme.highlightColor
+ font.pixelSize: Theme.fontSizeSmall
+ }
+
+ Label {
+ text: model.desc
+ color: Theme.secondaryHighlightColor
+ font.pixelSize: Theme.fontSizeExtraSmall
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/qml/pages/components/EmojiSelect.qml b/qml/pages/components/EmojiSelect.qml
new file mode 100644
index 0000000..7e808e2
--- /dev/null
+++ b/qml/pages/components/EmojiSelect.qml
@@ -0,0 +1,270 @@
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+
+
+Dialog {
+ id: emojiDialog
+ allowedOrientations: Orientation.All
+ canAccept: false //selector.currentIndex >= 0
+ onAcceptPendingChanged: {
+ if (acceptPending) {
+ // Tell the destination page what the selected category is
+ // acceptDestinationInstance.category = selector.value
+ }
+ }
+ anchors.top: parent.top
+
+ Column {
+ id: emojiColumn
+ spacing: Theme.paddingLarge
+ width: parent.width
+ height: parent.height
+
+ SilicaGridView {
+ id: gridView
+ header: PageHeader {
+ title: qsTr("Emojis")
+ description: qsTr("Tap to insert")
+ }
+ cellWidth: isPortrait ? gridView.width / 6 : gridView.width / 10
+ cellHeight: cellWidth
+ width: parent.width
+ height: parent.height
+ model: ListModel {
+ ListElement { section: "Smileys"; glyph: "😄" }
+ ListElement { section: "Smileys"; glyph: "😃" }
+ ListElement { section: "Smileys"; glyph: "😀" }
+ ListElement { section: "Smileys"; glyph: "😊" }
+ ListElement { section: "Smileys"; glyph: "☺" }
+ ListElement { section: "Smileys"; glyph: "😉" }
+ ListElement { section: "Smileys"; glyph: "😍" }
+ ListElement { section: "Smileys"; glyph: "😘" }
+ ListElement { section: "Smileys"; glyph: "😚" }
+ ListElement { section: "Smileys"; glyph: "😗" }
+ ListElement { section: "Smileys"; glyph: "😙" }
+ ListElement { section: "Smileys"; glyph: "😜" }
+ ListElement { section: "Smileys"; glyph: "😝" }
+ ListElement { section: "Smileys"; glyph: "😛" }
+ ListElement { section: "Smileys"; glyph: "😳" }
+ ListElement { section: "Smileys"; glyph: "😁" }
+ ListElement { section: "Smileys"; glyph: "😔" }
+ ListElement { section: "Smileys"; glyph: "😌" }
+ ListElement { section: "Smileys"; glyph: "😒" }
+ ListElement { section: "Smileys"; glyph: "😞" }
+ ListElement { section: "Smileys"; glyph: "😣" }
+ ListElement { section: "Smileys"; glyph: "😢" }
+ ListElement { section: "Smileys"; glyph: "😂" }
+ ListElement { section: "Smileys"; glyph: "😭" }
+ ListElement { section: "Smileys"; glyph: "😪" }
+ ListElement { section: "Smileys"; glyph: "😥" }
+ ListElement { section: "Smileys"; glyph: "😰" }
+ ListElement { section: "Smileys"; glyph: "😅" }
+ ListElement { section: "Smileys"; glyph: "😩" }
+ ListElement { section: "Smileys"; glyph: "😫" }
+ ListElement { section: "Smileys"; glyph: "😨" }
+ ListElement { section: "Smileys"; glyph: "😱" }
+ ListElement { section: "Smileys"; glyph: "😠" }
+ ListElement { section: "Smileys"; glyph: "😡" }
+ ListElement { section: "Smileys"; glyph: "😤" }
+ ListElement { section: "Smileys"; glyph: "😖" }
+ ListElement { section: "Smileys"; glyph: "😆" }
+ ListElement { section: "Smileys"; glyph: "😋" }
+ ListElement { section: "Smileys"; glyph: "😷" }
+ ListElement { section: "Smileys"; glyph: "😎" }
+ ListElement { section: "Smileys"; glyph: "😴" }
+ ListElement { section: "Smileys"; glyph: "😵" }
+ ListElement { section: "Smileys"; glyph: "😲" }
+ ListElement { section: "Smileys"; glyph: "😟" }
+ ListElement { section: "Smileys"; glyph: "😦" }
+ ListElement { section: "Smileys"; glyph: "😧" }
+ ListElement { section: "Smileys"; glyph: "😈" }
+ ListElement { section: "Smileys"; glyph: "👿" }
+ ListElement { section: "Smileys"; glyph: "😮" }
+ ListElement { section: "Smileys"; glyph: "😬" }
+ ListElement { section: "Smileys"; glyph: "😐" }
+ ListElement { section: "Smileys"; glyph: "😕" }
+ ListElement { section: "Smileys"; glyph: "😯" }
+ ListElement { section: "Smileys"; glyph: "😶" }
+ ListElement { section: "Smileys"; glyph: "😇" }
+ ListElement { section: "Smileys"; glyph: "😏" }
+ ListElement { section: "Smileys"; glyph: "😑" }
+
+ ListElement { section: "Cat Faces"; glyph: "😺" }
+ ListElement { section: "Cat Faces"; glyph: "😸" }
+ ListElement { section: "Cat Faces"; glyph: "😻" }
+ ListElement { section: "Cat Faces"; glyph: "😽" }
+ ListElement { section: "Cat Faces"; glyph: "😼" }
+ ListElement { section: "Cat Faces"; glyph: "🙀" }
+ ListElement { section: "Cat Faces"; glyph: "😿" }
+ ListElement { section: "Cat Faces"; glyph: "😹" }
+ ListElement { section: "Cat Faces"; glyph: "😾" }
+
+ ListElement { section: "Other Faces"; glyph: "👹" }
+ ListElement { section: "Other Faces"; glyph: "👺" }
+ ListElement { section: "Other Faces"; glyph: "🙈" }
+ ListElement { section: "Other Faces"; glyph: "🙉" }
+ ListElement { section: "Other Faces"; glyph: "🙊" }
+ ListElement { section: "Other Faces"; glyph: "💀" }
+ ListElement { section: "Other Faces"; glyph: "👽" }
+
+ ListElement { section: "Misc Emoji"; glyph: "🔥" }
+ ListElement { section: "Misc Emoji"; glyph: "✨" }
+ ListElement { section: "Misc Emoji"; glyph: "🌟" }
+ ListElement { section: "Misc Emoji"; glyph: "💫" }
+ ListElement { section: "Misc Emoji"; glyph: "💥" }
+ ListElement { section: "Misc Emoji"; glyph: "💢" }
+ ListElement { section: "Misc Emoji"; glyph: "💦" }
+ ListElement { section: "Misc Emoji"; glyph: "💧" }
+ ListElement { section: "Misc Emoji"; glyph: "💤" }
+ ListElement { section: "Misc Emoji"; glyph: "💨" }
+ ListElement { section: "Misc Emoji"; glyph: "👂" }
+ ListElement { section: "Misc Emoji"; glyph: "👀" }
+ ListElement { section: "Misc Emoji"; glyph: "👃" }
+ ListElement { section: "Misc Emoji"; glyph: "👅" }
+ ListElement { section: "Misc Emoji"; glyph: "👄" }
+ ListElement { section: "Misc Emoji"; glyph: "👍" }
+ ListElement { section: "Misc Emoji"; glyph: "👎" }
+ ListElement { section: "Misc Emoji"; glyph: "👌" }
+ ListElement { section: "Misc Emoji"; glyph: "👊" }
+ ListElement { section: "Misc Emoji"; glyph: "✊" }
+ ListElement { section: "Misc Emoji"; glyph: "✌" }
+ ListElement { section: "Misc Emoji"; glyph: "👋" }
+ ListElement { section: "Misc Emoji"; glyph: "✋" }
+ ListElement { section: "Misc Emoji"; glyph: "👐" }
+ ListElement { section: "Misc Emoji"; glyph: "👆" }
+ ListElement { section: "Misc Emoji"; glyph: "👇" }
+ ListElement { section: "Misc Emoji"; glyph: "👉" }
+ ListElement { section: "Misc Emoji"; glyph: "👈" }
+ ListElement { section: "Misc Emoji"; glyph: "🙌" }
+ ListElement { section: "Misc Emoji"; glyph: "🙏" }
+ ListElement { section: "Misc Emoji"; glyph: "☝" }
+ ListElement { section: "Misc Emoji"; glyph: "👏" }
+ ListElement { section: "Misc Emoji"; glyph: "💪" }
+
+ ListElement { section: "Animals Emoji"; glyph: "🐶" }
+ ListElement { section: "Animals Emoji"; glyph: "🐺" }
+ ListElement { section: "Animals Emoji"; glyph: "🐱" }
+ ListElement { section: "Animals Emoji"; glyph: "🐭" }
+ ListElement { section: "Animals Emoji"; glyph: "🐹" }
+ ListElement { section: "Animals Emoji"; glyph: "🐰" }
+ ListElement { section: "Animals Emoji"; glyph: "🐸" }
+ ListElement { section: "Animals Emoji"; glyph: "🐯" }
+ ListElement { section: "Animals Emoji"; glyph: "🐨" }
+ ListElement { section: "Animals Emoji"; glyph: "🐘" }
+ ListElement { section: "Animals Emoji"; glyph: "🐼" }
+ ListElement { section: "Animals Emoji"; glyph: "🐧" }
+ ListElement { section: "Animals Emoji"; glyph: "🐦" }
+ ListElement { section: "Animals Emoji"; glyph: "🐤" }
+ ListElement { section: "Animals Emoji"; glyph: "🐥" }
+ ListElement { section: "Animals Emoji"; glyph: "🐣" }
+ ListElement { section: "Animals Emoji"; glyph: "🐔" }
+ ListElement { section: "Animals Emoji"; glyph: "🐍" }
+ ListElement { section: "Animals Emoji"; glyph: "🐢" }
+ ListElement { section: "Animals Emoji"; glyph: "🐛" }
+ ListElement { section: "Animals Emoji"; glyph: "🐝" }
+ ListElement { section: "Animals Emoji"; glyph: "🐜" }
+ ListElement { section: "Animals Emoji"; glyph: "🐞" }
+ ListElement { section: "Animals Emoji"; glyph: "🐌" }
+ ListElement { section: "Animals Emoji"; glyph: "🐙" }
+ ListElement { section: "Animals Emoji"; glyph: "🐚" }
+ ListElement { section: "Animals Emoji"; glyph: "🐠" }
+ ListElement { section: "Animals Emoji"; glyph: "🐟" }
+ ListElement { section: "Animals Emoji"; glyph: "🐬" }
+ ListElement { section: "Animals Emoji"; glyph: "🐳" }
+ ListElement { section: "Animals Emoji"; glyph: "🐋" }
+ ListElement { section: "Animals Emoji"; glyph: "🐄" }
+ ListElement { section: "Animals Emoji"; glyph: "🐏" }
+ ListElement { section: "Animals Emoji"; glyph: "🐀" }
+ ListElement { section: "Animals Emoji"; glyph: "🐃" }
+ ListElement { section: "Animals Emoji"; glyph: "🐅" }
+ ListElement { section: "Animals Emoji"; glyph: "🐇" }
+ ListElement { section: "Animals Emoji"; glyph: "🐉" }
+ ListElement { section: "Animals Emoji"; glyph: "🐎" }
+ ListElement { section: "Animals Emoji"; glyph: "🐐" }
+ ListElement { section: "Animals Emoji"; glyph: "🐓" }
+ ListElement { section: "Animals Emoji"; glyph: "🐕" }
+ ListElement { section: "Animals Emoji"; glyph: "🐖" }
+ ListElement { section: "Animals Emoji"; glyph: "🐁" }
+ ListElement { section: "Animals Emoji"; glyph: "🐂" }
+ ListElement { section: "Animals Emoji"; glyph: "🐲" }
+ ListElement { section: "Animals Emoji"; glyph: "🐡" }
+ ListElement { section: "Animals Emoji"; glyph: "🐊" }
+ ListElement { section: "Animals Emoji"; glyph: "🐫" }
+ ListElement { section: "Animals Emoji"; glyph: "🐪" }
+ ListElement { section: "Animals Emoji"; glyph: "🐆" }
+ ListElement { section: "Animals Emoji"; glyph: "🐈" }
+ ListElement { section: "Animals Emoji"; glyph: "🐩" }
+ ListElement { section: "Animals Emoji"; glyph: "🐾" }
+
+ ListElement { section: "Transport and Map"; glyph: "🚀" }
+ ListElement { section: "Transport and Map"; glyph: "🚃" }
+ ListElement { section: "Transport and Map"; glyph: "🚀" }
+ ListElement { section: "Transport and Map"; glyph: "🚄" }
+ ListElement { section: "Transport and Map"; glyph: "🚅" }
+ ListElement { section: "Transport and Map"; glyph: "🚇" }
+ ListElement { section: "Transport and Map"; glyph: "🚉" }
+ ListElement { section: "Transport and Map"; glyph: "🚌" }
+ ListElement { section: "Transport and Map"; glyph: "🚏" }
+ ListElement { section: "Transport and Map"; glyph: "🚑" }
+ ListElement { section: "Transport and Map"; glyph: "🚒" }
+ ListElement { section: "Transport and Map"; glyph: "🚓" }
+ ListElement { section: "Transport and Map"; glyph: "🚕" }
+ ListElement { section: "Transport and Map"; glyph: "🚗" }
+ ListElement { section: "Transport and Map"; glyph: "🚙" }
+ ListElement { section: "Transport and Map"; glyph: "🚚" }
+ ListElement { section: "Transport and Map"; glyph: "🚢" }
+ ListElement { section: "Transport and Map"; glyph: "🚨" }
+ ListElement { section: "Transport and Map"; glyph: "🚩" }
+ ListElement { section: "Transport and Map"; glyph: "🚪" }
+ ListElement { section: "Transport and Map"; glyph: "🚫" }
+ ListElement { section: "Transport and Map"; glyph: "🚬" }
+ ListElement { section: "Transport and Map"; glyph: "🚭" }
+ ListElement { section: "Transport and Map"; glyph: "🚲" }
+ ListElement { section: "Transport and Map"; glyph: "🚶" }
+ ListElement { section: "Transport and Map"; glyph: "🚹" }
+ ListElement { section: "Transport and Map"; glyph: "🚺" }
+ ListElement { section: "Transport and Map"; glyph: "🚻" }
+ ListElement { section: "Transport and Map"; glyph: "🚼" }
+ ListElement { section: "Transport and Map"; glyph: "🚽" }
+ ListElement { section: "Transport and Map"; glyph: "🚾" }
+ ListElement { section: "Transport and Map"; glyph: "🛀" }
+
+ ListElement { section: "Horoscope Signs"; glyph: "♈" }
+ ListElement { section: "Horoscope Signs"; glyph: "♉" }
+ ListElement { section: "Horoscope Signs"; glyph: "♊" }
+ ListElement { section: "Horoscope Signs"; glyph: "♋" }
+ ListElement { section: "Horoscope Signs"; glyph: "♌" }
+ ListElement { section: "Horoscope Signs"; glyph: "♍" }
+ ListElement { section: "Horoscope Signs"; glyph: "♎" }
+ ListElement { section: "Horoscope Signs"; glyph: "♏" }
+ ListElement { section: "Horoscope Signs"; glyph: "♐" }
+ ListElement { section: "Horoscope Signs"; glyph: "♑" }
+ ListElement { section: "Horoscope Signs"; glyph: "♒" }
+ ListElement { section: "Horoscope Signs"; glyph: "♓" }
+ }
+
+ delegate: BackgroundItem {
+ width: gridView.cellWidth
+ height: gridView.cellHeight
+
+ Label {
+ text: glyph
+ font.pixelSize: Theme.fontSizeLarge
+ color: highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
+ anchors.centerIn: parent
+ }
+
+ onClicked: {
+ var cursorPosition = toot.cursorPosition
+ toot.text = toot.text.substring(
+ 0, cursorPosition) + model.glyph + toot.text.substring(
+ cursorPosition)
+ toot.cursorPosition = cursorPosition + model.glyph.length
+ emojiDialog.canAccept = true
+ emojiDialog.accept()
+ }
+ }
+ VerticalScrollDecorator { flickable: gridView }
+ }
+ }
+}
diff --git a/qml/pages/components/InfoBanner.qml b/qml/pages/components/InfoBanner.qml
index a9a0148..e740634 100644
--- a/qml/pages/components/InfoBanner.qml
+++ b/qml/pages/components/InfoBanner.qml
@@ -4,36 +4,34 @@ import Sailfish.Silica 1.0
DockedPanel {
id: root
- z: 100
- width: parent.width
- height: content.height
dock: Dock.Top
+ width: isPortrait ? parent.width : Theme.buttonWidthLarge * 1.5
+ height: content.height
+ anchors.horizontalCenter: parent.horizontalCenter
Rectangle {
id: content
- width: root.width
- height: infoLabel.height + 5*Theme.paddingMedium
- //anchors.topMargin: 20
color: Theme.highlightBackgroundColor
- opacity: 1.0
+ width: root.width
+ height: infoLabel.height + 2 * Theme.paddingMedium
Label {
id: infoLabel
text : ""
- color: Theme.primaryColor
font.family: Theme.fontFamilyHeading
font.pixelSize: Theme.fontSizeMedium
- //font.weight: Font.Bold
- width: parent.width
+ color: Theme.primaryColor
wrapMode: Text.WrapAnywhere
+ width: parent.width
anchors {
left: parent.left
leftMargin: Theme.horizontalPageMargin*2
right: parent.right
rightMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
- }
+ }
}
+
MouseArea {
anchors.fill: parent
onClicked: {
@@ -51,7 +49,7 @@ DockedPanel {
Timer {
id: autoClose
- interval: 6000
+ interval: 4500
running: false
onTriggered: {
root.hide()
diff --git a/qml/pages/components/ItemUser.qml b/qml/pages/components/ItemUser.qml
index 809c97e..02913eb 100644
--- a/qml/pages/components/ItemUser.qml
+++ b/qml/pages/components/ItemUser.qml
@@ -4,18 +4,20 @@ import Sailfish.Silica 1.0
BackgroundItem {
id: delegate
- signal openUser (string notice)
- height: Theme.itemSizeMedium
- width: parent.width
- Rectangle {
+ signal openUser (string notice)
+
+ width: parent.width
+ height: Theme.itemSizeMedium
+
+ Item {
id: avatar
width: Theme.itemSizeExtraSmall
height: width
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.horizontalPageMargin
- color: Theme.highlightDimmerColor
+
Image {
id: img
opacity: status === Image.Ready ? 1.0 : 0.0
@@ -23,46 +25,79 @@ BackgroundItem {
anchors.fill: parent
source: model.account_avatar
}
+
BusyIndicator {
size: BusyIndicatorSize.Small
opacity: img.status === Image.Ready ? 0.0 : 1.0
Behavior on opacity { FadeAnimator {} }
- running: avatar.status !== Image.Ready;
+ running: avatar.status !== Image.Ready
anchors.centerIn: parent
}
+
MouseArea {
anchors.fill: parent
- onClicked: pageStack.push(Qt.resolvedUrl("./../Profile.qml"), {
+ onClicked: pageStack.push(Qt.resolvedUrl("./../ProfilePage.qml"), {
"display_name": model.account_display_name,
"username": model.account_acct,
"user_id": model.account_id,
- "profileImage": model.account_avatar
+ "profileImage": model.account_avatar,
+ "profileBackground": model.account_header,
+ "note": model.account_note,
+ "url": model.account_url,
+ "followers_count": model.account_followers_count,
+ "following_count": model.account_following_count,
+ "statuses_count": model.account_statuses_count,
+ "locked": model.account_locked,
+ "bot": model.account_bot,
+ "group": model.account_group
})
}
}
- Column {
+
+ Item {
+ id: userDescription
+ height: account_acct.height + display_name.height
anchors.left: avatar.right
anchors.leftMargin: Theme.paddingLarge
+ anchors.right: parent.right
+ anchors.rightMargin: Theme.horizontalPageMargin
anchors.verticalCenter: parent.verticalCenter
- height: account_acct.height + display_name.height
+
Label {
id: display_name
- text: model.account_display_name+" "
- color: !pressed ? Theme.primaryColor : Theme.highlightColor
+ text: account_display_name ? account_display_name : account_username.split('@')[0]
+ color: !pressed ? Theme.primaryColor : Theme.highlightColor
font.pixelSize: Theme.fontSizeSmall
+ truncationMode: TruncationMode.Fade
+ width: parent.width - Theme.paddingMedium
+ anchors.top: parent.top
}
+
Label {
id: account_acct
text: "@"+model.account_acct
color: !pressed ? Theme.secondaryColor : Theme.secondaryHighlightColor
anchors.leftMargin: Theme.paddingMedium
font.pixelSize: Theme.fontSizeExtraSmall
+ truncationMode: TruncationMode.Fade
+ width: parent.width - Theme.paddingMedium
+ anchors.top: display_name.bottom
}
}
- onClicked: openUser({
+
+ onClicked: openUser( {
"display_name": model.account_display_name,
"username": model.account_acct,
"user_id": model.account_id,
- "profileImage": model.account_avatar
- })
+ "profileImage": model.account_avatar,
+ "profileBackground": model.account_header,
+ "note": model.account_note,
+ "url": model.account_url,
+ "followers_count": model.account_followers_count,
+ "following_count": model.account_following_count,
+ "statuses_count": model.account_statuses_count,
+ "locked": model.account_locked,
+ "bot": model.account_bot,
+ "group": model.account_group
+ } )
}
diff --git a/qml/pages/components/MediaBlock.qml b/qml/pages/components/MediaBlock.qml
index 069f954..e3bb587 100644
--- a/qml/pages/components/MediaBlock.qml
+++ b/qml/pages/components/MediaBlock.qml
@@ -4,15 +4,17 @@ import QtMultimedia 5.0
Item {
+ id: holder
+
property ListModel model
property double wRatio : 16/9
property double hRatio : 9/16
- id: holder
+
width: width
height: height
Component.onCompleted: {
if (model && model.count && model.get(0).type === "video") {
- while (model.count>1){
+ while (model.count>1) {
model.remove(model.count-1)
}
//console.log(JSON.stringify(model.get(0)))
@@ -21,15 +23,17 @@ Item {
if (model && model.count)
count = model.count
switch(count){
+
case 1:
placeholder1.width = holder.width
placeholder1.height = placeholder1.width*hRatio
placeholder1.visible = true;
holder.height = placeholder1.height
break;
+
case 2:
- placeholder1.visible = true;
- placeholder2.visible = true;
+ placeholder1.visible = true
+ placeholder2.visible = true
placeholder1.width = (holder.width-Theme.paddingSmall)/2
placeholder1.height = placeholder1.width
placeholder2.width = placeholder1.width
@@ -37,11 +41,12 @@ Item {
placeholder2.x = placeholder1.width + placeholder2.x + Theme.paddingSmall
holder.height = placeholder1.height
break;
+
case 3:
- placeholder1.visible = true;
- placeholder2.visible = true;
- placeholder3.visible = true;
- placeholder4.visible = false;
+ placeholder1.visible = true
+ placeholder2.visible = true
+ placeholder3.visible = true
+ placeholder4.visible = false
placeholder1.width = holder.width - Theme.paddingSmall - Theme.itemSizeLarge;
placeholder1.height = Theme.itemSizeLarge*2+Theme.paddingSmall
@@ -51,30 +56,30 @@ Item {
placeholder3.height = placeholder3.width = placeholder2.height = placeholder2.width
placeholder3.x = placeholder2.x = placeholder1.x + placeholder1.width + Theme.paddingSmall;
placeholder3.y = placeholder2.y + placeholder2.height + Theme.paddingSmall;
-
break;
+
case 4:
- placeholder1.visible = true;
- placeholder2.visible = true;
- placeholder3.visible = true;
- placeholder4.visible = true;
+ placeholder1.visible = true
+ placeholder2.visible = true
+ placeholder3.visible = true
+ placeholder4.visible = true
placeholder1.width = placeholder2.width = placeholder3.width = placeholder4.width = (holder.width - 3*Theme.paddingSmall)/4
placeholder1.height = placeholder2.height = placeholder3.height = placeholder4.height = Theme.itemSizeLarge*2+Theme.paddingSmall
- placeholder2.x = 1*(placeholder1.width)+ 1*Theme.paddingSmall;
- placeholder3.x = 2*(placeholder1.width)+ 2*Theme.paddingSmall;
- placeholder4.x = 3*(placeholder1.width)+ 3*Theme.paddingSmall;
+ placeholder2.x = 1*(placeholder1.width)+ 1*Theme.paddingSmall
+ placeholder3.x = 2*(placeholder1.width)+ 2*Theme.paddingSmall
+ placeholder4.x = 3*(placeholder1.width)+ 3*Theme.paddingSmall
-
- holder.height = placeholder1.height
+ holder.height = placeholder1.height
break;
+
default:
holder.height = 0
placeholder1.visible = placeholder2.visible = placeholder3.visible = placeholder4.visible = false;
}
}
- MyImage {
+ MyMedia {
id: placeholder1
width: 2
height: 1
@@ -84,7 +89,7 @@ Item {
type = model.get(0).type
previewURL = model.get(0).preview_url
mediaURL = model.get(0).url
- height = 200
+ height = Theme.itemSizeLarge
return true
} else {
height = 0
@@ -92,7 +97,8 @@ Item {
}
}
}
- MyImage {
+
+ MyMedia {
id: placeholder2
width: 2
height: 1
@@ -102,7 +108,7 @@ Item {
type = model.get(1).type
previewURL = model.get(1).preview_url
mediaURL = model.get(1).url
- height = 200
+ height = Theme.itemSizeLarge
return true
} else {
height = 0
@@ -110,7 +116,8 @@ Item {
}
}
}
- MyImage {
+
+ MyMedia {
id: placeholder3
width: 2
height: 1
@@ -120,7 +127,7 @@ Item {
type = model.get(2).type
previewURL = model.get(2).preview_url
mediaURL = model.get(2).url
- height = 200
+ height = Theme.itemSizeLarge
return true
} else {
height = 0
@@ -128,7 +135,8 @@ Item {
}
}
}
- MyImage {
+
+ MyMedia {
id: placeholder4
width: 2
height: 1
@@ -138,7 +146,7 @@ Item {
type = model.get(3).type
previewURL = model.get(3).preview_url
mediaURL = model.get(3).url
- height = 200
+ height = Theme.itemSizeLarge
return true
} else {
height = 0
@@ -147,7 +155,3 @@ Item {
}
}
}
-
-
-
-
diff --git a/qml/pages/components/ImageFullScreen.qml b/qml/pages/components/MediaFullScreen.qml
similarity index 67%
rename from qml/pages/components/ImageFullScreen.qml
rename to qml/pages/components/MediaFullScreen.qml
index 5384804..f4adf7d 100644
--- a/qml/pages/components/ImageFullScreen.qml
+++ b/qml/pages/components/MediaFullScreen.qml
@@ -1,68 +1,57 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
-import QtMultimedia 5.0
+import QtMultimedia 5.6
+
FullscreenContentPage {
- id: imagePage
+ id: mediaPage
+
property string type: ""
property string previewURL: ""
property string mediaURL: ""
+
allowedOrientations: Orientation.All
- Component.onCompleted: function(){
+ Component.onCompleted: function() {
console.log(type)
console.log(previewURL)
console.log(mediaURL)
if (type != 'gifv' && type != 'video') {
imagePreview.source = mediaURL
- imageFlickable.visible = true;
+ imageFlickable.visible = true
} else {
video.source = mediaURL
video.fillMode = VideoOutput.PreserveAspectFit
+ videoFlickable.visible = true
+ playerIcon.visible = true
+ playerProgress.visible = true
video.play()
- videoFlickable.visible = true;
+ hideTimer.start()
}
}
- Item {
- id: overlay
- z: 100
- property bool active: true
- enabled: active
- anchors.fill: parent
- opacity: active ? 1.0 : 0.0
- Behavior on opacity { FadeAnimator {}}
- IconButton {
- y: Theme.paddingLarge
- anchors {
- right: parent.right
- rightMargin: Theme.horizontalPageMargin
- }
- icon.source: "image://theme/icon-m-dismiss"
- onClicked: pageStack.pop()
- }
- }
-
- Flickable {
+ SilicaFlickable {
id: videoFlickable
visible: false
+ contentWidth: imageContainer.width
+ contentHeight: imageContainer.height
anchors.fill: parent
- contentWidth: imageContainer.width; contentHeight: imageContainer.height
- clip: true
+
Image {
id: videoPreview
fillMode: Image.PreserveAspectFit
anchors.fill: parent
source: previewURL
}
+
Video {
id: video
anchors.fill: parent
- onErrorStringChanged: function(){
- videoError.visible = true;
+ onErrorStringChanged: function() {
+ videoError.visible = true
}
onStatusChanged: {
console.log(status)
- switch (status){
+ switch (status) {
case MediaPlayer.Loading:
console.log("loading")
return;
@@ -71,10 +60,9 @@ FullscreenContentPage {
return;
}
}
-
onPlaybackStateChanged: {
console.log(playbackState)
- switch (playbackState){
+ switch (playbackState) {
case MediaPlayer.PlayingState:
playerIcon.icon.source = "image://theme/icon-m-pause"
return;
@@ -82,12 +70,11 @@ FullscreenContentPage {
playerIcon.icon.source = "image://theme/icon-m-play"
return;
case MediaPlayer.StoppedState:
- playerIcon.icon.source = "image://theme/icon-m-stop"
+ playerIcon.icon.source = "image://theme/icon-m-reload"
return;
}
}
-
- onPositionChanged: function(){
+ onPositionChanged: function() {
//console.log(duration)
//console.log(bufferProgress)
//console.log(position)
@@ -97,51 +84,32 @@ FullscreenContentPage {
playerProgress.minimumValue = 0
playerProgress.value = position
}
-
+ }
+ onStopped: function() {
+ if (type == 'gifv') {
+ video.play()
+ } else {
+ video.stop()
+ overlayIcons.active = true
+ hideTimer.stop()
+ }
}
- onStopped: function(){
- play()
- }
- IconButton {
- id: playerIcon
- anchors.left: parent.left
- anchors.bottom: parent.bottom
- anchors.leftMargin: Theme.paddingLarge
- anchors.bottomMargin: Theme.paddingLarge*1.5
- icon.source: "image://theme/icon-m-play"
+ MouseArea {
+ anchors.fill: parent
onClicked: function() {
- if (video.playbackState === MediaPlayer.PlayingState)
+ if (video.playbackState === MediaPlayer.PlayingState) {
video.pause()
- else
+ overlayIcons.active = true
+ hideTimer.stop()
+ } else {
video.play()
+ hideTimer.start()
+ }
}
}
- ProgressBar {
- indeterminate: true
- id: playerProgress
- anchors.left: playerIcon.right
- anchors.right: videoDlBtn.left
- anchors.verticalCenter: playerIcon.verticalCenter
- anchors.leftMargin: 0
- anchors.bottomMargin: Theme.paddingLarge*1.5
- }
- IconButton {
- id: videoDlBtn
- visible: true
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.rightMargin: Theme.paddingLarge
- anchors.bottomMargin: Theme.paddingLarge*1.5
- icon.source: "image://theme/icon-m-device-download"
- icon.opacity: 0.0
- onClicked: {
- var filename = mediaURL.split("/");
- FileDownloader.downloadFile(mediaURL, filename[filename.length-1]);
- }
- }
Rectangle {
visible: videoError.text != ""
anchors.left: parent.left
@@ -150,39 +118,32 @@ FullscreenContentPage {
color: Theme.highlightDimmerColor
height: videoError.height + 2*Theme.paddingMedium
width: parent.width
+
Label {
- anchors.centerIn: parent
id: videoError
- width: parent.width - 2*Theme.paddingMedium
- wrapMode: Text.Wrap
- height: contentHeight
- visible: false;
- font.pixelSize: Theme.fontSizeSmall;
+ visible: false
text: video.errorString
+ font.pixelSize: Theme.fontSizeSmall
color: Theme.highlightColor
- }
- }
-
-
- MouseArea {
- anchors.fill: parent
- onClicked: function() {
- if (video.playbackState === MediaPlayer.PlayingState)
- video.pause()
- else
- video.play()
+ wrapMode: Text.Wrap
+ width: parent.width - 2*Theme.paddingMedium
+ height: contentHeight
+ anchors.centerIn: parent
}
}
}
}
- Flickable {
+
+ SilicaFlickable {
id: imageFlickable
visible: false
+ contentWidth: imageContainer.width
+ contentHeight: imageContainer.height
anchors.fill: parent
- contentWidth: imageContainer.width; contentHeight: imageContainer.height
- clip: true
- onHeightChanged: if (imagePreview.status === Image.Ready) imagePreview.fitToScreen();
+ onHeightChanged: if (imagePreview.status === Image.Ready) {
+ imagePreview.fitToScreen()
+ }
Item {
id: imageContainer
@@ -191,18 +152,21 @@ FullscreenContentPage {
Image {
id: imagePreview
+
property real prevScale
+
function fitToScreen() {
- scale = Math.min(imageFlickable.width / width, imageFlickable.height / height, 1)
+ scale = Math.min(imageFlickable.width / width, imageFlickable.height / height, imageFlickable.width, imageFlickable.height)
pinchArea.minScale = scale
prevScale = scale
}
- anchors.centerIn: parent
+
fillMode: Image.PreserveAspectFit
cache: true
asynchronous: true
- sourceSize.height: 1000;
- smooth: false
+ sourceSize.width: mediaPage.width
+ smooth: true
+ anchors.centerIn: parent
onStatusChanged: {
if (status == Image.Ready) {
fitToScreen()
@@ -235,14 +199,15 @@ FullscreenContentPage {
PinchArea {
id: pinchArea
- opacity: 0.3
+
property real minScale: 1.0
property real maxScale: 3.0
+
anchors.fill: parent
enabled: imagePreview.status === Image.Ready
pinch.target: imagePreview
pinch.minimumScale: minScale * 0.5 // This is to create "bounce back effect"
- pinch.maximumScale: maxScale * 1.5 // when over zoomed
+ pinch.maximumScale: maxScale * 1.5 // when over zoomed}
onPinchFinished: {
imageFlickable.returnToBounds()
@@ -255,6 +220,7 @@ FullscreenContentPage {
bounceBackAnimation.start()
}
}
+
NumberAnimation {
id: bounceBackAnimation
target: imagePreview
@@ -262,6 +228,11 @@ FullscreenContentPage {
property: "scale"
from: imagePreview.scale
}
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: overlayIcons.active = !overlayIcons.active
+ }
}
}
@@ -281,35 +252,109 @@ FullscreenContentPage {
Component {
id: loadingIndicator
Item {
+ width: mediaPage.width
height: childrenRect.height
- width: imagePage.width
+
ProgressCircle {
id: imageLoadingIndicator
- anchors.horizontalCenter: parent.horizontalCenter
progressValue: imagePreview.progress
+ progressColor: inAlternateCycle ? Theme.highlightColor : Theme.highlightDimmerColor
+ backgroundColor: inAlternateCycle ? Theme.highlightDimmerColor : Theme.highlightColor
+ anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
+
Component {
id: failedLoading
Text {
- font.pixelSize: Theme.fontSizeSmall;
text: qsTr("Error loading")
+ font.pixelSize: Theme.fontSizeSmall
color: Theme.highlightColor
}
}
- IconButton {
- visible: true
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.rightMargin: Theme.paddingLarge
- anchors.bottomMargin: Theme.paddingLarge*1.5
- icon.source: "image://theme/icon-m-device-download"
- onClicked: {
- var filename = mediaURL.split("/");
- FileDownloader.downloadFile(mediaURL, filename[filename.length-1]);
+
+ Item {
+ id: overlayIcons
+
+ property bool active: true
+
+ enabled: active
+ anchors.fill: parent
+ opacity: active ? 1.0 : 0.0
+ Behavior on opacity { FadeAnimator {}}
+
+ IconButton {
+ y: Theme.paddingLarge
+ icon.source: "image://theme/icon-m-dismiss"
+ onClicked: pageStack.pop()
+ anchors {
+ right: parent.right
+ rightMargin: Theme.horizontalPageMargin
+ }
+ }
+
+ IconButton {
+ id: mediaDlBtn
+ icon.source: "image://theme/icon-m-cloud-download"
+ anchors {
+ right: parent.right
+ rightMargin: Theme.horizontalPageMargin
+ bottom: parent.bottom
+ bottomMargin: Theme.horizontalPageMargin
+ }
+ onClicked: {
+ var filename = mediaURL.split("/")
+ FileDownloader.downloadFile(mediaURL, filename[filename.length-1])
+ }
+ }
+
+ IconButton {
+ id: playerIcon
+ visible: false
+ icon.source: "image://theme/icon-m-play"
+ anchors {
+ left: parent.left
+ bottom: parent.bottom
+ leftMargin: Theme.horizontalPageMargin
+ bottomMargin: Theme.horizontalPageMargin
+ }
+ onClicked: function() {
+ if (video.playbackState === MediaPlayer.PlayingState) {
+ video.pause()
+ hideTimer.stop()
+ } else {
+ video.play()
+ hideTimer.start()
+ }
+ }
+ }
+
+ ProgressBar {
+ id: playerProgress
+ visible: false
+ indeterminate: true
+ width: 400
+ anchors {
+ verticalCenter: playerIcon.verticalCenter
+ left: playerIcon.right
+ right: parent.right
+ rightMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium
+ bottomMargin: Theme.horizontalPageMargin
+ }
+ }
+
+ Timer {
+ id: hideTimer
+ running: false
+ interval: 2000
+ onTriggered: {
+ overlayIcons.active = !overlayIcons.active
+ }
}
}
+
VerticalScrollDecorator { flickable: imageFlickable }
}
+
diff --git a/qml/pages/components/MiniHeader.qml b/qml/pages/components/MiniHeader.qml
index 06c420a..3cf3cd3 100644
--- a/qml/pages/components/MiniHeader.qml
+++ b/qml/pages/components/MiniHeader.qml
@@ -1,70 +1,69 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
+
Item {
- id: miniheader
+ id: miniHeader
height: lblName.height
width: parent.width
Label {
id: lblName
+ text: account_display_name ? account_display_name : account_username.split('@')[0]
+ font.weight: Font.Bold
+ font.pixelSize: Theme.fontSizeSmall
+ color: if ( myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )) {
+ ( pressed ? Theme.secondaryHighlightColor : (!highlight ? Theme.secondaryColor : Theme.secondaryHighlightColor ))
+ } else ( pressed ? Theme.highlightColor : ( !highlight ? Theme.primaryColor : Theme.secondaryColor ))
+ truncationMode: TruncationMode.Fade
+ width: myList.type !== "follow" ? ( contentWidth > parent.width /2 ? parent.width /2 : contentWidth ) : parent.width - Theme.paddingMedium
anchors {
left: parent.left
leftMargin: Theme.paddingMedium
}
- text:
- if (account_display_name === "") {
- account_username.split('@')[0]
- }
- else account_display_name
- width: contentWidth > parent.width /2 ? parent.width /2 : contentWidth
- truncationMode: TruncationMode.Fade
- font.weight: Font.Bold
- font.pixelSize: Theme.fontSizeSmall
- color: (pressed ? Theme.highlightColor : Theme.primaryColor)
- }
-
- Image {
- id: iconVerified
- y: Theme.paddingLarge
- anchors {
- left: lblName.right
- leftMargin: Theme.paddingSmall
- verticalCenter: lblName.verticalCenter
- }
- visible: account_locked
- width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0
- opacity: 0.8
- height: width
- source: "image://theme/icon-s-secure?" + (pressed
- ? Theme.highlightColor
- : Theme.primaryColor)
}
Label {
id: lblScreenName
- anchors {
- left: iconVerified.right
- right: lblDate.left
- leftMargin: Theme.paddingMedium
- baseline: lblName.baseline
- }
- truncationMode: TruncationMode.Fade
+ visible: model.type !== "follow"
text: '@'+account_username
font.pixelSize: Theme.fontSizeExtraSmall
- color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
+ color: ( pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor )
+ truncationMode: TruncationMode.Fade
+ anchors {
+ left: lblName.right
+ leftMargin: Theme.paddingMedium
+ right: lblDate.left
+ rightMargin: Theme.paddingMedium
+ verticalCenter: lblName.verticalCenter
+ }
}
- Label {
+ Label {
+ id: lblScreenNameFollow
+ visible: model.type === "follow"
+ text: '@'+account_username
+ font.pixelSize: Theme.fontSizeExtraSmall
+ color: ( pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor )
+ width: parent.width - Theme.paddingMedium
+ truncationMode: TruncationMode.Fade
+ anchors {
+ top: lblName.bottom
+ left: parent.left
+ leftMargin: Theme.paddingMedium
+ }
+ }
+
+ Label {
id: lblDate
- color: (pressed ? Theme.highlightColor : Theme.primaryColor)
text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours)
font.pixelSize: Theme.fontSizeExtraSmall
+ color: ( pressed ? Theme.highlightColor : Theme.secondaryColor )
horizontalAlignment: Text.AlignRight
anchors {
right: parent.right
- baseline: lblName.baseline
rightMargin: Theme.horizontalPageMargin
+ verticalCenter: lblName.verticalCenter
}
}
}
diff --git a/qml/pages/components/MiniStatus.qml b/qml/pages/components/MiniStatus.qml
index f7a57d0..96170fe 100644
--- a/qml/pages/components/MiniStatus.qml
+++ b/qml/pages/components/MiniStatus.qml
@@ -1,34 +1,32 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
+
Item {
- id: ministatus
+ id: miniStatus
visible: true
- height: icon.height+Theme.paddingMedium
width: parent.width
- Image {
+ height: icon.height+Theme.paddingMedium
+
+ Icon {
id: icon
- anchors {
- top: parent.top
- topMargin: Theme.paddingMedium
- bottomMargin: Theme.paddingMedium
- left: parent.left
- leftMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium - width
- }
visible: type.length
+ color: Theme.highlightColor
width: Theme.iconSizeExtraSmall
height: width
source: typeof typeIcon !== "undefined" ? typeIcon : ""
-
+ anchors {
+ top: parent.top
+ topMargin: Theme.paddingMedium
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium - width
+ bottomMargin: Theme.paddingMedium
+ }
}
+
Label {
id: lblRtByName
visible: type.length
- anchors {
- left: icon.right
- leftMargin: Theme.paddingMedium
- verticalCenter: icon.verticalCenter
- }
text: {
var action = "";
switch(type){
@@ -42,13 +40,17 @@ Item {
action = qsTr('followed you');
break;
default:
- ministatus.visible = false
+ miniStatus.visible = false
action = type;
}
- return typeof reblog_account_username !== "undefined" ? '@' + reblog_account_username + ' ' + action : ''
+ return typeof reblog_account_username !== "undefined" ? '@' + reblog_account_username + " " + action : " "
}
-
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
+ anchors {
+ left: icon.right
+ leftMargin: Theme.paddingMedium
+ verticalCenter: icon.verticalCenter
+ }
}
}
diff --git a/qml/pages/components/MyList.qml b/qml/pages/components/MyList.qml
index 27acc24..23ddd73 100644
--- a/qml/pages/components/MyList.qml
+++ b/qml/pages/components/MyList.qml
@@ -3,31 +3,30 @@ import Sailfish.Silica 1.0
import "../../lib/API.js" as Logic
import "."
+
SilicaListView {
id: myList
- property string type;
+
+ property string type
property string title
- property string vwPlaceholderText: qsTr("Loading")
- property string vwPlaceholderHint: qsTr("please wait...")
property string description
property ListModel mdl: []
property variant params: []
property var locale: Qt.locale()
- property bool autoLoadMore : true;
- property bool loadStarted : false;
- property int scrollOffset;
+ property bool autoLoadMore: true
+ property bool loadStarted: false
+ property int scrollOffset
property string action: ""
property variant vars
property variant conf
- property bool notifier : false;
+ property bool notifier: false
+
model: mdl
+
signal notify (string what, int num)
onNotify: {
console.log(what + " - " + num)
}
-
-
-
signal openDrawer (bool setDrawer)
onOpenDrawer: {
//console.log("Open drawer: " + setDrawer)
@@ -37,53 +36,74 @@ SilicaListView {
console.log("LIST send signal emitted with notice: " + notice)
}
-
- BusyIndicator {
- size: BusyIndicatorSize.Large
- running: myList.model.count === 0 && !viewPlaceHolder.visible
- anchors.centerIn: parent
- }
-
header: PageHeader {
title: myList.title
description: myList.description
}
+ BusyLabel {
+ id: myListBusyLabel
+ running: model.count === 0
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ verticalCenter: parent.verticalCenter
+ }
+ Timer {
+ interval: 5000
+ running: true
+ onTriggered: {
+ myListBusyLabel.visible = false
+ loadStatusPlaceholder.visible = true
+ }
+ }
+ }
ViewPlaceholder {
- id: viewPlaceHolder
+ id: loadStatusPlaceholder
+ visible: false
enabled: model.count === 0
- text: vwPlaceholderText
- hintText: vwPlaceholderHint
+ text: qsTr("Nothing found")
}
PullDownMenu {
+ id: mainPulleyMenu
MenuItem {
text: qsTr("Settings")
+ visible: !profilePage
onClicked: {
- pageStack.push(Qt.resolvedUrl("../Settings.qml"), {})
+ pageStack.push(Qt.resolvedUrl("../SettingsPage.qml"), {})
}
}
MenuItem {
- text: qsTr("Load more")
+ text: qsTr("New Toot")
+ visible: !profilePage
+ onClicked: {
+ pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
+ headerTitle: qsTr("New Toot"),
+ type: "new"
+ })
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Open in Browser")
+ visible: !mainPage
+ onClicked: {
+ Qt.openUrlExternally(url)
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Reload")
onClicked: {
loadData("prepend")
}
}
}
- clip: true
- section {
- property: 'section'
- delegate: SectionHeader {
- height: Theme.itemSizeExtraSmall
- text: Format.formatDate(section, Formatter.DateMedium)
- }
- }
- delegate: VisualContainer {
- } //Toot {}
+ delegate: VisualContainer {}
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 800 }
@@ -95,13 +115,12 @@ SilicaListView {
}
onCountChanged: {
- loadStarted = false;
+ loadStarted = false
/*contentY = scrollOffset
console.log("CountChanged!")*/
-
}
- footer: Item{
+ footer: Item {
visible: autoLoadMore
width: parent.width
height: Theme.itemSizeLarge
@@ -114,24 +133,29 @@ SilicaListView {
loadData("append")
}
}
+
BusyIndicator {
+ running: loadStarted
+ visible: myListBusyLabel.running ? false : true
size: BusyIndicatorSize.Small
- running: loadStarted;
- anchors.verticalCenter: parent.verticalCenter
- anchors.horizontalCenter: parent.horizontalCenter
+ anchors {
+ verticalCenter: parent.verticalCenter
+ horizontalCenter: parent.horizontalCenter
+ }
}
}
+
onContentYChanged: {
if (Math.abs(contentY - scrollOffset) > Theme.itemSizeMedium) {
openDrawer(contentY - scrollOffset > 0 ? false : true )
scrollOffset = contentY
}
-
- if(contentY+height > footerItem.y && !loadStarted && autoLoadMore){
+ if(contentY+height > footerItem.y && !loadStarted && autoLoadMore) {
loadData("append")
- loadStarted = true;
+ loadStarted = true
}
}
+
VerticalScrollDecorator {}
WorkerScript {
@@ -144,7 +168,6 @@ SilicaListView {
if (messageObject.fireNotification && notifier){
Logic.notifier(messageObject.data)
}
-
}
}
@@ -159,17 +182,18 @@ SilicaListView {
loadData("prepend")
}
}
- function loadData(mode){
- var p = [];
- if (params.length)
+
+ function loadData(mode) {
+ var p = []
+ if (params.length) {
for(var i = 0; i 0 ? Theme.paddingLarge : 0 )+ lblName.paintedHeight + (type.length ? Theme.paddingLarge + iconRT.height : 0) + Theme.paddingLarge
- Image {
- id: iconRT
- y: Theme.paddingLarge
- anchors {
- right: avatar.right
- }
- visible: type.length
- width: Theme.iconSizeExtraSmall
- height: width
- source: "../../images/boosted.svg"
- }
- Label {
- id: lblRtByName
- visible: type.length
- anchors {
- left: lblName.left
- bottom: iconRT.bottom
- }
- text: {
- var action;
- switch(type){
- case "reblog":
- action = qsTr('boosted');
- break;
- case "favourite":
- action = qsTr('favourited');
- break;
- case "follow":
- action = qsTr('followed you');
- break;
- default:
- action = type;
- }
- return '@' + retweetScreenName + ' ' + action
- }
-
- font.pixelSize: Theme.fontSizeExtraSmall
- color: Theme.secondaryColor
- }
- Image {
- id: avatar
- x: Theme.horizontalPageMargin
- y: Theme.paddingLarge + (type.length ? iconRT.height+Theme.paddingMedium : 0)
- asynchronous: true
- width: Theme.iconSizeMedium
- height: width
- smooth: true
- source: account_avatar
- visible: true
- MouseArea {
- anchors.fill: parent
- onClicked: {
- pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
- "display_name": account_display_name,
- "username": account_username,
- "profileImage": account_avatar
- })
- }
-
- }
-
- }
- Label {
- id: lblName
- anchors {
- top: avatar.top
- topMargin: 0
- left: avatar.right
- leftMargin: Theme.paddingMedium
- }
- text: account_display_name
- font.weight: Font.Bold
- font.pixelSize: Theme.fontSizeSmall
- color: (pressed ? Theme.highlightColor : Theme.primaryColor)
- }
-
- Image {
- id: iconVerified
- y: Theme.paddingLarge
- anchors {
- left: lblName.right
- leftMargin: Theme.paddingSmall
- verticalCenter: lblName.verticalCenter
- }
- visible: account_locked
- width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0
- opacity: 0.8
- height: width
- source: "image://theme/icon-s-secure?" + (pressed
- ? Theme.highlightColor
- : Theme.primaryColor)
- }
-
-
- Label {
- id: lblScreenName
- anchors {
- left: iconVerified.right
- right: lblDate.left
- leftMargin: Theme.paddingMedium
- baseline: lblName.baseline
- }
- truncationMode: TruncationMode.Fade
- text: '@'+account_username
- font.pixelSize: Theme.fontSizeExtraSmall
- color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
- }
- Label {
- function timestamp() {
- var txt = Format.formatDate(created_at, Formatter.Timepoint)
- var elapsed = Format.formatDate(created_at, Formatter.DurationElapsedShort)
- return (elapsed ? elapsed : txt )
- }
- id: lblDate
- color: (pressed ? Theme.highlightColor : Theme.primaryColor)
- text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours)
- font.pixelSize: Theme.fontSizeExtraSmall
- horizontalAlignment: Text.AlignRight
- anchors {
- right: parent.right
- baseline: lblName.baseline
- rightMargin: Theme.paddingLarge
- }
- }
-
- Label {
- id: lblText
- anchors {
- left: lblName.left
- right: parent.right
- top: lblScreenName.bottom
- topMargin: Theme.paddingSmall
- rightMargin: Theme.paddingLarge
- }
- height: content.length ? paintedHeight : 0
- onLinkActivated: {
- console.log(link)
- if (link[0] === "@") {
- pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
- "name": "",
- "username": link.substring(1),
- "profileImage": ""
- })
- } else if (link[0] === "#") {
-
- pageStack.pop(pageStack.find(function(page) {
- var check = page.isFirstPage === true;
- if (check)
- page.onLinkActivated(link)
- return check;
- }));
-
- send(link)
- } else {
- Qt.openUrlExternally(link);
- }
-
-
- }
- text: content
- textFormat: Text.RichText
- linkColor : Theme.highlightColor
- wrapMode: Text.Wrap
- maximumLineCount: 6
- font.pixelSize: Theme.fontSizeSmall
- color: (pressed ? Theme.highlightColor : Theme.primaryColor)
- }
- onClicked: {
- pageStack.push(Qt.resolvedUrl("../Conversation.qml"), {
- toot_id: id,
- title: account_display_name,
- description: '@'+account_username,
- avatar: account_avatar,
- type: "reply"
- })
- }
-
-}
diff --git a/qml/pages/components/VisualContainer.qml b/qml/pages/components/VisualContainer.qml
index 8ae8b1b..af62906 100644
--- a/qml/pages/components/VisualContainer.qml
+++ b/qml/pages/components/VisualContainer.qml
@@ -2,24 +2,35 @@ import QtQuick 2.2
import Sailfish.Silica 1.0
import "../../lib/API.js" as Logic
+
BackgroundItem {
id: delegate
+
signal send (string notice)
signal navigateTo(string link)
- width: parent.width
- height: mnu.height + miniHeader.height + (typeof attachments !== "undefined" && attachments.count ? media.height + Theme.paddingLarge + Theme.paddingMedium: Theme.paddingLarge) + lblContent.height + Theme.paddingLarge + (ministatus.visible ? ministatus.height : 0)
+
+ height: if (myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )) {
+ mnu.height + miniHeader.height + Theme.paddingLarge + lblContent.height + Theme.paddingLarge + (miniStatus.visible ? miniStatus.height : 0)
+ } else mnu.height + miniHeader.height + (typeof attachments !== "undefined" && attachments.count ? media.height + Theme.paddingLarge + Theme.paddingMedium: Theme.paddingLarge) + lblContent.height + Theme.paddingLarge + (miniStatus.visible ? miniStatus.height : 0) + (iconDirectMsg.visible ? iconDirectMsg.height : 0)
+
+ // Background for Direct Messages in Notification View
Rectangle {
- x: 0;
- y: 0;
- visible: status_visibility == 'direct'
+ id: bgDirect
+ x: 0
+ y: 0
+ visible: model.status_visibility === "direct"
width: parent.width
height: parent.height
opacity: 0.3
- color: Theme.highlightBackgroundColor;
+ gradient: Gradient {
+ GradientStop { position: -1.5; color: "transparent" }
+ GradientStop { position: 0.6; color: Theme.highlightBackgroundColor }
+ }
}
+ // Element showing reblog, favourite, follow status on top of Toot
MiniStatus {
- id: ministatus
+ id: miniStatus
anchors {
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
@@ -28,55 +39,74 @@ BackgroundItem {
}
}
+ // Account avatar
Image {
id: avatar
- anchors {
- top: ministatus.visible ? ministatus.bottom : parent.top
- topMargin: ministatus.visible ? Theme.paddingMedium : Theme.paddingLarge
- left: parent.left
- leftMargin: Theme.horizontalPageMargin
- }
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
asynchronous: true
- width: Theme.iconSizeMedium
- height: width
smooth: true
source: account_avatar
- visible: true
+ width: Theme.iconSizeMedium
+ height: width
+ anchors {
+ top: miniStatus.visible ? miniStatus.bottom : parent.top
+ topMargin: miniStatus.visible ? Theme.paddingMedium : Theme.paddingLarge
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin
+ }
onStatusChanged: {
if (avatar.status === Image.Error)
- source = "../../images/icon-m-profile.svg?" + (pressed
- ? Theme.highlightColor
- : Theme.primaryColor)
+ source = "../../images/icon-m-profile.svg?" + Theme.primaryColor
}
+
MouseArea {
anchors.fill: parent
onClicked: {
- pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
+ pageStack.push(Qt.resolvedUrl("../ProfilePage.qml"), {
"display_name": model.account_display_name,
"username": model.account_acct,
"user_id": model.account_id,
"profileImage": model.account_avatar,
- "profileBackground": model.account_header
- })
+ "profileBackground": model.account_header,
+ "note": model.account_note,
+ "url": model.account_url,
+ "followers_count": model.account_followers_count,
+ "following_count": model.account_following_count,
+ "statuses_count": model.account_statuses_count,
+ "locked": model.account_locked,
+ "bot": model.account_bot,
+ "group": model.account_group
+ } )
}
-
}
- Image {
- id: iconTR
+
+ // Avatar dimmer for facourite and reblog notifications
+ Rectangle {
+ visible: myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )
+ opacity: 0.5
+ color: Theme.highlightDimmerColor
+ anchors.fill: avatar
+ }
+
+ Icon {
+ id: iconDirectMsg
+ visible: status_visibility === "direct"
+ width: Theme.iconSizeMedium
+ height: width
+ source: "image://theme/icon-m-mail?" + Theme.primaryColor
+ color: Theme.primaryColor
anchors {
+ horizontalCenter: avatar.horizontalCenter
top: avatar.bottom
topMargin: Theme.paddingMedium
left: avatar.left
}
- visible: typeof status_reblogged !== "undefined" && status_reblogged
- width: Theme.iconSizeExtraSmall
- height: width
- source: "image://theme/icon-s-retweet"
- }
+ }
+
Rectangle {
- color: Theme.highlightDimmerColor
+ id: bgReblogAvatar
+ color: Theme.secondaryColor
width: Theme.iconSizeSmall
height: width
visible: typeof status_reblog !== "undefined" && status_reblog
@@ -86,18 +116,43 @@ BackgroundItem {
left: parent.left
leftMargin: -width/3
}
+
Image {
+ id: reblogAvatar
asynchronous: true
- width: Theme.iconSizeSmall
- height: width
smooth: true
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
source: typeof reblog_account_avatar !== "undefined" ? reblog_account_avatar : ''
visible: typeof status_reblog !== "undefined" && status_reblog
+ width: Theme.iconSizeSmall
+ height: width
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ pageStack.push(Qt.resolvedUrl("../ProfilePage.qml"), {
+ "display_name": model.reblog_account_display_name,
+ "username": model.reblog_account_acct,
+ "user_id": model.reblog_account_id,
+ "profileImage": model.reblog_account_avatar,
+ "profileBackground": model.account_header,
+ "note": model.reblog_account_note,
+ "url": model.reblog_account_url,
+ "followers_count": model.reblog_account_followers_count,
+ "following_count": model.reblog_account_following_count,
+ "statuses_count": model.reblog_account_statuses_count,
+ "locked": model.reblog_account_locked,
+ "bot": model.reblog_account_bot,
+ "group": model.reblog_account_group
+ } )
+ }
}
}
}
+
+ // Display name, username, date of Toot
MiniHeader {
id: miniHeader
anchors {
@@ -106,24 +161,43 @@ BackgroundItem {
right: parent.right
}
}
- Text {
+
+ // Toot content
+ Label {
id: lblContent
+ visible: model.type !== "follow"
+ text: if (myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )) {
+ content
+ } else content.replace(new RegExp(" paintedHeight ? contentWarningLabel.paintedHeight : paintedHeight ) : 0
anchors {
left: miniHeader.left
leftMargin: Theme.paddingMedium
right: miniHeader.right
- rightMargin: Theme.horizontalPageMargin
+ rightMargin: Theme.horizontalPageMargin + Theme.paddingMedium
top: miniHeader.bottom
topMargin: Theme.paddingSmall
bottomMargin: Theme.paddingLarge
}
- height: content.length ? (contentWarningLabel.paintedHeight > paintedHeight ? contentWarningLabel.paintedHeight : paintedHeight) : 0
onLinkActivated: {
var test = link.split("/")
console.log(link)
console.log(JSON.stringify(test))
console.log(JSON.stringify(test.length))
-
if (test.length === 5 && (test[3] === "tags" || test[3] === "tag") ) {
pageStack.pop(pageStack.find(function(page) {
var check = page.isFirstPage === true;
@@ -134,36 +208,33 @@ BackgroundItem {
send(link)
// temporary solution for access to user profiles via toots
} else if (test.length === 4 && test[3][0] === "@" ) {
- tlSearch.search = decodeURIComponent("@"+test[3].substring(1)+"@"+test[2])
- slideshow.positionViewAtIndex(4, ListView.SnapToItem)
- navigation.navigateTo('search')
-
- // Original component
- /* pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
- "name": "",
- "username": test[3].substring(1)+"@"+test[2],
- "profileImage": ""
- }) */
-
+ pageStack.pop(pageStack.find(function(page) {
+ var check = page.isFirstPage === true;
+ if (check)
+ page.onLinkActivated(link)
+ return check;
+ }));
} else {
Qt.openUrlExternally(link);
}
}
- text: content.replace(new RegExp(" 0
+ anchors.fill: parent
+
Label {
id: contentWarningLabel
+ text: model.status_spoiler_text
font.pixelSize: Theme.fontSizeExtraSmall
+ color: Theme.highlightColor
+ truncationMode: TruncationMode.Fade
+ wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
+ width: parent.width
anchors {
topMargin: Theme.paddingSmall
left: parent.left
@@ -173,40 +244,43 @@ BackgroundItem {
rightMargin: Theme.paddingMedium
bottomMargin: Theme.paddingSmall
}
- width: parent.width
- truncationMode: TruncationMode.Fade
- color: Theme.highlightColor
- wrapMode: Text.Wrap
- text: model.status_spoiler_text
}
+
MouseArea {
anchors.fill: parent
- onClicked: parent.visible = false;
+ onClicked: parent.visible = false
}
-
}
}
+ // Displays media in Toots
MediaBlock {
id: media
+ visible: (myList.type === "notifications" && ( type === "favourite" || type === "reblog" )) ? false : true
+ model: typeof attachments !== "undefined" ? attachments : Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject')
+ height: Theme.iconSizeExtraLarge * 2
anchors {
left: lblContent.left
+ leftMargin: isPortrait ? 0 : Theme.itemSizeSmall
right: lblContent.right
+ rightMargin: isPortrait ? 0 : Theme.itemSizeLarge * 1.2
top: lblContent.bottom
- topMargin: Theme.paddingSmall
+ topMargin: Theme.paddingMedium
bottomMargin: Theme.paddingLarge
}
- model: typeof attachments !== "undefined" ? attachments : Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
- height: 100
}
+ // Context menu for Toots
ContextMenu {
id: mnu
+
MenuItem {
- enabled: model.type !== "follow"
- text: typeof model.reblogged !== "undefined" && model.reblogged ? qsTr("Unboost") : qsTr("Boost")
+ id: mnuBoost
+ visible: model.type !== "follow"
+ enabled: model.status_visibility !== "direct"
+ text: typeof model.status_reblogged !== "undefined" && model.status_reblogged ? qsTr("Unboost") : qsTr("Boost")
onClicked: {
- var status = typeof model.reblogged !== "undefined" && model.reblogged
+ var status = typeof model.status_reblogged !== "undefined" && model.status_reblogged
worker.sendMessage({
"conf" : Logic.conf,
"params" : [],
@@ -214,36 +288,40 @@ BackgroundItem {
"bgAction": true,
"action" : "statuses/"+model.status_id+"/" + (status ? "unreblog" : "reblog")
})
- model.reblogs_count = !status ? model.reblogs_count+1 : (model.reblogs_count > 0 ? model.reblogs_count-1 : model.reblogs_count);
- model.reblogged = !model.reblogged
+ model.status_reblogs_count = !status ? model.status_reblogs_count+1 : (model.status_reblogs_count > 0 ? model.status_reblogs_count-1 : model.status_reblogs_count);
+ model.status_reblogged = !model.status_reblogged
}
- Image {
+
+ Icon {
id: icRT
+ source: "image://theme/icon-s-retweet?" + (!model.status_reblogged ? Theme.highlightColor : Theme.primaryColor)
+ width: Theme.iconSizeSmall
+ height: width
anchors {
leftMargin: Theme.horizontalPageMargin
left: parent.left
verticalCenter: parent.verticalCenter
}
- width: Theme.iconSizeExtraSmall
- height: width
- source: "image://theme/icon-s-retweet?" + (!model.reblogged ? Theme.highlightColor : Theme.primaryColor)
}
+
Label {
+ text: status_reblogs_count
+ font.pixelSize: Theme.fontSizeSmall
+ color: !model.status_reblogged ? Theme.highlightColor : Theme.primaryColor
anchors {
left: icRT.right
leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter
}
- text: reblogs_count
- font.pixelSize: Theme.fontSizeExtraSmall
- color: !model.reblogged ? Theme.highlightColor : Theme.primaryColor
}
}
+
MenuItem {
- enabled: model.type !== "follow"
- text: typeof model.favourited !== "undefined" && model.favourited ? qsTr("Unfavorite") : qsTr("Favorite")
+ id: mnuFavourite
+ visible: model.type !== "follow"
+ text: typeof model.status_favourited !== "undefined" && model.status_favourited ? qsTr("Unfavorite") : qsTr("Favorite")
onClicked: {
- var status = typeof model.favourited !== "undefined" && model.favourited
+ var status = typeof model.status_favourited !== "undefined" && model.status_favourited
worker.sendMessage({
"conf" : Logic.conf,
"params" : [],
@@ -251,54 +329,129 @@ BackgroundItem {
"bgAction": true,
"action" : "statuses/"+model.status_id+"/" + (status ? "unfavourite" : "favourite")
})
- model.favourites_count = !status ? model.favourites_count+1 : (model.favourites_count > 0 ? model.favourites_count-1 : model.favourites_count);
- model.favourited = !model.favourited
+ model.status_favourites_count = !status ? model.status_favourites_count+1 : (model.status_favourites_count > 0 ? model.status_favourites_count-1 : model.status_favourites_count);
+ model.status_favourited = !model.status_favourited
}
- Image {
+
+ Icon {
id: icFA
+ source: "image://theme/icon-s-favorite?" + (!model.status_favourited ? Theme.highlightColor : Theme.primaryColor)
+ width: Theme.iconSizeSmall
+ height: width
anchors {
- leftMargin: Theme.horizontalPageMargin
left: parent.left
+ leftMargin: Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
- width: Theme.iconSizeExtraSmall
- height: width
- source: "image://theme/icon-s-favorite?" + (!model.favourited ? Theme.highlightColor : Theme.primaryColor)
}
+
Label {
+ text: status_favourites_count
+ font.pixelSize: Theme.fontSizeSmall
+ color: !model.status_favourited ? Theme.highlightColor : Theme.primaryColor
anchors {
left: icFA.right
leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter
}
- text: favourites_count
- font.pixelSize: Theme.fontSizeExtraSmall
- color: !model.favourited ? Theme.highlightColor : Theme.primaryColor
+ }
+ }
+
+ MenuItem {
+ id: mnuBookmark
+ visible: model.type !== "follow"
+ text: typeof model.status_bookmarked !== "undefined" && model.status_bookmarked ? qsTr("Remove Bookmark") : qsTr("Bookmark")
+ onClicked: {
+ var status = typeof model.status_bookmarked !== "undefined" && model.status_bookmarked
+ worker.sendMessage({
+ "conf" : Logic.conf,
+ "params" : [],
+ "method" : "POST",
+ "bgAction": true,
+ "action" : "statuses/"+model.status_id+"/" + (status ? "unbookmark" : "bookmark")
+ })
+ model.status_bookmarked = !model.status_bookmarked
+ }
+
+ Icon {
+ id: icBM
+ source: "../../images/icon-s-bookmark.svg?"
+ color: !model.status_bookmarked ? Theme.highlightColor : Theme.primaryColor
+ width: Theme.iconSizeSmall
+ height: width
+ anchors {
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin + Theme.paddingMedium
+ verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+
+ MenuItem {
+ id: mnuMention
+ visible: model.type === "follow"
+ text: qsTr("Mention")
+ onClicked: {
+ pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
+ headerTitle: qsTr("Mention"),
+ description: "@"+reblog_account_acct,
+ type: "new"
+ })
+ }
+
+ Icon {
+ id: icMT
+ source: "image://theme/icon-s-chat?" + (!model.status_favourited ? Theme.highlightColor : Theme.primaryColor)
+ width: Theme.iconSizeSmall
+ height: width
+ anchors {
+ left: parent.left
+ leftMargin: Theme.horizontalPageMargin + Theme.paddingMedium
+ verticalCenter: parent.verticalCenter
+ }
}
}
}
+ // Open ConversationPage and show other Toots in thread (if available) or ProfilePage if new Follower
onClicked: {
- var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
+ var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
if (typeof mdl !== "undefined")
m.append(mdl.get(index))
- pageStack.push(Qt.resolvedUrl("../Conversation.qml"), {
- headerTitle: "Conversation",
- toot_id: status_id,
- toot_url: status_url,
- title: account_display_name,
- description: '@'+account_acct,
- avatar: account_avatar,
- mdl: m,
- type: "reply"
- })
+
+ if (model.type !== "follow") {
+ pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
+ headerTitle: qsTr("Conversation"),
+ "status_id": status_id,
+ "status_url": status_url,
+ "status_uri": status_uri,
+ "username": '@'+account_acct,
+ mdl: m,
+ type: "reply"
+ })
+ } else pageStack.push(Qt.resolvedUrl("../ProfilePage.qml"), {
+ "display_name": model.account_display_name,
+ "username": model.account_acct,
+ "user_id": model.account_id,
+ "profileImage": model.account_avatar,
+ "profileBackground": model.account_header,
+ "note": model.account_note,
+ "url": model.account_url,
+ "followers_count": model.account_followers_count,
+ "following_count": model.account_following_count,
+ "statuses_count": model.account_statuses_count,
+ "locked": model.account_locked,
+ "bot": model.account_bot,
+ "group": model.account_group
+ } )
}
+
onPressAndHold: {
console.log(JSON.stringify(mdl.get(index)))
- mnu.show(delegate)
+ mnu.open(delegate)
}
+
onDoubleClicked: {
console.log("double click")
}
-
}
diff --git a/rpm/harbour-tooterb.changes b/rpm/harbour-tooterb.changes
index a42114a..4581a83 100644
--- a/rpm/harbour-tooterb.changes
+++ b/rpm/harbour-tooterb.changes
@@ -1,3 +1,53 @@
+*Sun Jul 12 2020 molan 1.0.7-0
+- Fix missing / wrong reblog and favourite counts in Retoots (issue #90)
+- Added full landscape support
+- Added new Pulley Menu options
+- Improved Toot context menu
+- Improved media page
+- Improved loading indicators
+- Small changes for some UI-elements
+- New Emojis
+- New translated strings
+
+*Fri Jun 18 2020 molan 1.0.6-3
+- Fix broken reblog indication
+
+*Fri Jun 18 2020 molan 1.0.6-2
+- Fix reported small UI issue
+- Updated translations
+
+*Thu Jun 18 2020 molan 1.0.6-1
+- Fix app crash when open some Profile pages
+- Fix sometimes missing favourite / reblog counts
+- Fix various QML warnings, replace deprecated Silica items
+- Add save to Bookmarks feature
+- Add Follows you / Locked / Bot / Group labels to Profile Page header
+- Add Bot icon to user display name
+- Add clicking on reblog-avatar opens reblog user profile
+- Remove Locked icon from user display name
+- Further improved Notification Page / general UI
+- Code refactoring & other changes under the hood
+- Translation updates
+
+*Fri Jun 12 2020 molan 1.0.5-1
+- [hotfix] fix missing images in mentions on Notification page
+
+*Thu Jun 11 2020 molan 1.0.5-0
+- fixed: show search results without entering # before term
+- fixed: non-clickable user mentions in Toots
+- fixed: Copy link to clipboard in Conversations
+- Notifications Page: Reworked UI and context menus for notifications
+- Profile Page: Open fullscreen profile image
+- Profile Page: Show bot label
+- Profile Page: New expander for Profile details
+- Conversation Page: Possibility to hide and reopen Toot text field
+- Conversation Page: Improved display of uploaded images
+- Media Page: Adjust size of images to screen width or height
+- Media Page: Only automatically restart videos if shorter than 30 seconds
+- new Settings Page
+- bigger custom emojis in Toots
+- overall improvement of UI
+
*Mon May 25 2020 molan 1.0.4-3
- Show user profile background image (if available)
- New Sailfish 3-styled image/video viewer page (WIP)
diff --git a/rpm/harbour-tooterb.spec b/rpm/harbour-tooterb.spec
index 60fef1f..4b290da 100644
--- a/rpm/harbour-tooterb.spec
+++ b/rpm/harbour-tooterb.spec
@@ -13,8 +13,8 @@ Name: harbour-tooterb
%{!?qtc_make:%define qtc_make make}
%{?qtc_builddir:%define _builddir %qtc_builddir}
Summary: Tooter β
-Version: 1.0.4
-Release: 3
+Version: 1.0.7
+Release: 0
Group: Qt/Qt
License: LICENSE
URL: http://example.org/
@@ -25,7 +25,10 @@ BuildRequires: pkgconfig(sailfishapp) >= 1.0.2
BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Qml)
BuildRequires: pkgconfig(Qt5Quick)
+BuildRequires: pkgconfig(Qt5DBus)
+BuildRequires: pkgconfig(Qt5Multimedia)
BuildRequires: pkgconfig(nemonotifications-qt5)
+BuildRequires: pkgconfig(openssl)
BuildRequires: desktop-file-utils
%description
diff --git a/rpm/harbour-tooterb.yaml b/rpm/harbour-tooterb.yaml
index 5e38bbb..927cb80 100644
--- a/rpm/harbour-tooterb.yaml
+++ b/rpm/harbour-tooterb.yaml
@@ -1,7 +1,7 @@
Name: harbour-tooterb
Summary: Tooter β
-Version: 1.0.4
-Release: 3
+Version: 1.0.7
+Release: 0
# The contents of the Group field should be one of the groups listed here:
# https://github.com/mer-tools/spectacle/blob/master/data/GROUPS
Group: Qt/Qt
@@ -25,12 +25,14 @@ PkgConfigBR:
- Qt5Core
- Qt5Qml
- Qt5Quick
+ - Qt5DBus
+ - Qt5Multimedia
- nemonotifications-qt5
-
+ - openssl
# Build dependencies without a pkgconfig setup can be listed here
-# PkgBR:
-# - package-needed-to-build
+# PkgBR:
+# - qt5-qtmultimedia-plugin-mediaservice-gstmediaplayer
# Runtime dependencies which are not automatically detected
Requires:
diff --git a/src/filedownloader.h b/src/filedownloader.h
index a8f5179..125ac84 100644
--- a/src/filedownloader.h
+++ b/src/filedownloader.h
@@ -24,7 +24,7 @@ class FileDownloader : public QObject
{
Q_OBJECT
public:
- explicit FileDownloader(QQmlEngine *engine, QObject *parent = 0);
+ explicit FileDownloader(QQmlEngine *engine, QObject *parent = nullptr);
Q_INVOKABLE void downloadFile(QUrl url, QString filename);
Q_INVOKABLE void open(QString filename);
diff --git a/src/imageuploader.cpp b/src/imageuploader.cpp
index 3153372..4e66a65 100644
--- a/src/imageuploader.cpp
+++ b/src/imageuploader.cpp
@@ -8,18 +8,17 @@
#include
#include
-//static const QUrl IMGUR_UPLOAD_URL("https://httpbin.org/post");
//static const QUrl IMGUR_UPLOAD_URL();
-ImageUploader::ImageUploader(QObject *parent) : QObject(parent), m_networkAccessManager(0), m_reply(0) {
+ImageUploader::ImageUploader(QObject *parent) : QObject(parent), m_networkAccessManager(nullptr), m_reply(nullptr) {
m_networkAccessManager = new QNetworkAccessManager(this);
}
ImageUploader::~ImageUploader() {
- if (m_reply != 0) {
+ if (m_reply != nullptr) {
m_reply->disconnect();
m_reply->deleteLater();
- m_reply = 0;
+ m_reply = nullptr;
}
}
@@ -58,10 +57,10 @@ void ImageUploader::upload() {
return;
}
- if (m_reply != 0) {
+ if (m_reply != nullptr) {
m_reply->disconnect();
m_reply->deleteLater();
- m_reply = 0;
+ m_reply = nullptr;
}
/*QFileInfo fileInfo(QUrl(m_fileName).toLocalFile());
@@ -101,12 +100,8 @@ void ImageUploader::upload() {
//imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(fileInfo));
-
-
//POST data
-
-
QNetworkRequest request(m_uploadUrl);
request.setRawHeader("Authorization", m_authorizationHeader);
m_reply = m_networkAccessManager->post(request, multiPart);
@@ -114,8 +109,6 @@ void ImageUploader::upload() {
connect(m_reply, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
-
-
//connect(m_reply, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
//connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));*/
}
@@ -146,6 +139,6 @@ void ImageUploader::replyFinished() {
}
m_reply->deleteLater();
- m_reply = 0;
+ m_reply = nullptr;
postdata.clear();
}
diff --git a/src/imageuploader.h b/src/imageuploader.h
index e530e48..86eda07 100644
--- a/src/imageuploader.h
+++ b/src/imageuploader.h
@@ -12,7 +12,7 @@ class ImageUploader : public QObject
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
public:
- explicit ImageUploader(QObject *parent = 0);
+ explicit ImageUploader(QObject *parent = nullptr);
~ImageUploader();
Q_INVOKABLE void setFile(const QString &fileName);
diff --git a/src/notifications.h b/src/notifications.h
index b22486a..524da9e 100644
--- a/src/notifications.h
+++ b/src/notifications.h
@@ -17,7 +17,7 @@ class Notifications : public QObject
{
Q_OBJECT
public:
- explicit Notifications(QObject *parent = 0);
+ explicit Notifications(QObject *parent = nullptr);
Q_INVOKABLE void notify(QString appName, QString summary, QString body, bool preview, QString ts, QString issuekey);
};
diff --git a/translations/harbour-tooterb-de.ts b/translations/harbour-tooterb-de.ts
index 0f08f63..ebe1c3c 100644
--- a/translations/harbour-tooterb-de.ts
+++ b/translations/harbour-tooterb-de.ts
@@ -21,23 +21,22 @@
- Conversation
+ ConversationPage
-
- Löschen
-
-
-
- Emojis
-
-
-
- Tippen um einzufügen
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ Link kopieren
+ placeholderText in Toot content warning panel
Inhaltswarnung
+
+
+ placeholderText in Toot text panel
+ Was gibt's Neues?
+
Öffentlich
@@ -54,24 +53,40 @@
Direktnachricht
-
-
- Was gibt's Neues?
-
Toot gesendet!
-
- Link kopieren
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Antworten
+
+
+
+ Antwort verbergen
+
+
+
+ Im Browser öffnen
- ImageFullScreen
+ CoverPage
-
- Ladefehler
+
+ Neuer Toot
+
+
+
+ EmojiSelect
+
+
+ Emojis
+
+
+
+ Tippen um einzufügen
@@ -115,8 +130,12 @@
Benachrichtigungen
-
- Neuer Toot
+
+ Lokal
+
+
+
+ Föderiert
@@ -127,12 +146,15 @@
@Benutzer oder #Ausdruck
-
- Lokal
+
+ Neuer Toot
+
+
+ MediaFullScreen
-
- Föderation
+
+ Ladefehler
@@ -152,88 +174,126 @@
MyList
-
-
- Lade mehr
-
Einstellungen
-
- Wird geladen
+
+ Neuer Toot
-
- bitte warten...
+
+ Neu laden
+
+
+
+ Im Browser öffnen
+
+
+
+ Nichts gefunden
- Profile
+ ProfileHeader
-
- Entfolgen
+
+ Bot
-
- Folge-Anfrage gesendet!
+
+ Folgt dir
-
- Folgt
+
+ Gruppe
+
+
+ ProfilePage
-
- Stummschalten
-
-
-
- Nicht stummschalten
-
-
-
- Nicht blockieren
-
-
-
- Blockieren
-
-
-
- Beiträge
-
-
-
- Favoriten
-
-
-
- Folgen
-
-
-
- Zusammenfassung
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ Details
+ Will show as: "35 Followers"
Folgende
-
- Bio
+
+ Will show as: "23 Following"
+ Folgt
-
- Profil im Browser öffnen
+
+ Will show as: "115 Statuses"
+ Beiträge
+
+
+
+ Erwähnen
+
+
+
+ Is a button. Keep it as short as possible.
+ Entfolgen
+
+
+
+ Is a button. Keep it as short as possible.
+ Angefragt
+
+
+
+ Is a button. Keep it as short as possible.
+ Folgen
+
+
+
+ Is a button. Keep it as short as possible.
+ Nicht stumm
+
+
+
+ Is a button. Keep it as short as possible.
+ Stumm schalten
+
+
+
+ Is a button. Keep it as short as possible.
+ Zulassen
+
+
+
+ Is a button. Keep it as short as possible.
+ Blockieren
- Settings
+ SettingsPage
Einstellungen
+
+
+ Optionen
+
+
+
+ Bilder in Toots laden
+
+
+
+ Diese Option deaktivieren um Datenvolumen zu sparen
+
+
+
+ Konto
+
Konto entfernen
@@ -243,7 +303,7 @@
Konto hinzufügen
-
+
Konto entfernen und für diese Anwendung deaktivieren
@@ -251,11 +311,12 @@
Zugriff durch diese Anwendung auf eigenes Mastodon-Konto erlauben
-
- Diese Option deaktivieren um Datenvolumen zu sparen
+
+ Übersetzungen
+ Translation alternative: "Development"
Über
@@ -266,10 +327,18 @@
Visuelle Identität
+
+
+ Entwicklung und Übersetzungen
+
Französische Übersetzung
+
+
+ Chinesische Übersetzung
+
Niederländische Übersetzung
@@ -279,43 +348,13 @@
Spanische Übersetzung
-
- Erstellung README-Datei
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Benutze
-
- Chinesische Übersetzung
-
-
-
- Bilder in Toots laden
-
-
-
- Übersetzungen
-
-
-
- Transifex benutzen um bei den Übersetzungen mitzuhelfen
-
-
-
- Entwicklung und Übersetzungen
-
-
-
- Toot
-
-
- hat geteilt
-
-
-
- hat favorisiert
-
-
-
- folgt dir
+
+ um bei den Übersetzungen mitzuhelfen.
@@ -336,5 +375,21 @@
Favorisieren
+
+
+ Erwähnen
+
+
+
+ Konversation
+
+
+
+ Lesezeichen entfernen
+
+
+
+ Lesezeichen
+
diff --git a/translations/harbour-tooterb-el.ts b/translations/harbour-tooterb-el.ts
index 104a1fd..a4a7b3b 100644
--- a/translations/harbour-tooterb-el.ts
+++ b/translations/harbour-tooterb-el.ts
@@ -21,21 +21,20 @@
- Conversation
+ ConversationPage
-
- Διαγραφή
-
-
-
- Emoji
-
-
-
- Κτυπήστε για εισαγωγή
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+
+ placeholderText in Toot content warning panel
+
+
+
+
+ placeholderText in Toot text panel
@@ -54,24 +53,40 @@
-
-
-
-
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+
+
+
+
+
+
+
+
- ImageFullScreen
+ CoverPage
-
-
+
+ Νέος
+
+
+
+ EmojiSelect
+
+
+ Emoji
+
+
+
+ Κτυπήστε για εισαγωγή
@@ -101,7 +116,7 @@
-
+ Επαναφόρτωση
@@ -115,8 +130,12 @@
Ειδοποιήσεις
-
- Νέος
+
+ Τοπικός
+
+
+
+
@@ -127,11 +146,14 @@
@χρήστη ή #όρος
-
-
+
+ Νέος
+
+
+ MediaFullScreen
-
+
@@ -152,88 +174,126 @@
MyList
-
-
- Φόρτωση περισσοτέρων
-
Ρυθμίσεις
-
- Φόρτωση
+
+ Νέος
-
+
+ Φόρτωση περισσοτέρων
+
+
+
+
+
+
+
- Profile
+ ProfileHeader
-
- Αναίρεση παρακολούθησης
+
+
-
- Η αίτηση παρακολούθησης εστάλη!
+
+
+
+
+
+
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+
+
+
+
+ Will show as: "35 Followers"
+ Σας ακολουθούν
+ Will show as: "23 Following"
Σε παρακολούθηση
-
- Σίγαση
+
+ Will show as: "115 Statuses"
+ Κατάσταση
+
+
+
+ Φραγή
+
+
+
+ Is a button. Keep it as short as possible.
+ Αναίρεση παρακολούθησης
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Παρακολούθηση
+ Is a button. Keep it as short as possible.
Αναίρεση σίγασης
+
+
+ Is a button. Keep it as short as possible.
+ Σίγαση
+
+ Is a button. Keep it as short as possible.
Αναίρεση φραγής
+ Is a button. Keep it as short as possible.
Φραγή
-
-
- Κατάσταση
-
-
-
- Σελιδοδείκτες
-
-
-
- Παρακολούθηση
-
-
-
- Σύνοψη
-
-
-
- Σας ακολουθούν
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Ρυθμίσεις
+
+
+
+
+
+
+
+
+
+
+ Απενεργοποιήστε αυτήν την επιλογή αν θέλετε να διατηρήσετε την σύνδεση των δεδομένων σας
+
+
+
+ λογαριασμού
+
Αφαίρεση λογαριασμού
@@ -243,7 +303,7 @@
Προσθήκη λογαριασμού
-
+
Άρση της αδειοδότησης της εφαρμογής και αφαίρεση του λογαριασμού σας
@@ -251,11 +311,12 @@
Να επιτρέπεται στην εφαρμογή να χρησιμοποιεί τον λογαριασμό σας στο Mastodon εκ μέρους σας
-
- Απενεργοποιήστε αυτήν την επιλογή αν θέλετε να διατηρήσετε την σύνδεση των δεδομένων σας
+
+ Μετάφραση
+ Translation alternative: "Development"
Ευχαριστίες
@@ -266,10 +327,18 @@
+
+
+
+
+
+
+
+
@@ -279,43 +348,13 @@
-
-
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Χρησιμοποιήστε το
-
-
-
-
-
-
-
-
-
- Μετάφραση
-
-
-
- Χρησιμοποιήστε το Transifex για να βοηθήσετε την μετάφραση της εφαρμογής στην γλώσσα σας
-
-
-
-
-
-
-
- Toot
-
-
- προωθημένο
-
-
-
- στους σελιδοδείκτες
-
-
-
- σας ακολουθούν
+
+ για να βοηθήσετε την μετάφραση της εφαρμογής στην γλώσσα σας.
@@ -336,5 +375,21 @@
Σελιδοδείκτης
+
+
+ Φραγή
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/harbour-tooterb-es.ts b/translations/harbour-tooterb-es.ts
index 86ab21a..92b07d4 100644
--- a/translations/harbour-tooterb-es.ts
+++ b/translations/harbour-tooterb-es.ts
@@ -21,23 +21,22 @@
- Conversation
+ ConversationPage
-
- Borrar
-
-
-
- Emoticonos
-
-
-
- Toca para insertar
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ Copiar enlace al portapapeles
+ placeholderText in Toot content warning panel
Escribe aquí tu advertencia
+
+
+ placeholderText in Toot text panel
+ ¿En qué estás pensando?
+
Público
@@ -54,24 +53,40 @@
Directo
-
-
- ¿En qué estás pensando?
-
¡Toot enviado!
-
- Copiar enlace al portapapeles
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Respuesta
+
+
+
+ Cerrar respuesta
+
+
+
+ Abrir en el navegador
- ImageFullScreen
+ CoverPage
-
- Error al cargar
+
+ Nuevo toot
+
+
+
+ EmojiSelect
+
+
+ Emoticonos
+
+
+
+ Toca para insertar
@@ -115,8 +130,12 @@
Notificaciones
-
- Nuevo toot
+
+ Local
+
+
+
+ Federada
@@ -127,12 +146,15 @@
@usuario o #término
-
- Local
+
+ Nuevo toot
+
+
+ MediaFullScreen
-
- Federada
+
+ Error al cargar
@@ -152,88 +174,126 @@
MyList
-
-
- Cargar más
-
Ajustes
-
- Cargando
+
+ Nuevo toot
-
- por favor, espera...
+
+ Volver a cargar
+
+
+
+ Abrir en el navegador
+
+
+
+ No encontrado nada
- Profile
+ ProfileHeader
-
- Dejar de seguir
+
+ Bot
-
- ¡Solicitud de seguidor enviada!
+
+ Te sigue
+
+
+
+ Grupo
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ Detalles
+
+
+
+ Will show as: "35 Followers"
+ Seguidores
+ Will show as: "23 Following"
Siguiendo
-
- Silenciar
+
+ Will show as: "115 Statuses"
+ Estados
+
+
+
+ Mencionar
+
+
+
+ Is a button. Keep it as short as possible.
+ Dejar de seguir
+
+
+
+ Is a button. Keep it as short as possible.
+ Requerido
+
+
+
+ Is a button. Keep it as short as possible.
+ Seguir
+ Is a button. Keep it as short as possible.
Dejar de silenciar
+
+
+ Is a button. Keep it as short as possible.
+ Silenciar
+
+ Is a button. Keep it as short as possible.
Desbloquear
+ Is a button. Keep it as short as possible.
Bloquear
-
-
- Estados
-
-
-
- Favoritos
-
-
-
- Seguir
-
-
-
- Resumen
-
-
-
- Seguidores
-
-
-
- Bio
-
-
-
- Abrir perfil en el navegador
-
- Settings
+ SettingsPage
Ajustes
+
+
+ Opciones
+
+
+
+ Cargar imágenes en messages
+
+
+
+ Deshabilita esta opción si quieres ahorrar en tu conexión de datos
+
+
+
+ Cuenta
+
Eliminar cuenta
@@ -243,7 +303,7 @@
Añadir cuenta
-
+
Retira la autorización a esta aplicación y elimina tu cuenta
@@ -251,11 +311,12 @@
Autoriza a esta aplicación para usar tu cuenta de Mastodon en tu nombre
-
- Deshabilita esta opción si quieres ahorrar en tu conexión de datos
+
+ Traducir
+ Translation alternative: "Development"
Créditos
@@ -266,10 +327,18 @@
Identidad visual
+
+
+ Desarrollo y traducciones
+
Traducción al occitano y francés
+
+
+ Traducción al chino
+
Traducción al holandés
@@ -279,43 +348,13 @@
Traducción al español
-
- Añadido archivo README
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Usar
-
- Traducción al chino
-
-
-
- Cargar imágenes en messages
-
-
-
- Traducir
-
-
-
- Usar Transifex para ayudar con traducciones
-
-
-
- Desarrollo y traducciones
-
-
-
- Toot
-
-
- retooteó
-
-
-
- marcó como favorito
-
-
-
- te empezó a seguir
+
+ para ayudar con traducciones.
@@ -336,5 +375,21 @@
Marcar como favorito
+
+
+ Mencionar
+
+
+
+ Conversación
+
+
+
+ Eliminar marcador
+
+
+
+ Marcador
+
diff --git a/translations/harbour-tooterb-fi.ts b/translations/harbour-tooterb-fi.ts
deleted file mode 100644
index 50a5f73..0000000
--- a/translations/harbour-tooterb-fi.ts
+++ /dev/null
@@ -1,340 +0,0 @@
-
-
-
-
- API
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Conversation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ImageFullScreen
-
-
-
-
-
-
- ImageUploader
-
-
-
-
-
-
- LoginPage
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- MainPage
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- MiniStatus
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- MyList
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Profile
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Toot
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- VisualContainer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/translations/harbour-tooterb-fr.ts b/translations/harbour-tooterb-fr.ts
index baafe35..5657178 100644
--- a/translations/harbour-tooterb-fr.ts
+++ b/translations/harbour-tooterb-fr.ts
@@ -21,23 +21,22 @@
- Conversation
+ ConversationPage
-
- Supprimer
-
-
-
- Emojis
-
-
-
- Appuyez pour insérer
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ Copier le lien
+ placeholderText in Toot content warning panel
Rédigez votre alerte ici
+
+
+ placeholderText in Toot text panel
+ Qu'avez-vous en tête?
+
Public
@@ -54,24 +53,40 @@
Direct
-
-
- Qu'avez-vous en tête?
-
Pouet envoyé !
-
- Copier le lien
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Répondre
+
+
+
+ Masquer la réponse
+
+
+
+ Ouvrir dans le navigateur
- ImageFullScreen
+ CoverPage
-
-
+
+ Nouveau pouet
+
+
+
+ EmojiSelect
+
+
+ Emojis
+
+
+
+ Appuyez pour insérer
@@ -115,8 +130,12 @@
Notifications
-
- Nouveau pouet
+
+ Fil public local
+
+
+
+ Fil public global
@@ -127,12 +146,15 @@
@personne ou #terme
-
- Fil public local
+
+ Nouveau pouet
+
+
+ MediaFullScreen
-
- Fil public global
+
+ Erreur au chargement
@@ -152,88 +174,126 @@
MyList
-
-
- Charger plus
-
Paramètres
-
- Chargement
+
+ Nouveau pouet
-
- patientez...
+
+ Recharger
+
+
+
+ Ouvrir dans le navigateur
+
+
+
+ Rien trouvé
- Profile
+ ProfileHeader
-
- Ne plus suivre
+
+ Bot
-
- Demande d’abonnement envoyée !
+
+ Vous suit
+
+
+
+ Groupe
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ Détails
+
+
+
+ Will show as: "35 Followers"
+ Abonné(e)s
+ Will show as: "23 Following"
Abonnements
-
- Masquer
+
+ Will show as: "115 Statuses"
+ Pouets
+
+
+
+ Mentionner
+
+
+
+ Is a button. Keep it as short as possible.
+ Ne plus suivre
+
+
+
+ Is a button. Keep it as short as possible.
+ Demandé
+
+
+
+ Is a button. Keep it as short as possible.
+ Suivre
+ Is a button. Keep it as short as possible.
Démasquer
+
+
+ Is a button. Keep it as short as possible.
+ Masquer
+
+ Is a button. Keep it as short as possible.
Débloquer
+ Is a button. Keep it as short as possible.
Bloquer
-
-
- Pouets
-
-
-
- Favoris
-
-
-
- Suivre
-
-
-
- Résumé
-
-
-
- Abonné(e)s
-
-
-
- Bio
-
-
-
- Ouvrir dans le navigateur
-
- Settings
+ SettingsPage
Paramètres
+
+
+ Options
+
+
+
+ Charger images dans les pouets
+
+
+
+ Désactiver cette option pour économiser des données mobiles
+
+
+
+ Compte
+
Déconnecter votre compte
@@ -243,7 +303,7 @@
Ajouter compte
-
+
Désautoriser cette application et enlever votre compte
@@ -251,11 +311,12 @@
Autoriser l’accès à votre compte pour cette application
-
- Désactiver cette option pour économiser des données mobiles
+
+ Traduire
+ Translation alternative: "Development"
Développement
@@ -266,10 +327,18 @@
Identité visuelle
+
+
+ Développement et traductions
+
Traduction français
+
+
+ Traduction chinoise
+
Traduction néerlandaise
@@ -279,43 +348,13 @@
Traduction espagnole
-
- Traduction chinoise
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Utiliser
-
- Fichier README ajouté
-
-
-
- Charger images dans les pouets
-
-
-
- Traduire
-
-
-
- Utiliser Transifex pour aider à traduire cette application
-
-
-
- Développement et traductions
-
-
-
- Toot
-
-
- a partagé
-
-
-
- a ajouté à ses favoris
-
-
-
- vous suit
+
+ pour aider à traduire cette application.
@@ -336,5 +375,21 @@
Ajouter aux favoris
+
+
+ Mentionner
+
+
+
+ Conversation
+
+
+
+ Retirer marque-page
+
+
+
+ Ajouter aux marque-pages
+
diff --git a/translations/harbour-tooterb-it.ts b/translations/harbour-tooterb-it.ts
index 67a9a56..9b7dfe8 100644
--- a/translations/harbour-tooterb-it.ts
+++ b/translations/harbour-tooterb-it.ts
@@ -4,97 +4,94 @@
API
-
ha apprezzato
-
ha iniziato a seguirti
-
ha condiviso
-
-
ha detto
- Conversation
+ ConversationPage
-
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
Copia link
-
+ placeholderText in Toot content warning panel
Contenuto avviso
-
+ placeholderText in Toot text panel
A cosa stai pensando?
-
-
- Elimina
-
-
-
Pubblico
-
Non elencato
-
Solo ai seguaci
-
Diretto
-
Toot è stato pubblicato!
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Rispondere
+
+
+
+ Chuidere risposta
+
+
+
+ Aprire nel browser
+
+
+
+ CoverPage
+
+
+ Nuovo Toot
+
+
+
+ EmojiSelect
+
Emojis
-
Tap per inserire
-
- ImageFullScreen
-
-
-
- Errore durante caricamento
-
-
ImageUploader
-
Il file %1 non esiste
@@ -102,27 +99,22 @@
LoginPage
-
Accesso
-
Istanza
-
Inserire URL di una istanza Mastodon valida
-
Mastodon è un servizio di rete sociale in software libero, costituito in una federazione d'istanze. Mastodon fa parte del più ampio Fediverso, permettendo ai suoi utenti di interagire anche con utenti su diverse piattaforme aperte che supportano lo stesso protocollo.
-
Ricarica
@@ -130,55 +122,52 @@
MainPage
-
Home
-
Notifiche
-
Locale
-
Federazione
-
Cerca
-
- @utente o #termine
+ @utente o #terme
-
- Nuovo toot
+ Nuovo Toot
+
+
+
+ MediaFullScreen
+
+
+ Errore durante caricamento
MiniStatus
-
ha condiviso
-
ha apprezzato
-
ha iniziato a seguirti
@@ -186,231 +175,221 @@
MyList
-
-
- Caricamento
-
-
-
-
- Attendere un momento...
-
-
-
Impostazioni
-
-
- Caricare altri
+
+ Nuovo Toot
+
+
+
+ Ricarica
+
+
+
+ Aprire nel browser
+
+
+
+ Niente trovato
- Profile
+ ProfileHeader
-
-
- Sintesi
+
+ Bot
+
+
+
+ Ti segue
+
+
+
+ Gruppo
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ Dettagli
-
+ Will show as: "35 Followers"
Seguaci
-
+ Will show as: "23 Following"
Segue
-
+ Will show as: "115 Statuses"
Toots
-
-
- Apprezzati
+
+ Menzionare
-
+ Is a button. Keep it as short as possible.
Smetti di seguire
-
-
- Richiesta di seguito inviata!
+
+ Is a button. Keep it as short as possible.
+ Richiesto
-
+ Is a button. Keep it as short as possible.
Segui
-
+ Is a button. Keep it as short as possible.
Non silenziare
-
+ Is a button. Keep it as short as possible.
Silenzia
-
+ Is a button. Keep it as short as possible.
Sblocca
-
+ Is a button. Keep it as short as possible.
Blocca
-
-
-
- Biografia
-
-
-
-
- Aprire profile nel browser
-
- Settings
+ SettingsPage
-
- Impostazione
+ Impostazioni
-
-
- Rimozione del account
+
+ Opzioni
-
-
- Aggiungi account
+
+ Caricare immagini nei Toots
-
-
- Annullare l'autorizzazione dell'app e rimuovere l'account
-
-
-
-
- Autorizzare l'app all'utilizzo del conto Mastodon
-
-
-
-
- Caricare immagini nei toots
-
-
-
Disabilitare questa opzione per conservare connessione dati
-
+
+ Account
+
+
+
+ Rimozione del account
+
+
+
+ Aggiungi account
+
+
+
+ Annullare l'autorizzazione dell'app e rimuovere l'account
+
+
+
+ Autorizzare l'app all'utilizzo del conto Mastodon
+
+
Tradurre
-
-
- Utilizzare Transifex per aiutare nella traduzione dell'app
-
-
-
+ Translation alternative: "Development"
Sviluppo
-
Design UI/UX e sviluppo
-
Identità visiva
-
Sviluppo e traduzioni
-
Traduzione francese e occitanica
-
Traduzione cinese
-
Traduzione olandese
-
Traduzione spagnola
-
-
- Aggiunto file README
-
-
-
- Toot
-
-
-
- ha condiviso
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Utilizzare
-
-
- ha apprezzato
-
-
-
-
- ha iniziato a seguirti
+
+ per aiutare nella traduzione dell'app.
VisualContainer
-
Annulla condivisione
-
Condividi
-
Annulla apprezzamento
-
Apprezzato
+
+
+ Menzionare
+
+
+
+ Conversazione
+
+
+
+ Elimina segnalibro
+
+
+
+ Aggiungi segnalibro
+
diff --git a/translations/harbour-tooterb-nl.ts b/translations/harbour-tooterb-nl.ts
index 9c3e4b0..e0bf1d1 100644
--- a/translations/harbour-tooterb-nl.ts
+++ b/translations/harbour-tooterb-nl.ts
@@ -21,11 +21,65 @@
- Conversation
+ ConversationPage
-
- Verwijderen
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ Linkadres kopiëren
+
+
+ placeholderText in Toot content warning panel
+ Waarschuwingstekst
+
+
+
+ placeholderText in Toot text panel
+ Wat wil je kwijt?
+
+
+
+ Openbaar
+
+
+
+ Minder openbaar
+
+
+
+ Alleen volgers
+
+
+
+ Direct
+
+
+
+ Toot verzonden!
+
+
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Antwoord
+
+
+
+ Antwoord verbergen
+
+
+
+ Open een Browser
+
+
+
+ CoverPage
+
+
+ Nieuwe Toot
+
+
+
+ EmojiSelect
Emojis
@@ -34,45 +88,6 @@
Tikken om in te voegen
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ImageFullScreen
-
-
-
-
ImageUploader
@@ -93,7 +108,7 @@
-
+ Geldig Mastodon URL
@@ -115,8 +130,12 @@
Meldingen
-
- Nieuwe Toot
+
+ Lokaal
+
+
+
+ Gefedereerd
@@ -127,12 +146,15 @@
@user of #term
-
- Lokaal
+
+ Nieuwe Toot
+
+
+ MediaFullScreen
-
- Gefedereerd
+
+ Laadfout
@@ -152,88 +174,126 @@
MyList
-
-
- Meer laden
-
Instellingen
-
- Laden
+
+ Nieuwe Toot
-
- even geduld…
+
+ Herladen
+
+
+
+ Open een Browser
+
+
+
+ Niets gevonden
- Profile
+ ProfileHeader
-
- Ontvolgen
+
+ Bot
-
- Volgverzoek verstuurd!
+
+ Volgt jou
+
+
+
+ Groep
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ Gegevens
+
+
+
+ Will show as: "35 Followers"
+ Volgers
+ Will show as: "23 Following"
Volgend
-
- Dempen
+
+ Will show as: "115 Statuses"
+ Statussen
+
+
+
+ Vermelden
+
+
+
+ Is a button. Keep it as short as possible.
+ Ontvolgen
+
+
+
+ Is a button. Keep it as short as possible.
+ Gevraagd
+
+
+
+ Is a button. Keep it as short as possible.
+ Volgen
+ Is a button. Keep it as short as possible.
Ontdempen
+
+
+ Is a button. Keep it as short as possible.
+ Dempen
+
+ Is a button. Keep it as short as possible.
Deblokkeren
+ Is a button. Keep it as short as possible.
Blokkeren
-
-
- Statussen
-
-
-
- Favorieten
-
-
-
- Volgen
-
-
-
- Samenvatting
-
-
-
- Volgers
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Instellingen
+
+
+ Opties
+
+
+
+ Laden afbeeldingen in toots
+
+
+
+ Schakel deze optie uit als je je dataverbinding wilt behouden
+
+
+
+ Account
+
Verwijderen account
@@ -243,7 +303,7 @@
Toevoegen account
-
+
Trek autorisaties van deze app in en verwijder je account
@@ -251,11 +311,12 @@
Autoriseer deze app om je Mastodon namens jou te gebruiken
-
- Schakel deze optie uit als je je dataverbinding wilt behouden
+
+ Vertalen
+ Translation alternative: "Development"
Credits
@@ -264,58 +325,36 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Laden afbeeldingen in toots
-
-
-
- Vertalen
-
-
-
- Gebruik Transifex om deze app te helpen vertalen in jouw taal
+ Visuele identiteit
Ontwikkeling en vertalingen
-
-
- Toot
-
- boostte
+
+ Occitaanse & Franse vertaling
-
- maakte favoriet
+
+ Chinese vertaling
-
- volgde jou
+
+ Nederlandse vertaling
+
+
+
+ Spaanse vertaling
+
+
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Gebruik
+
+
+
+ om deze app te helpen vertalen in jouw taal.
@@ -336,5 +375,21 @@
Markeren als favoriet
+
+
+ Vermelden
+
+
+
+ Conversatie
+
+
+
+ Bookmarken
+
+
+
+ Bladwijzer verwijderen
+
diff --git a/translations/harbour-tooterb-nl_BE.ts b/translations/harbour-tooterb-nl_BE.ts
index 25d9369..0089850 100644
--- a/translations/harbour-tooterb-nl_BE.ts
+++ b/translations/harbour-tooterb-nl_BE.ts
@@ -21,21 +21,20 @@
- Conversation
+ ConversationPage
-
- Verwijderen
-
-
-
- Emoji’s
-
-
-
- Tikt voor in te voegen
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+
+ placeholderText in Toot content warning panel
+
+
+
+
+ placeholderText in Toot text panel
@@ -54,24 +53,40 @@
-
-
-
-
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+
+
+
+
+
+
+
+
- ImageFullScreen
+ CoverPage
-
-
+
+ Nieuwen toot
+
+
+
+ EmojiSelect
+
+
+ Emojis
+
+
+
+ Tikt voor in te voegen
@@ -115,8 +130,12 @@
Meldingen
-
- Nieuwen toot
+
+ Lokaal
+
+
+
+ Gefedereerd
@@ -127,12 +146,15 @@
@gebruiker of #term
-
- Lokaal
+
+ Nieuwen toot
+
+
+ MediaFullScreen
-
- Gefedereerd
+
+
@@ -152,88 +174,126 @@
MyList
-
-
- Meer laden
-
Instellingen
-
- Laden
+
+ Nieuwen toot
-
- efkens geduld…
+
+ Herladen
+
+
+
+
+
+
+
+
- Profile
+ ProfileHeader
-
- Ontvolgen
+
+ Bot
-
- Volgverzoek verzonden!
+
+
+
+
+
+
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+
+
+
+
+ Will show as: "35 Followers"
+ Volgers
+ Will show as: "23 Following"
Volgend
-
- Dempen
+
+ Will show as: "115 Statuses"
+ Statussen
+
+
+
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Ontvolgen
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Volgen
+ Is a button. Keep it as short as possible.
Ontdempen
+
+
+ Is a button. Keep it as short as possible.
+ Dempen
+
+ Is a button. Keep it as short as possible.
Deblokkeren
+ Is a button. Keep it as short as possible.
Blokkeren
-
-
- Statussen
-
-
-
- Duimen
-
-
-
- Volgen
-
-
-
- Samenvatting
-
-
-
- Volgers
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Instellingen
+
+
+
+
+
+
+ Afbeeldingen in toots laden
+
+
+
+ Schakelt dees optie uit als ge uw verbinding wilt behouden
+
+
+
+ Account
+
Account verwijderen
@@ -243,7 +303,7 @@
Account toevoegen
-
+
Trekt autorisaties van dezen app in en verwijdert uwen account
@@ -251,11 +311,12 @@
Autoriseert dezen app voor uwe Mastodon-account namens u te gebruiken
-
- Schakelt dees optie uit als ge uw verbinding wilt behouden
+
+ Vertalen
+ Translation alternative: "Development"
Credits
@@ -266,10 +327,18 @@
+
+
+
+
+
+
+
+
@@ -279,43 +348,13 @@
-
-
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Gebruikt
-
-
-
-
-
- Afbeeldingen in toots laden
-
-
-
- Vertalen
-
-
-
- Gebruikt Transifex voor te helpen met dezen app in uw taal te vertalen
-
-
-
-
-
-
-
- Toot
-
-
- heeft geboost
-
-
-
- heeft geduimd voor
-
-
-
- volgt u nu
+
+ voor te helpen met dezen app in uw taal te vertalen.
@@ -336,5 +375,21 @@
Duim toevoegen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/harbour-tooterb-oc.ts b/translations/harbour-tooterb-oc.ts
index 3319228..81fb159 100644
--- a/translations/harbour-tooterb-oc.ts
+++ b/translations/harbour-tooterb-oc.ts
@@ -21,21 +21,20 @@
- Conversation
+ ConversationPage
-
- Escafar
-
-
-
- Emojis
-
-
-
- Tustejar per inserir
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+
+ placeholderText in Toot content warning panel
+
+
+
+
+ placeholderText in Toot text panel
@@ -54,24 +53,40 @@
-
-
-
-
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+
+
+
+
+
+
+
+
- ImageFullScreen
+ CoverPage
-
-
+
+ Nòu Tut
+
+
+
+ EmojiSelect
+
+
+ Emojis
+
+
+
+ Tustejar per inserir
@@ -108,31 +123,38 @@
MainPage
- Acuèlh
+
- Notificacions
-
-
-
- Nòu Tut
-
-
-
- Cercar
-
-
-
- @utilizaire o #tèrm
+
- Local
+
- Federat
+
+
+
+
+
+
+
+
+
+
+
+
+ Nòu Tut
+
+
+
+ MediaFullScreen
+
+
+
@@ -152,88 +174,126 @@
MyList
-
-
- Cargar mai
-
Parmètres
-
- Cargament
+
+ Nòu Tut
-
- esperatz....
+
+
+
+
+
+
+
+
+
+
- Profile
+ ProfileHeader
-
- Quitar de seguir
+
+ Bot
-
- Demanda de seguir enviada !
+
+
+
+
+
+
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+
+
+
+
+ Will show as: "35 Followers"
+ Seguidors
+ Will show as: "23 Following"
Abonaments
-
- Amagar
+
+ Will show as: "115 Statuses"
+ Estatuts
+
+
+
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Quitar de seguir
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Seguir
+ Is a button. Keep it as short as possible.
Mostrar
+
+
+ Is a button. Keep it as short as possible.
+ Amagar
+
+ Is a button. Keep it as short as possible.
Desblocar
+ Is a button. Keep it as short as possible.
Blocar
-
-
- Estatuts
-
-
-
- Favorits
-
-
-
- Seguir
-
-
-
- Resumit
-
-
-
- Seguidors
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Parmètres
+
+
+
+
+
+
+ Cargar los imatges dels tuts
+
+
+
+ Desactivar aquesta opcion per estalviar vòstra connexion de donadas
+
+
+
+ Compte
+
Levar un compte
@@ -243,7 +303,7 @@
Ajustar un compte
-
+
Revocar l’aplicacion e levar vòstre compte
@@ -251,11 +311,12 @@
Autorizar aquesta aplicacion a utilizar vòstre compte Mastodon per vos
-
- Desactivar aquesta opcion per estalviar vòstra connexion de donadas
+
+ Traduire
+ Translation alternative: "Development"
Crèdits
@@ -266,10 +327,18 @@
+
+
+
+
+
+
+
+
@@ -279,43 +348,13 @@
-
-
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Utilizar
-
-
-
-
-
- Cargar los imatges dels tuts
-
-
-
- Traduire
-
-
-
- Utilizar Transifex per ajudar a traduire l’aplicacion dins vòstra lenga
-
-
-
-
-
-
-
- Toot
-
-
- a tornat partejar
-
-
-
- a mes en favorit
-
-
-
- vos sèc
+
+ per ajudar a traduire l’aplicacion dins vòstra lenga.
@@ -336,5 +375,21 @@
Ajustar als favorits
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/harbour-tooterb-pl.ts b/translations/harbour-tooterb-pl.ts
index 4d7fe81..8c1140c 100644
--- a/translations/harbour-tooterb-pl.ts
+++ b/translations/harbour-tooterb-pl.ts
@@ -5,7 +5,7 @@
API
- dodał(a) do ulubionych
+ dodał(a) do ulubionych
@@ -21,21 +21,20 @@
- Conversation
+ ConversationPage
-
- Usuń
-
-
-
- Emoji
-
-
-
- Dotknij aby wstawić
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+
+ placeholderText in Toot content warning panel
+
+
+
+
+ placeholderText in Toot text panel
@@ -54,24 +53,40 @@
-
-
-
-
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+
+
+
+
+
+
+ Otwarte w przeglądarce
+
- ImageFullScreen
+ CoverPage
-
-
+
+ Nowy wpis
+
+
+
+ EmojiSelect
+
+
+ Emoji
+
+
+
+ Dotknij aby wstawić
@@ -85,7 +100,7 @@
LoginPage
-
+ Login
@@ -101,7 +116,7 @@
-
+ Załaduj ponownie
@@ -115,8 +130,12 @@
Powiadomienia
-
- Nowy wpis
+
+ Lokalne
+
+
+
+ Globalne
@@ -127,12 +146,15 @@
@użytkownik lub #tag
-
- Lokalne
+
+ Nowy wpis
+
+
+ MediaFullScreen
-
- Globalne
+
+
@@ -153,86 +175,124 @@
MyList
-
- Załaduj więcej
+
+ Ustawienia
+
+
+ Nowy wpis
+
+
+
+ Załaduj ponownie
+
+
+
+ Otwarte w przeglądarce
+
+
+
+ Nic nie znaleziono
+
+
+
+ ProfileHeader
+
+
+ Bot
+
+
+
+
+
+
+
+
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+
+
+
+
+ Will show as: "35 Followers"
+
+
+
+
+ Will show as: "23 Following"
+ Śledzisz
+
+
+
+ Will show as: "115 Statuses"
+
+
+
+
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Przestań śledzić
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Wycisz
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ SettingsPage
Ustawienia
-
- Ładowanie
-
-
-
- proszę czekać…
-
-
-
- Profile
-
-
- Przestań śledzić
-
-
-
- Wysłano prośbę o możliwość śledzenia!
-
-
-
- Śledzisz
-
-
-
- Wycisz
-
-
-
- Unmute
-
-
-
- Unblock
-
-
-
- Block
-
-
-
- Statuses
-
-
-
- Favourites
-
-
-
- Follow
-
-
-
- Summary
-
-
-
- Followers
-
-
-
+
-
+
-
-
- Settings
-
- Ustawienia
+
+
+
+
+
+
@@ -243,7 +303,7 @@
-
+
@@ -251,11 +311,12 @@
-
+
+ Translation alternative: "Development"
@@ -266,10 +327,18 @@
+
+
+
+
+
+
+
+
@@ -279,44 +348,14 @@
-
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Toot
-
-
- podbił(a)
-
-
-
- dodał(a) do ulubionych
-
-
-
- zaczął(-ęła Cię śledzić)
-
VisualContainer
@@ -336,5 +375,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/harbour-tooterb-ru.ts b/translations/harbour-tooterb-ru.ts
index d47095f..98a54ca 100644
--- a/translations/harbour-tooterb-ru.ts
+++ b/translations/harbour-tooterb-ru.ts
@@ -21,11 +21,65 @@
- Conversation
+ ConversationPage
-
- Удалить
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ Копировать ссылку
+
+
+ placeholderText in Toot content warning panel
+ Текст предупреждения
+
+
+
+ placeholderText in Toot text panel
+ О чём думаете?
+
+
+
+ Публичный
+
+
+
+ Скрытый
+
+
+
+ Приватный
+
+
+
+ Адресованный
+
+
+
+ Поста отправлено!
+
+
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Ответ
+
+
+
+ Скрыть ответ
+
+
+
+ Открыть в браузере
+
+
+
+ CoverPage
+
+
+ Новый
+
+
+
+ EmojiSelect
Cмайликов
@@ -34,45 +88,6 @@
Нажмите, чтобы вставить
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ImageFullScreen
-
-
-
-
ImageUploader
@@ -85,11 +100,11 @@
LoginPage
-
+ Авторизоваться
-
+ Экземпляра
@@ -101,7 +116,7 @@
-
+ Перезарядка
@@ -115,8 +130,12 @@
Уведомления
-
- Новый
+
+ Локальны
+
+
+
+ Федеративные
@@ -127,12 +146,15 @@
@пользователь или #срок
-
- Локальный
+
+ Новый
+
+
+ MediaFullScreen
-
- Федеративные
+
+ Ошибка при загрузке
@@ -152,88 +174,126 @@
MyList
-
-
- Загрузи больше
-
Настройки
-
- Загрузка
+
+ Новый
-
- Пожалуйста, подождите...
+
+ Перезагрузить
+
+
+
+ Открыть в браузере
+
+
+
+ Ничего не найдено
- Profile
+ ProfileHeader
-
- Отписаться
+
+ бот
-
- Следуйте запрошенному запросу!
+
+ Подписан(а) на вас
+
+
+
+ Группа
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ Подробности
+
+
+
+ Will show as: "35 Followers"
+ Читают
+ Will show as: "23 Following"
Следующий
-
- Безгласный
+
+ Will show as: "115 Statuses"
+ Статусы
+
+
+
+ Упоминание
+
+
+
+ Is a button. Keep it as short as possible.
+ Отписаться
+
+
+
+ Is a button. Keep it as short as possible.
+ Запрошенный
+
+
+
+ Is a button. Keep it as short as possible.
+ Следить
+ Is a button. Keep it as short as possible.
Нет безгласный
+
+
+ Is a button. Keep it as short as possible.
+ Безгласный
+
+ Is a button. Keep it as short as possible.
Открыть
+ Is a button. Keep it as short as possible.
Блокировать
-
-
- Статусы
-
-
-
- Избранные
-
-
-
- Следить
-
-
-
- Резюме
-
-
-
- Читают
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Настройки
+
+
+ Параметры
+
+
+
+ Загружать изображения
+
+
+
+ Отключите эту опцию, если вы хотите сохранить подключение к данным
+
+
+
+ Aккаунт
+
Удалить учетную запись
@@ -243,7 +303,7 @@
Добавить аккаунт
-
+
удалить учетную запись с устройства
@@ -251,11 +311,12 @@
Уполномочить это приложение использовать свою учетную запись Mastodon от вашего имени
-
- Отключите эту опцию, если вы хотите сохранить подключение к данным
+
+ Переведите
+ Translation alternative: "Development"
Зачет
@@ -264,58 +325,36 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Загружать изображения
-
-
-
- Переведите
-
-
-
- Используйте Transifex, чтобы помочь с переводом приложения на ваш язык
+ Визуальная идентичность
-
-
-
-
- Toot
-
-
- росту
+ Разработка и переводы
-
- имеет любимый
+
+ французский перевод
-
- следую за тобой
+
+ Китайский перевод
+
+
+
+ Голландский перевод
+
+
+
+ Испанский перевод
+
+
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Используйте
+
+
+
+ чтобы помочь с переводом приложения на ваш язык.
@@ -336,5 +375,21 @@
Избранные
+
+
+ Упоминание
+
+
+
+ беседа
+
+
+
+ Убрать из закладок
+
+
+
+ Добавить в закладки
+
diff --git a/translations/harbour-tooterb-sr.ts b/translations/harbour-tooterb-sr.ts
index 52a0d2c..11298c2 100644
--- a/translations/harbour-tooterb-sr.ts
+++ b/translations/harbour-tooterb-sr.ts
@@ -21,21 +21,20 @@
- Conversation
+ ConversationPage
-
- Обриши
-
-
-
- Емотикони
-
-
-
- Тапни за убацивање
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+
+ placeholderText in Toot content warning panel
+
+
+
+
+ placeholderText in Toot text panel
@@ -54,24 +53,40 @@
-
-
-
-
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+
+
+
+
+
+
+
+
- ImageFullScreen
+ CoverPage
-
-
+
+ Novi toot
+
+
+
+ EmojiSelect
+
+
+ Емотикони
+
+
+
+ Тапни за убацивање
@@ -101,7 +116,7 @@
-
+ учитај још
@@ -115,8 +130,12 @@
Обавјештење
-
- Novi toot
+
+ Локална
+
+
+
+ Федеративна
@@ -127,12 +146,15 @@
@korisnik ili #pojam
-
- Локална
+
+ Novi toot
+
+
+ MediaFullScreen
-
- Федеративна
+
+
@@ -152,88 +174,126 @@
MyList
-
-
- учитај још
-
Подешавања
-
- Učitavanje
+
+ Novi toot
-
- молимо вас, сачекајте...
+
+ учитај још
+
+
+
+
+
+
+
+
- Profile
+ ProfileHeader
-
- Одпрати
+
+
-
- Захтјев за праћењем поднесен!
+
+
+
+
+
+
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+
+
+
+
+ Will show as: "35 Followers"
+ Пратиоци
+ Will show as: "23 Following"
Пратите
-
- Утишај
+
+ Will show as: "115 Statuses"
+ Статуси
+
+
+
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Одпрати
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Прати
+ Is a button. Keep it as short as possible.
Укини утишање
+
+
+ Is a button. Keep it as short as possible.
+ Утишај
+
+ Is a button. Keep it as short as possible.
Одблокирати
+ Is a button. Keep it as short as possible.
Блокирати
-
-
- Статуси
-
-
-
- Омиљени
-
-
-
- Прати
-
-
-
- Детаљи
-
-
-
- Пратиоци
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Подешавања
+
+
+
+
+
+
+ Прикажи слике у објавама
+
+
+
+ Искључите ову опцију уколико желите да уштедите на преносу података
+
+
+
+ Hалог
+
Уклони налог
@@ -243,7 +303,7 @@
Додај налог
-
+
Укините дозволе за кориштење и уклоните налог с телефона
@@ -251,11 +311,12 @@
Дозволите овој апликацији да користи ваш Mastodon налог
-
- Искључите ову опцију уколико желите да уштедите на преносу података
+
+ Преведи
+ Translation alternative: "Development"
Спомен плоча
@@ -266,10 +327,18 @@
+
+
+
+
+
+
+
+
@@ -279,43 +348,13 @@
-
-
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Користите
-
-
-
-
-
- Прикажи слике у објавама
-
-
-
- Преведи
-
-
-
- Користите Transifex и помозите у преводу апликације на други језик
-
-
-
-
-
-
-
- Toot
-
-
- разглашено
-
-
-
- омиљено
-
-
-
- вас прати
+
+ и помозите у преводу апликације на други језик.
@@ -336,5 +375,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/harbour-tooterb-sv.ts b/translations/harbour-tooterb-sv.ts
index 5cd3f54..53b7f6e 100644
--- a/translations/harbour-tooterb-sv.ts
+++ b/translations/harbour-tooterb-sv.ts
@@ -21,21 +21,20 @@
- Conversation
+ ConversationPage
-
- Radera
-
-
-
- Emojis
-
-
-
- Tryck för att infoga
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+
+ placeholderText in Toot content warning panel
+
+
+
+
+ placeholderText in Toot text panel
@@ -54,24 +53,40 @@
-
-
-
-
-
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+
+
+
+
+
+
+
+
- ImageFullScreen
+ CoverPage
-
-
+
+ Ny toot
+
+
+
+ EmojiSelect
+
+
+ Emojis
+
+
+
+ Tryck för att infoga
@@ -101,7 +116,7 @@
-
+ Ladda mer
@@ -115,8 +130,12 @@
Notifieringar
-
- Ny toot
+
+ Lokalt
+
+
+
+ Förenade
@@ -127,12 +146,15 @@
@user eller #term
-
- Lokalt
+
+ Ny toot
+
+
+ MediaFullScreen
-
- Förenade
+
+
@@ -152,88 +174,126 @@
MyList
-
-
- Ladda mer
-
Inställningar
-
- Laddar
+
+ Ny toot
-
- Vänligen vänta...
+
+ Ladda mer
+
+
+
+
+
+
+
+
- Profile
+ ProfileHeader
-
- Sluta följa
+
+ Bot
-
- Följarförfrågan har skickats!
+
+
+
+
+
+
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+
+
+
+
+ Will show as: "35 Followers"
+ Följare
+ Will show as: "23 Following"
Följer
-
- Tysta
+
+ Will show as: "115 Statuses"
+ Statusar
+
+
+
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Sluta följa
+
+
+
+ Is a button. Keep it as short as possible.
+
+
+
+
+ Is a button. Keep it as short as possible.
+ Följ
+ Is a button. Keep it as short as possible.
Avtysta
+
+
+ Is a button. Keep it as short as possible.
+ Tysta
+
+ Is a button. Keep it as short as possible.
Avblockera
+ Is a button. Keep it as short as possible.
Blockera
-
-
- Statusar
-
-
-
- Favoriter
-
-
-
- Följ
-
-
-
- Översikt
-
-
-
- Följare
-
-
-
-
-
-
-
-
-
- Settings
+ SettingsPage
Inställningar
+
+
+
+
+
+
+ Ladda bilder i toots
+
+
+
+ Inaktivera det här alternativet om du vill behålla din dataanslutning
+
+
+
+ Konto
+
Radera konto
@@ -243,19 +303,20 @@
Lägg till konto
-
- Avauktorisera denna app och radera ditt konto
+
+ Avauktorisera denna app och radera ditt konto
Godkänn denna app att använda ditt Mastodon-konto på dina vägnar
-
- Inaktivera det här alternativet om du vill behålla din dataanslutning
+
+ Översätt
+ Translation alternative: "Development"
Erkännanden
@@ -266,10 +327,18 @@
+
+
+
+
+
+
+
+
@@ -279,43 +348,13 @@
-
-
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Använd
-
-
-
-
-
- Ladda bilder i toots
-
-
-
- Översätt
-
-
-
-
-
-
-
- Använd Transifex för att hjälpa med app-översättningar till ditt språk
-
-
-
- Toot
-
-
- puffade
-
-
-
- favoriserad
-
-
-
- följer dig
+
+ för att hjälpa med app-översättningar till ditt språk.
@@ -336,5 +375,21 @@
Favorisera
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/translations/harbour-tooterb-zh_CN.ts b/translations/harbour-tooterb-zh_CN.ts
index b92289e..050c9fc 100644
--- a/translations/harbour-tooterb-zh_CN.ts
+++ b/translations/harbour-tooterb-zh_CN.ts
@@ -21,23 +21,22 @@
- Conversation
+ ConversationPage
-
- 删除
-
-
-
- 表情
-
-
-
- 点击以插入
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ 复制链接到剪切板
+ placeholderText in Toot content warning panel
在此编写你的警告信息
+
+
+ placeholderText in Toot text panel
+ 有何想法?
+
公共区域
@@ -54,24 +53,40 @@
私信
-
-
- 有何想法?
-
-
+ 已发送嘟嘟!
-
- 复制链接到剪切板
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ 回复
+
+
+
+ 隐藏回复
+
+
+
+ 在浏览器打开个人简介
- ImageFullScreen
+ CoverPage
-
-
+
+ 新嘟嘟
+
+
+
+ EmojiSelect
+
+
+ 表情
+
+
+
+ 点击以插入
@@ -115,8 +130,12 @@
通知
-
- 新嘟嘟
+
+ 本地
+
+
+
+ 联合
@@ -127,12 +146,15 @@
@用户或#项目
-
- 本地
+
+ 新嘟嘟
+
+
+ MediaFullScreen
-
- 联合
+
+ 加载错误
@@ -152,88 +174,126 @@
MyList
-
-
- 加载更多
-
设置
-
- 加载中
+
+ 新嘟嘟
-
- 稍等片刻......
+
+ 重新加载
+
+
+
+ 在浏览器打开个人简介
+
+
+
+ 没有发现任何东西
- Profile
+ ProfileHeader
-
- 取消关注
+
+ 机器人
-
- 已寄出关注请求!
+
+ 关注你
+
+
+
+ 群组
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ 关于
+
+
+
+ Will show as: "35 Followers"
+ 关注者
+ Will show as: "23 Following"
关注中
-
- 静音
+
+ Will show as: "115 Statuses"
+ 状态
+
+
+
+ 提及
+
+
+
+ Is a button. Keep it as short as possible.
+ 取消关注
+
+
+
+ Is a button. Keep it as short as possible.
+ 请求
+
+
+
+ Is a button. Keep it as short as possible.
+ 关注
+ Is a button. Keep it as short as possible.
未静音
+
+
+ Is a button. Keep it as short as possible.
+ 静音
+
+ Is a button. Keep it as short as possible.
解除封锁
+ Is a button. Keep it as short as possible.
封锁
-
-
- 状态
-
-
-
- 收藏
-
-
-
- 关注
-
-
-
- 摘要
-
-
-
- 关注者
-
-
-
- 简介
-
-
-
- 在浏览器打开个人简介
-
- Settings
+ SettingsPage
设置
+
+
+ 选项
+
+
+
+ 加载嘟嘟图片
+
+
+
+ 如果你想保护你的数据连接,请禁用此选项
+
+
+
+ 账号
+
移除账号
@@ -243,7 +303,7 @@
添加账号
-
+
取消授权此软件并移除你的账号
@@ -251,11 +311,12 @@
授权此软件使用你的 Mastodon 账号
-
- 如果你想保护你的数据连接,请禁用此选项
+
+ 翻译
+ Translation alternative: "Development"
信誉
@@ -266,10 +327,18 @@
视觉识别
+
+
+ 开发及翻译
+
奥克西坦语及法语翻译
+
+
+ 汉语翻译
+
尼德兰语翻译
@@ -279,43 +348,13 @@
西班牙语翻译
-
- 添加 README 文件
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ 使用
-
- 汉语翻译
-
-
-
-
-
-
-
-
-
-
-
- 使用 Transifex 以帮助翻译软件为你的语言
-
-
-
- 开发及翻译
-
-
-
- Toot
-
-
- 推起
-
-
-
- 收藏
-
-
-
- 关注你
+
+ 以帮助翻译软件为你使用的语言.
@@ -336,5 +375,21 @@
关注
+
+
+ 提及
+
+
+
+ 对话
+
+
+
+ 移除收藏
+
+
+
+ 收藏
+
diff --git a/translations/harbour-tooterb.ts b/translations/harbour-tooterb.ts
index 0bf8406..49f0835 100644
--- a/translations/harbour-tooterb.ts
+++ b/translations/harbour-tooterb.ts
@@ -1,6 +1,6 @@
-
+
API
@@ -21,11 +21,65 @@
- Conversation
+ ConversationPage
-
- Delete
+
+ Use the translation of "Copy Link" for a shorter PullDownMenu label
+ Copy Link to Clipboard
+
+
+ placeholderText in Toot content warning panel
+ Write your warning here
+
+
+
+ placeholderText in Toot text panel
+ What's on your mind?
+
+
+
+ Public
+
+
+
+ Unlisted
+
+
+
+ Followers-only
+
+
+
+ Direct
+
+
+
+ Toot sent!
+
+
+
+ "Reply" will show the Toot text entry Panel. "Hide Reply" closes it. Alternative: Use "Close Reply"
+ Reply
+
+
+
+ Hide Reply
+
+
+
+ Open in Browser
+
+
+
+ CoverPage
+
+
+ New Toot
+
+
+
+ EmojiSelect
Emojis
@@ -34,45 +88,6 @@
Tap to insert
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ImageFullScreen
-
-
-
-
ImageUploader
@@ -85,54 +100,61 @@
LoginPage
-
+ Login
-
+ Instance
-
+ Enter a valid Mastodon instance URL
-
+ Mastodon is a free, open-source social network. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Pick a server that you trust — whichever you choose, you can interact with everyone else. Anyone can run their own Mastodon instance and participate in the social network seamlessly.
-
+ Reload
MainPage
-
+ Home
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Notifications
-
+ Local
-
+ Federated
+
+
+
+ Search
+
+
+
+ @user or #term
+
+
+
+ New Toot
+
+
+
+ MediaFullScreen
+
+
+ Error loading
@@ -153,188 +175,221 @@
MyList
-
- Load more
+
+ Settings
+
+
+ New Toot
+
+
+
+ Reload
+
+
+
+ Open in Browser
+
+
+
+ Nothing found
+
+
+
+ ProfileHeader
+
+
+ Bot
+
+
+
+ Follows you
+
+
+
+ Group
+
+
+
+ ProfilePage
+
+
+ If there's no good translation for "About", use "Details" (in details about profile).
+ About
+
+
+
+ Will show as: "35 Followers"
+ Followers
+
+
+
+ Will show as: "23 Following"
+ Following
+
+
+
+ Will show as: "115 Statuses"
+ Statuses
+
+
+
+ Mention
+
+
+
+ Is a button. Keep it as short as possible.
+ Unfollow
+
+
+
+ Is a button. Keep it as short as possible.
+ Requested
+
+
+
+ Is a button. Keep it as short as possible.
+ Follow
+
+
+
+ Is a button. Keep it as short as possible.
+ Unmute
+
+
+
+ Is a button. Keep it as short as possible.
+ Mute
+
+
+
+ Is a button. Keep it as short as possible.
+ Unblock
+
+
+
+ Is a button. Keep it as short as possible.
+ Block
+
+
+
+ SettingsPage
Settings
-
-
+
+ Options
-
-
-
-
-
- Profile
-
-
- Unfollow
-
-
-
- Follow request sent!
-
-
-
- Following
-
-
-
- Mute
-
-
-
- Unmute
-
-
-
- Unblock
-
-
-
- Block
-
-
-
- Statuses
-
-
-
- Favourites
-
-
-
- Follow
-
-
-
- Summary
-
-
-
- Followers
-
-
-
-
-
-
-
-
-
-
-
- Settings
-
-
- Settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ Load Images in Toots
-
+ Disable this option if you want to preserve your data connection
-
-
+
+ Account
-
-
+
+ Remove Account
-
-
+
+ Add Account
-
-
+
+ Deauthorize this app from using your account and remove account data from phone
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ Authorize this app to access your Mastodon account
-
+ Translate
-
-
+
+ Translation alternative: "Development"
+ Credits
+
+
+
+ UI/UX design and development
+
+
+
+ Visual identity
-
-
-
-
- Toot
-
-
- boosted
+ Development and translations
-
- favourited
+
+ Occitan & French translation
-
- followed you
+
+ Chinese translation
+
+
+
+ Dutch translation
+
+
+
+ Spanish translation
+
+
+
+ Full sentence for translation: "Use Transifex to help with app translation to your language." - The word Transifex is a link and doesn't need translation.
+ Use
+
+
+
+ to help with app translation to your language.
VisualContainer
-
+ Unboost
-
+ Boost
-
+ Unfavourite
-
+ Favourite
+
+
+
+ Mention
+
+
+
+ Conversation
+
+
+
+ Remove Bookmark
+
+
+
+ Bookmark