Merge pull request #75 from molan-git/ui-improvements

ui-improvements and fixes
This commit is contained in:
molan-git 2020-06-11 14:32:31 +02:00 committed by GitHub
commit f6527d04f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 2022 additions and 1507 deletions

View file

@ -4,8 +4,3 @@ X-Nemo-Application-Type=silica-qt5
Icon=harbour-tooter
Exec=harbour-tooter
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).

View file

@ -1,116 +1,116 @@
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = harbour-tooter
CONFIG += sailfishapp
QT += network dbus sql
CONFIG += link_pkgconfig
PKGCONFIG += sailfishapp
PKGCONFIG += \
nemonotifications-qt5
DEFINES += "APPVERSION=\\\"$${SPECVERSION}\\\""
DEFINES += "APPNAME=\\\"$${TARGET}\\\""
!exists( src/dbusAdaptor.h ) {
system(qdbusxml2cpp config/ba.dysko.harbour.tooter.xml -i dbus.h -a src/dbusAdaptor)
}
config.path = /usr/share/$${TARGET}/config/
config.files = config/icon-lock-harbour-tooter.png
notification_categories.path = /usr/share/lipstick/notificationcategories
notification_categories.files = config/x-harbour.tooter.activity.*
dbus_services.path = /usr/share/dbus-1/services/
dbus_services.files = config/ba.dysko.harbour.tooter.service
interfaces.path = /usr/share/dbus-1/interfaces/
interfaces.files = config/ba.dysko.harbour.tooter.xml
SOURCES += src/harbour-tooter.cpp
SOURCES += src/imageuploader.cpp
SOURCES += src/filedownloader.cpp
SOURCES += src/notifications.cpp
SOURCES += src/dbusAdaptor.cpp
SOURCES += src/dbus.cpp
HEADERS += src/imageuploader.h
HEADERS += src/filedownloader.h
HEADERS += src/notifications.h
HEADERS += src/dbusAdaptor.h
HEADERS += src/dbus.h
DISTFILES += qml/harbour-tooter.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/tooter.svg \
qml/images/emojiselect.svg \
qml/images/icon-m-profile.svg \
qml/images/icon-l-profile.svg \
qml/lib/Mastodon.js \
qml/lib/Worker.js \
config/icon-lock-harbour-tooter.png \
config/x-harbour.tooter.activity.conf \
rpm/harbour-tooter.changes \
rpm/harbour-tooter.changes.run.in \
rpm/harbour-tooter.spec \
rpm/harbour-tooter.yaml \
translations/*.ts \
harbour-tooter.desktop
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the
# 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-tooter-de.ts
TRANSLATIONS += translations/harbour-tooter-el.ts
TRANSLATIONS += translations/harbour-tooter-es.ts
TRANSLATIONS += translations/harbour-tooter-fi.ts
TRANSLATIONS += translations/harbour-tooter-fr.ts
TRANSLATIONS += translations/harbour-tooter-nl.ts
TRANSLATIONS += translations/harbour-tooter-nl_BE.ts
TRANSLATIONS += translations/harbour-tooter-oc.ts
TRANSLATIONS += translations/harbour-tooter-pl.ts
TRANSLATIONS += translations/harbour-tooter-ru.ts
TRANSLATIONS += translations/harbour-tooter-sr.ts
TRANSLATIONS += translations/harbour-tooter-sv.ts
TRANSLATIONS += translations/harbour-tooter-zh_CN.ts
TRANSLATIONS += translations/harbour-tooter-it.ts
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = harbour-tooter
CONFIG += sailfishapp
QT += network dbus sql
CONFIG += link_pkgconfig
PKGCONFIG += sailfishapp
PKGCONFIG += \
nemonotifications-qt5
DEFINES += "APPVERSION=\\\"$${SPECVERSION}\\\""
DEFINES += "APPNAME=\\\"$${TARGET}\\\""
!exists( src/dbusAdaptor.h ) {
system(qdbusxml2cpp config/ba.dysko.harbour.tooter.xml -i dbus.h -a src/dbusAdaptor)
}
config.path = /usr/share/$${TARGET}/config/
config.files = config/icon-lock-harbour-tooter.png
notification_categories.path = /usr/share/lipstick/notificationcategories
notification_categories.files = config/x-harbour.tooter.activity.*
dbus_services.path = /usr/share/dbus-1/services/
dbus_services.files = config/ba.dysko.harbour.tooter.service
interfaces.path = /usr/share/dbus-1/interfaces/
interfaces.files = config/ba.dysko.harbour.tooter.xml
SOURCES += src/harbour-tooter.cpp
SOURCES += src/imageuploader.cpp
SOURCES += src/filedownloader.cpp
SOURCES += src/notifications.cpp
SOURCES += src/dbusAdaptor.cpp
SOURCES += src/dbus.cpp
HEADERS += src/imageuploader.h
HEADERS += src/filedownloader.h
HEADERS += src/notifications.h
HEADERS += src/dbusAdaptor.h
HEADERS += src/dbus.h
DISTFILES += qml/harbour-tooter.qml \
qml/images/tooter-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/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/cover/CoverPage.qml \
qml/pages/MainPage.qml \
qml/pages/LoginPage.qml \
qml/pages/components/Toot.qml \
qml/pages/Browser.qml \
qml/lib/API.js \
qml/images/icon-s-following \
qml/images/icon-m-emoji.svg \
qml/images/icon-m-profile.svg \
qml/images/icon-l-profile.svg \
qml/lib/Mastodon.js \
qml/lib/Worker.js \
config/icon-lock-harbour-tooter.png \
config/x-harbour.tooter.activity.conf \
rpm/harbour-tooter.changes \
rpm/harbour-tooter.changes.run.in \
rpm/harbour-tooter.spec \
rpm/harbour-tooter.yaml \
translations/*.ts \
harbour-tooter.desktop
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the
# 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-tooter-de.ts
TRANSLATIONS += translations/harbour-tooter-el.ts
TRANSLATIONS += translations/harbour-tooter-es.ts
TRANSLATIONS += translations/harbour-tooter-fi.ts
TRANSLATIONS += translations/harbour-tooter-fr.ts
TRANSLATIONS += translations/harbour-tooter-nl.ts
TRANSLATIONS += translations/harbour-tooter-nl_BE.ts
TRANSLATIONS += translations/harbour-tooter-oc.ts
TRANSLATIONS += translations/harbour-tooter-pl.ts
TRANSLATIONS += translations/harbour-tooter-ru.ts
TRANSLATIONS += translations/harbour-tooter-sr.ts
TRANSLATIONS += translations/harbour-tooter-sv.ts
TRANSLATIONS += translations/harbour-tooter-zh_CN.ts
TRANSLATIONS += translations/harbour-tooter-it.ts

View file

@ -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/tooter.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;
}
}
}

View file

@ -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,19 @@ 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()
}
}
}

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 36 36" enable-background="new 0 0 36 36" xml:space="preserve">
<g>
<g>
<path fill="#FFFFFF" d="M28.8,12.5c-1.8,0-4.6,0-6.3,0c-0.5,0-1.5,0-0.8-1.1c1-1.9,3-5.9,4.3-8.1c0.7-1.1,0.8-1.8-0.4-1.8
c-2.7,0-9.1,0-12,0c-1.1,0-1.6,0.5-2.1,1.6c-1.4,3.5-4.7,12.1-5.9,15.7c-0.4,1.2,0.3,1.7,1.2,1.7c1.8,0,5,0,6.7,0
c0.6,0,1.2,0.1,0.8,1.4c-0.8,2.3-2,7-2.8,9.7c0,0-0.8,3.7,2.4,0.8C18.1,28.2,25.4,17.7,29,14C29.7,13.4,29.7,12.5,28.8,12.5z
M20.7,21.1c-2.2,2.8-4.4,5.7-6.3,7.8c0.1-0.2,0.1-0.5,0.2-0.7c0.6-2.1,1.2-4.3,1.7-5.7l0,0l0,0c0.3-1.2,0.2-2.1-0.3-2.9
c-0.5-0.7-1.4-1.1-2.4-1.1H7.9c1.3-3.7,3.9-10.4,5.2-13.8l0.3-0.8c0.1-0.2,0.2-0.3,0.2-0.4c0,0,0,0,0,0h10
c-1.2,2.2-2.7,5.2-3.6,6.9c-0.7,1.3-0.5,2.2-0.2,2.8c0.7,1.3,2.2,1.3,2.7,1.3h3.4C24.4,16.3,22.6,18.6,20.7,21.1z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 886 B

After

Width:  |  Height:  |  Size: 886 B

View file

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title>Artboard 1</title>
<g>
<rect x="-2" y="-2" width="36.2" height="36.2" fill="#fff" fill-opacity="0"/>
<g>
<path d="M22.9,11.3a6.8,6.8,0,1,1-6.8-6.8A6.74,6.74,0,0,1,22.9,11.3Z" fill="#fff"/>
<g opacity="0.6">
<path d="M28,26.6v.6H4.3v-.6a6.23,6.23,0,0,1,6.2-6.2H21.8A6.24,6.24,0,0,1,28,26.3Z" fill="#fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 451 B

View file

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="15 0 60 60" enable-background="new 15 0 60 60" xml:space="preserve">
<path id="Home" display="none" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linejoin="round" stroke-miterlimit="10" d="
M42,7.7l-18.6,15c-0.3,0.3-0.5,0.7-0.5,1V52c0,0.8,0.7,1.4,1.4,1.4h12.4c0.8,0,1.4-0.7,1.4-1.4V34.1c0-0.7,0.7-1.4,1.4-1.4h11.1
c0.8,0,1.4,0.7,1.4,1.4V52c0,0.8,0.7,1.4,1.4,1.4h12.4c0.8,0,1.4-0.7,1.4-1.4V23.7c0-0.4-0.2-0.8-0.5-1l-18.5-15
C46.3,6.2,43.7,6.2,42,7.7z"/>
<g id="Local" display="none">
<circle display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linejoin="round" stroke-miterlimit="10" cx="45" cy="26.1" r="6.9"/>
<path display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linejoin="round" stroke-miterlimit="10" d="M45,6.8
c10.7,0,19.3,8.6,19.3,19.3c0,2.8-0.6,5.4-1.7,7.9c-0.8,2-2.1,3.8-3.6,5.3l-14,14l-14.1-14c-1.5-1.6-2.7-3.4-3.6-5.3
c-1-2.4-1.7-5.1-1.7-7.9C25.7,15.4,34.3,6.8,45,6.8z"/>
</g>
<g id="Federation" display="none">
<circle display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" cx="45" cy="30" r="23.4"/>
<ellipse display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" cx="45" cy="30" rx="12.4" ry="23.4"/>
<path display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M61.5,13.4
c-2.6,4.1-9.5,6.9-16.5,6.9s-13.9-2.8-16.5-6.9"/>
<path display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M28.5,46.6
c2.6-4.1,9.5-6.9,16.5-6.9s13.9,2.8,16.5,6.9"/>
<line display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" x1="21.6" y1="30" x2="68.4" y2="30"/>
<line display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" x1="45" y1="6.6" x2="45" y2="53.4"/>
</g>
<g id="Search" display="none">
<circle display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linejoin="round" stroke-miterlimit="10" cx="42.3" cy="27.3" r="19.3"/>
<line display="inline" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linejoin="round" stroke-miterlimit="10" x1="67" y1="52" x2="56.1" y2="41.1"/>
</g>
<path id="Notification_1_" fill="none" stroke="#FFFFFF" stroke-width="3" stroke-linejoin="round" stroke-miterlimit="10" d="
M56.3,49.9c1.9,2.2,4.6,3.5,7.7,3.5c2.1,0,3.9-0.6,5.5-1.7c-3.2-1.8-5.4-5-6.1-8.7c2.5-3.8,3.9-8.2,3.9-13
C67.4,17.1,56.9,6.6,44,6.6S20.5,17,20.5,29.9S31,53.3,43.8,53.3C48.5,53.3,52.8,52,56.3,49.9z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve">
<path fill="#FFFFFF" d="M47.7,22.5c-0.2-0.8-0.5-1.6-1-2.3c-0.5-0.7-1-1.3-1.6-1.9s-1.3-1-2.1-1.4c0.1-0.2,0.2-0.5,0.3-0.7
c0-0.3,0.1-0.5,0.2-0.8s0.1-0.5,0.1-0.8s0-0.6,0.1-0.8c0-1.3-0.3-2.5-0.7-3.6c-0.4-1.1-1-2.1-1.9-2.9s-1.7-1.5-2.8-2
c-1-0.5-2.2-0.7-3.4-0.7c-0.3,0-0.5,0-0.8,0c-0.3,0-0.5,0.1-0.8,0.1c-0.2,0-0.5,0.1-0.8,0.2S32.1,5,31.9,5.1
c-0.4-0.8-0.9-1.4-1.4-2.1s-1.1-1.2-1.8-1.6s-1.4-0.8-2.2-1C25.7,0.1,24.9,0,24,0c-0.8,0-1.7,0.1-2.5,0.4S20,1,19.3,1.4
c-0.7,0.4-1.3,1-1.8,1.6c-0.6,0.6-1,1.3-1.3,2.1c-0.3-0.1-0.5-0.2-0.8-0.2c-0.2-0.1-0.5-0.1-0.8-0.2c-0.3,0-0.5-0.1-0.8-0.1
c-0.2,0-0.5,0-0.8,0c-1.1,0-2.3,0.2-3.4,0.7c-1.1,0.5-2,1.1-2.8,2S5.5,9,5,10.1s-0.7,2.3-0.7,3.6c0,0.3,0,0.5,0,0.8s0.1,0.6,0.1,0.8
c0,0.3,0.1,0.5,0.2,0.8c0.1,0.3,0.2,0.5,0.2,0.7c-0.7,0.4-1.3,0.9-2,1.4s-1.2,1.2-1.6,1.9c-0.4,0.7-0.7,1.5-1,2.3
C0.1,23.4,0,24.3,0,25.2c0,0.8,0.1,1.7,0.3,2.5s0.5,1.5,0.9,2.2s0.8,1.3,1.4,1.9s1.2,1,1.8,1.4c0,0.1,0,0.2,0,0.3s-0.1,0.2,0,0.3
c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3c0,1.2,0.2,2.4,0.7,3.5C5.5,39,6.2,40,6.9,40.8s1.7,1.5,2.8,2s2.2,0.7,3.4,0.7
c0.3,0,0.6,0,0.8,0c0.2,0,0.5-0.1,0.8-0.1c0.3,0,0.5-0.1,0.8-0.2c0.2-0.1,0.5-0.2,0.8-0.3c0.3,0.8,0.7,1.5,1.3,2.1
c0.6,0.6,1.2,1.2,1.8,1.6c0.7,0.5,1.4,0.8,2.2,1.1s1.6,0.4,2.5,0.4c0.9,0,1.7-0.1,2.5-0.4c0.8-0.2,1.5-0.6,2.2-1.1s1.3-1,1.8-1.6
c0.5-0.6,1-1.3,1.4-2.1c0.2,0.1,0.5,0.2,0.7,0.3c0.3,0.1,0.5,0.2,0.8,0.2c0.2,0,0.5,0.1,0.8,0.1c0.3,0,0.5,0,0.8,0
c1.2,0,2.4-0.2,3.4-0.7s2-1.1,2.8-2s1.4-1.8,1.9-2.9c0.4-1.1,0.7-2.3,0.7-3.5c0-0.1-0.1-0.2,0-0.3s0-0.2,0-0.3c0-0.1,0-0.2,0-0.3
s0-0.2-0.1-0.3c0.7-0.4,1.3-0.9,1.9-1.4c0.5-0.6,1-1.2,1.4-1.9c0.4-0.7,0.7-1.4,0.9-2.2c0.2-0.8,0.3-1.6,0.3-2.5
C48,24.3,47.9,23.4,47.7,22.5z M35.8,18.5c-0.2,0.3-0.3,0.6-0.5,0.8h-0.1L22,32.6c0,0-0.1,0,0,0s0,0,0,0c-0.1,0.1-0.2,0.2-0.4,0.3
c-0.2,0.1-0.3,0.2-0.4,0.2c-0.1,0-0.3,0.1-0.5,0.1c-0.2,0-0.3,0.1-0.4,0.1c-0.2,0-0.4,0-0.5-0.1c-0.1,0-0.3-0.1-0.5-0.1
c-0.2,0-0.3-0.1-0.4-0.2c-0.1-0.1-0.3-0.2-0.4-0.3l-5.7-5.8c-0.3-0.2-0.5-0.5-0.6-0.8c-0.1-0.3-0.2-0.6-0.2-0.9c0-0.3,0-0.6,0.2-0.9
c0.2-0.3,0.3-0.6,0.5-0.9c0.3-0.2,0.6-0.4,0.9-0.5s0.6-0.2,0.9-0.2c0.4,0,0.7,0.1,0.9,0.2c0.3,0.1,0.6,0.3,0.9,0.5l3.9,4l11.7-11.6
c0.2-0.2,0.4-0.4,0.8-0.5s0.7-0.2,0.9-0.2s0.6,0.1,0.9,0.2s0.6,0.3,0.8,0.5c0.3,0.3,0.5,0.6,0.6,0.9c0.1,0.3,0.2,0.6,0.2,0.9
C36.1,17.9,36,18.2,35.8,18.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -88,7 +88,6 @@ 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
@ -100,7 +99,6 @@ var tootParser = function(data){
ret.sensitive = data.sensitive ? true : false
ret.visibility = data.visibility ? data.visibility : false
console.log(ret)
}
var test = 1;

View file

@ -3,7 +3,7 @@
// 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) {
@ -56,8 +56,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 {
@ -91,8 +91,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 {
@ -180,8 +180,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 {
@ -221,8 +221,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 +236,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;

View file

@ -22,7 +22,7 @@ WorkerScript.onMessage = function(msg) {
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});
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){
@ -91,7 +91,7 @@ WorkerScript.onMessage = function(msg) {
addDataToModel (msg.model, "append", items);
items = [];
} else if (data[i].hasOwnProperty("content")){
} else if (data[i].hasOwnProperty("content")){
//console.log("Is toot... parsing...")
item = parseToot(data[i]);
item['id'] = item['status_id']
@ -132,11 +132,13 @@ function parseAccounts(collection, prefix, data){
res[prefix + 'account_username'] = data["username"]
res[prefix + 'account_acct'] = data["acct"]
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_avatar'] = data["avatar"]
res[prefix + 'account_header'] = data["header"]
// /console.log(JSON.stringify(res))
// console.log(JSON.stringify(res))
return (res);
}
@ -188,7 +190,7 @@ function parseNotification(data){
item = parseAccounts(item, "", data["account"])
item = parseAccounts(item, "reblog_", data["account"])
item['content'] = data['account']['note']
item['typeIcon'] = "image://theme/icon-s-installed"
item['typeIcon'] = "../../images/icon-s-following.svg"
item['attachments'] = []
break;
@ -226,6 +228,7 @@ function parseToot (data){
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
@ -236,6 +239,7 @@ function parseToot (data){
item['favourites_count'] = data["favourites_count"]
item['reblogged'] = data["reblogged"]
item['favourited'] = data["favourited"]
item['bookmarked'] = data["bookmarked"]
item['status_sensitive'] = data["sensitive"]
item['status_spoiler_text'] = data["spoiler_text"]
item['status_visibility'] = data["visibility"]
@ -294,13 +298,13 @@ function addEmojis(item, data){
var emoji, i;
for (i = 0; i < data["emojis"].length; i++){
emoji = data["emojis"][i];
item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "<img src=\"" + emoji.static_url+"\" align=\"middle\" width=\"24\" height=\"24\">")
item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "<img src=\"" + emoji.static_url+"\" align=\"top\" width=\"50\" height=\"50\">")
//console.log(JSON.stringify(data["emojis"][i]))
}
if (data["reblog"])
for (i = 0; i < data["reblog"]["emojis"].length; i++){
emoji = data["reblog"]["emojis"][i];
item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "<img src=\"" + emoji.static_url+"\" align=\"middle\" width=\"24\" height=\"24\">")
item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "<img src=\"" + emoji.static_url+"\" align=\"top\" width=\"50\" height=\"50\">")
}
return item;

View file

@ -4,17 +4,24 @@ import harbour.tooter.Uploader 1.0
import "../lib/API.js" as Logic
import "./components/"
Page {
id: conversationPage
property string type
property alias title: header.title
property alias description: header.description
property alias avatar: header.image
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 string toot_uri: ""
property int tootMaxChar: 500;
property ListModel mdl
property bool bot: false
property ListModel mdl
allowedOrientations: Orientation.All
onSuggestedUserChanged: {
console.log(suggestedUser)
@ -59,18 +66,21 @@ Page {
id: header
visible: false
}
SilicaListView {
id: conversationList
SilicaListView {
id: myList
header: PageHeader {
title: qsTr("Conversation")
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
}
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'
@ -90,22 +100,53 @@ Page {
}
}
}
}
PullDownMenu {
id: pulleyConversation
visible: type === "reply"
MenuItem {
text: qsTr("Copy Link to Clipboard")
onClicked: if (toot_url === "") {
var test = toot_uri.split("/")
console.log(toot_uri)
console.log(JSON.stringify(test))
console.log(JSON.stringify(test.length))
if (test.length === 8 && (test[7] === "activity")) {
var urialt = toot_uri.replace("activity", "")
Clipboard.text = urialt
}
else Clipboard.text = toot_uri
} else 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
color: Theme.highlightDimmerColor
height: parent.height - panel.height - (Theme.paddingLarge * 4.5)
anchors {
left: panel.left
right: panel.right
bottom: if (panel.open == true) {
panel.top
} else {
hiddenPanel.top
}
}
SilicaListView {
anchors.fill: parent
SilicaListView {
rotation: 180
anchors.fill: parent
model: suggestedModel
clip: true
quickScroll: false
VerticalScrollDecorator {}
delegate: ItemUser {
rotation: 180
onClicked: {
var start = toot.cursorPosition
while (toot.text[start] !== "@" && start > 0) {
@ -124,26 +165,22 @@ Page {
}
}
onCountChanged: {
positionViewAtIndex(suggestedModel.count - 1, ListView.End)
positionViewAtBeginning(suggestedModel.count - 1, ListView.Beginning)
}
}
}
DockedPanel {
id: panel
open: true
onExpandedChanged: {
if (!expanded) {
show()
}
}
width: parent.width
height: progressBar.height + toot.height + (mediaModel.count ? uploadedImages.height : 0)
height: progressBar.height + toot.height + (mediaModel.count ? uploadedImages.height : 0)
+ btnContentWarning.height + Theme.paddingMedium
+ (warningContent.visible ? warningContent.height : 0)
dock: Dock.Bottom
Rectangle {
+ (warningContent.visible ? warningContent.height : 0)
dock: Dock.Bottom
open: true
animationDuration: 200
Rectangle {
width: parent.width
height: progressBar.height
color: Theme.highlightBackgroundColor
@ -154,15 +191,16 @@ Page {
top: parent.top
}
}
Rectangle {
id: progressBar
width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0
height: Theme.itemSizeSmall * 0.05
height: Theme.itemSizeSmall * 0.05
color: Theme.highlightBackgroundColor
opacity: 0.7
anchors {
left: parent.left
top: parent.top
top: parent.top
}
}
@ -171,7 +209,7 @@ Page {
visible: false
height: visible ? implicitHeight : 0
anchors {
top: parent.top
top: parent.top
topMargin: Theme.paddingMedium
left: parent.left
right: parent.right
@ -183,10 +221,9 @@ Page {
placeholderColor: palette.highlightColor
color: palette.highlightColor
horizontalAlignment: Text.AlignLeft
EnterKey.onClicked: {
//tweet()
}
EnterKey.onClicked: {}
}
TextInput {
id: textOperations
visible: false
@ -203,18 +240,19 @@ Page {
}
autoScrollEnabled: true
labelVisible: false
//focus: true
text: description !== "" && (description.charAt(0) == '@'
text: description !== "" && (description.charAt(0) === '@'
|| description.charAt(
0) == '#') ? description + ' ' : ''
height: Math.max(270, Math.min(900, implicitHeight))
//height: implicitHeight
0) === '#') ? description + ' ' : ''
height: if (type !== "reply") {
Math.max(conversationPage.height / 3, Math.min(conversationPage.height * 0.65, implicitHeight))
}
else {
Math.max(conversationPage.height / 4, Math.min(conversationPage.height * 0.65, implicitHeight))
}
horizontalAlignment: Text.AlignLeft
placeholderText: qsTr("What's on your mind?")
font.pixelSize: Theme.fontSizeSmall
EnterKey.onClicked: {
//tweet()
}
EnterKey.onClicked: {}
onTextChanged: {
textOperations.text = toot.text
textOperations.cursorPosition = toot.cursorPosition
@ -230,45 +268,51 @@ Page {
}
}
}
IconButton {
id: btnSmileys
property string selection
onSelectionChanged: {
console.log(selection)
}
property string selection
opacity: 0.7
icon {
color: Theme.secondaryColor
width: Theme.iconSizeSmallPlus
fillMode: Image.PreserveAspectFit
source: "../../qml/images/icon-m-emoji.svg"
}
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)
onSelectionChanged: { console.log(selection) }
onClicked: pageStack.push(emojiSelect)
}
SilicaGridView {
id: uploadedImages
width: parent.width
anchors.top: bottom.toot
anchors.bottom: parent.bottom
height: mediaModel.count ? Theme.itemSizeSmall : 0
model: mediaModel
height: mediaModel.count ? Theme.itemSizeExtraLarge : 0
model: mediaModel
cellWidth: uploadedImages.width / 4
cellHeight: Theme.itemSizeSmall
cellHeight: Theme.itemSizeExtraLarge
delegate: BackgroundItem {
id: myDelegate
width: uploadedImages.cellWidth
height: uploadedImages.cellHeight
RemorseItem {
id: remorse
id: remorse
}
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: model.preview_url
}
onClicked: {
var idx = index
console.log(idx)
@ -286,7 +330,6 @@ Page {
duration: 800
}
}
remove: Transition {
NumberAnimation {
property: "opacity"
@ -303,8 +346,8 @@ Page {
}
}
}
IconButton {
IconButton {
id: btnContentWarning
anchors {
top: toot.bottom
@ -316,6 +359,7 @@ Page {
+ (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
onClicked: warningContent.visible = !warningContent.visible
}
IconButton {
id: btnAddImage
enabled: mediaModel.count < 4
@ -341,21 +385,18 @@ Page {
})
}
}
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
@ -363,15 +404,16 @@ Page {
console.log(statusText)
}
}
ComboBox {
id: privacy
id: privacy
anchors {
top: toot.bottom
topMargin: -Theme.paddingSmall * 1.5
left: btnAddImage.right
right: btnSend.left
}
menu: ContextMenu {
right: btnSend.left
}
menu: ContextMenu {
MenuItem {
text: qsTr("Public")
}
@ -405,7 +447,6 @@ Page {
console.log(mediaModel.get(k).id)
media_ids.push(mediaModel.get(k).id)
}
var msg = {
"action": 'statuses',
"method": 'POST',
@ -426,22 +467,23 @@ Page {
msg.params['spoiler_text'] = warningContent.text
}
worker.sendMessage(msg)
warningContent.text = ""
toot.text = ""
mediaModel.clear()
pageStack.pop()
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.bottom: parent.bottom
anchors.left: parent.left
height: 3
height: Theme.itemSizeSmall * 0.05
}
}
Component.onCompleted: {
toot.cursorPosition = toot.text.length
if (mdl.count > 0) {
@ -474,157 +516,66 @@ Page {
"conf": Logic.conf
})
}
Component {
id: firstWizardPage
Dialog {
id: emoticonsDialog
canAccept: false //selector.currentIndex >= 0
BackgroundItem {
id: hiddenPanel
visible: !panel.open
height: Theme.paddingLarge * 0.5
width: parent.width
opacity: enabled ? 0.6 : 0.0
Behavior on opacity { FadeAnimator { duration: 400 } }
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
//acceptDestination: conversationPage
onAcceptPendingChanged: {
if (acceptPending) {
MouseArea {
anchors.fill: parent
onClicked: panel.open = !panel.open
}
// Tell the destination page what the selected category is
// acceptDestinationInstance.category = selector.value
}
}
Rectangle {
id: hiddenPanelBackground
width: parent.width
height: parent.height
color: Theme.highlightBackgroundColor
opacity: 0.4
anchors.fill: parent
}
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: "🙏" }
Rectangle {
id: progressBarBackground
width: parent.width
height: progressBarHiddenPanel.height
color: Theme.highlightBackgroundColor
opacity: 0.2
anchors {
left: parent.left
right: parent.right
top: parent.top
}
}
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: "🛀" }
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 {
left: parent.left
top: parent.top
}
}
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()
}
}
}
}
}
EmojiSelect {
id: emojiSelect
}
InfoBanner {
id: sentBanner
}
}

View file

@ -1,48 +1,14 @@
/*
Copyright (C) 2013 Jolla Ltd.
Contact: Thomas Perl <thomas.perl@jollamobile.com>
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
import "../lib/API.js" as Logic
Page {
id: loginPage
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
SilicaFlickable {
anchors.fill: parent
contentHeight: column.height + Theme.paddingLarge
@ -52,8 +18,9 @@ Page {
Column {
id: column
width: parent.width
PageHeader { title: qsTr("Login") }
PageHeader {
title: qsTr("Login")
}
SectionHeader {
text: qsTr("Instance")
@ -64,47 +31,45 @@ 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['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
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 {
@ -144,7 +109,7 @@ Page {
if (
(url+"").substr(0, 37) === 'http://localhost/harbour-tooter?code=' ||
(url+"").substr(0, 38) === 'https://localhost/harbour-tooter?code='
) {
) {
visible = false;
var vars = {};
@ -155,22 +120,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"), {})
}
)
}
@ -196,5 +161,5 @@ Page {
}
}
}
}
}

View file

@ -1,33 +1,3 @@
/*
Copyright (C) 2013 Jolla Ltd.
Contact: Thomas Perl <thomas.perl@jollamobile.com>
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,8 +6,9 @@ import "./components/"
Page {
id: mainPage
property bool isFirstPage: true
property bool isTablet: true; //Screen.sizeCategory >= Screen.Large
property bool isTablet: true //Screen.sizeCategory >= Screen.Large
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
@ -57,10 +28,11 @@ Page {
}
}
}
VisualItemModel {
id: visualModel
MyList{
id: tlHome;
id: tlHome
title: qsTr("Home")
type: "timelines/home"
mdl: Logic.modelTLhome
@ -68,51 +40,62 @@ Page {
height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer
}
MyList{
id: tlNotifications;
id: tlNotifications
title: qsTr("Notifications")
type: "notifications"
notifier: true
mdl: Logic.modelTLnotifications
width: parent.itemWidth
height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer
onOpenDrawer: infoPanel.open = setDrawer
}
MyList{
id: tlLocal;
id: tlLocal
title: qsTr("Local")
type: "timelines/public?local=true"
//params: ["local", true]
mdl: Logic.modelTLlocal
width: parent.itemWidth
height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer
onOpenDrawer: infoPanel.open = setDrawer
}
MyList{
id: tlPublic;
id: tlPublic
title: qsTr("Federated")
type: "timelines/public"
mdl: Logic.modelTLpublic
width: parent.itemWidth
height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer
onOpenDrawer: infoPanel.open = setDrawer
}
Item {
id: tlSearch;
id: tlSearch
property ListModel mdl: ListModel {}
property string search
width: parent.itemWidth
height: parent.itemHeight
property ListModel mdl: ListModel {}
property string search;
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
@ -132,6 +115,7 @@ Page {
}
}
}
Component {
id: loading
BusyIndicator {
@ -140,6 +124,7 @@ Page {
running: true
}
}
Component {
id: tagListComponent
MyList {
@ -164,6 +149,7 @@ Page {
}
}
}
Component {
id: userListComponent
MyList {
@ -184,11 +170,12 @@ 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
"profileImage": model.account_avatar,
"profileBackground": model.account_header
})
}
}
@ -201,11 +188,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
@ -216,12 +225,9 @@ Page {
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
}
@ -231,22 +237,22 @@ Page {
}
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: Theme.paddingLarge
bottom: (mainPage.isPortrait ? infoPanel.top : parent.bottom)
bottomMargin: Theme.paddingLarge
}
onClicked: {
pageStack.push(Qt.resolvedUrl("Conversation.qml"), {title: qsTr("New Toot"), type: "new"})
pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
headerTitle: qsTr("New Toot"),
type: "new"
})
}
}
@ -266,11 +272,12 @@ Page {
navigation.navigateTo('search')
} else {
Qt.openUrlExternally(href);
Qt.openUrlExternally(href)
}
}
Component.onCompleted: {
console.log("aaa")
}
}
}

View file

@ -1,309 +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 profile_background: "";
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
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
}
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)
} 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')
} else {
Qt.openUrlExternally(link);
}
}
}
Column {
spacing: Theme.paddingMedium
anchors.horizontalCenter: parent.horizontalCenter
Button {
id: btnUrl
text: qsTr("Open Profile in Browser")
onClicked: {
Qt.openUrlExternally(url);
}
}
}
Label {
text: " "
}
}
}
}
}

373
qml/pages/ProfilePage.qml Normal file
View file

@ -0,0 +1,373 @@
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 int favourites_count
property int reblogs_count
property int count_moments
property bool locked: false
property bool bot: false
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
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':
// line below was commented out, reason unknown
// username = messageObject.data
break;
case 'locked':
locked = messageObject.data
break;
case 'bot':
bot = 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;
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: 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
}
}
ExpandingSectionGroup { // ProfilePage ExpandingSection
id: profileExpander
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
ExpandingSection {
id: expandingSection1
title: qsTr("About")
content.sourceComponent: Column {
height: Math.min( txtContainer, parent.height * 0.7 )
spacing: Theme.paddingLarge
Item {
id: txtContainer
width: parent.width
height: Math.min( txtNote.height, parent.height * 0.55 )
visible: {
if ((note.text === "") || ( note.text === "<p></p>" )) {
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.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall
linkColor: Theme.highlightColor
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
Text {
id: txtFollowers
visible: followers_count ? true : false
text: followers_count+" "+qsTr("Followers")
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
wrapMode: Text.Wrap
}
Text {
id: txtFollowing
visible: following_count ? true : false
text: following_count+" "+qsTr("Following")
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
wrapMode: Text.Wrap
}
Text {
id: txtStatuses
visible: statuses_count ? true : false
text: statuses_count+" "+qsTr("Statuses")
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
wrapMode: Text.Wrap
}
/*Text {
id: txtFavourites
visible: favourites_count ? true : false
text: favourites_count+" "+qsTr("Favourites")
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
wrapMode: Text.Wrap
} */
}
Item { // dummy item for spacing
height: Theme.paddingSmall
}
ButtonLayout {
id: btnLayout
Button {
id: btnMention
preferredWidth: Theme.buttonWidthSmall
text: "Mention"
onClicked: {
pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
headerTitle: "Mention",
description: "@"+username,
type: "new"
})
}
}
Button {
id: btnFollow
preferredWidth: Theme.buttonWidthSmall
text: (following ? qsTr("Unfollow") : (requested ? qsTr("Requested") : 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);
// to-do: create notification banner "Follow request sent!"
}
}
Button {
id: btnMute
preferredWidth: Theme.buttonWidthSmall
text: (muting ? qsTr("Unmute") : 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 ? qsTr("Unblock") : 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);
}
}
}
Button {
id: btnBrowser
text: qsTr("Open in Browser")
preferredWidth: Theme.buttonWidthMedium
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
Qt.openUrlExternally(url)
}
}
Rectangle { // dummy item for spacing
height: Theme.paddingSmall
width: parent.width
opacity: 0
}
}
}
}
}

View file

@ -1,86 +1,131 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import "../lib/API.js" as Logic
Page {
id: settingsPage
allowedOrientations: Orientation.All
SilicaFlickable {
anchors.fill: parent
contentHeight: column.height + Theme.paddingLarge
contentWidth: parent.width
anchors.fill: parent
RemorsePopup { id: remorsePopup }
VerticalScrollDecorator {}
Column {
id: column
spacing: Theme.paddingSmall
spacing: Theme.paddingMedium
width: parent.width
PageHeader {
title: qsTr("Settings")
}
Column {
// No spacing in this column
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"
enabled: true
checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages']
onClicked: {
Logic.conf['loadImages'] = checked
}
}
SectionHeader { text: qsTr("Account")}
Item {
id: removeAccount
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
}
height: txtRemoveAccount.height + btnRemoveAccount.height + Theme.paddingLarge
anchors {
left: parent.left
leftMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.paddingLarge
}
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
}
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
}
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()
Column {
id: clnRemoveAccount
spacing: Theme.paddingMedium
anchors {
left: parent.left
right: icnRemoveAccount.left
}
Timer {
id: timer2
interval: 4700
onTriggered: parent.busy = false
Button {
id: btnRemoveAccount
text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account")
width: 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
anchors {
left: parent.left
right: parent.right
rightMargin: Theme.paddingLarge + icnRemoveAccount
}
}
}
}
SectionHeader {
text: qsTr("Translate")
}
LinkedLabel {
text: qsTr("Use <a href='https://www.transifex.com/dysko/tooter/'>Transifex</a> 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 {
text: qsTr("Credits")
}
@ -90,52 +135,61 @@ Page {
anchors {
left: parent.left
right: parent.right
rightMargin: Theme.horizontalPageMargin
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: "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"
mastodon: "molan@fosstodon.org"
mail: ""
}
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")
@ -147,31 +201,29 @@ Page {
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
}
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,
pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
headerTitle: "Mention",
description: '@'+model.mastodon,
avatar: "",
mdl: m,
type: "reply"
type: "new"
})
} else {
Qt.openUrlExternally("mailto:"+model.mail);
}
}
}
Column {
anchors {
verticalCenter: parent.verticalCenter
@ -184,9 +236,10 @@ Page {
Label {
id: lblName
text: model.name
color: Theme.secondaryColor
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeSmall
}
Label {
text: model.desc
color: Theme.secondaryHighlightColor
@ -198,4 +251,5 @@ Page {
}
}
}
}

View file

@ -0,0 +1,166 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Component {
id: emojiComponent
Dialog {
id: emoticonsDialog
canAccept: false //selector.currentIndex >= 0
onAcceptPendingChanged: {
if (acceptPending) {
// Tell the destination page what the selected category is
// acceptDestinationInstance.category = selector.value
}
}
SilicaGridView {
id: gridView
header: PageHeader {
title: qsTr("Emojis")
description: qsTr("Tap to insert")
}
cellWidth: gridView.width / 6
cellHeight: cellWidth
anchors.fill: parent
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: "People and Fantasy"; glyph: "🙅" }
ListElement { section: "People and Fantasy"; glyph: "🙆" }
ListElement { section: "People and Fantasy"; glyph: "🙇" }
ListElement { section: "People and Fantasy"; glyph: "🙈" }
ListElement { section: "People and Fantasy"; glyph: "🙉" }
ListElement { section: "People and Fantasy"; glyph: "🙊" }
ListElement { section: "People and Fantasy"; glyph: "🙋" }
ListElement { section: "People and Fantasy"; glyph: "🙍" }
ListElement { section: "People and Fantasy"; glyph: "🙎" }
ListElement { section: "People and Fantasy"; glyph: "👍" }
ListElement { section: "People and Fantasy"; glyph: "👎" }
ListElement { section: "People and Fantasy"; glyph: "🙌" }
ListElement { section: "People and Fantasy"; glyph: "✊" }
ListElement { section: "People and Fantasy"; glyph: "💪" }
ListElement { section: "People and Fantasy"; glyph: "👉" }
ListElement { section: "People and Fantasy"; 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
emoticonsDialog.canAccept = true
emoticonsDialog.accept()
}
}
VerticalScrollDecorator {flickable: listEmojis }
}
}
}

View file

@ -0,0 +1,59 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
DockedPanel {
id: root
dock: Dock.Top
width: parent.width
height: content.height
Rectangle {
id: content
color: Theme.highlightBackgroundColor
width: root.width
height: infoLabel.height + 2 * Theme.paddingMedium
Label {
id: infoLabel
text : ""
font.family: Theme.fontFamilyHeading
font.pixelSize: Theme.fontSizeMedium
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: {
root.hide()
autoClose.stop()
}
}
}
function showText(text) {
infoLabel.text = text
root.show()
autoClose.start()
}
Timer {
id: autoClose
interval: 4500
running: false
onTriggered: {
root.hide()
stop()
}
}
}

View file

@ -4,9 +4,11 @@ import Sailfish.Silica 1.0
BackgroundItem {
id: delegate
signal openUser (string notice)
height: Theme.itemSizeMedium
width: parent.width
height: Theme.itemSizeMedium
Rectangle {
id: avatar
@ -23,6 +25,7 @@ BackgroundItem {
anchors.fill: parent
source: model.account_avatar
}
BusyIndicator {
size: BusyIndicatorSize.Small
opacity: img.status === Image.Ready ? 0.0 : 1.0
@ -30,16 +33,19 @@ BackgroundItem {
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
})
}
}
Column {
anchors.left: avatar.right
anchors.leftMargin: Theme.paddingLarge
@ -63,6 +69,8 @@ BackgroundItem {
"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
})
}

View file

@ -4,10 +4,12 @@ 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: {
@ -74,8 +76,6 @@ Item {
}
}
MyImage {
id: placeholder1
width: 2
@ -94,6 +94,7 @@ Item {
}
}
}
MyImage {
id: placeholder2
width: 2
@ -112,6 +113,7 @@ Item {
}
}
}
MyImage {
id: placeholder3
width: 2
@ -130,6 +132,7 @@ Item {
}
}
}
MyImage {
id: placeholder4
width: 2
@ -148,8 +151,5 @@ Item {
}
}
}
}

View file

@ -2,11 +2,14 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import QtMultimedia 5.0
Page {
id: imagePage
FullscreenContentPage {
id: mediaPage
property string type: ""
property string previewURL: ""
property string mediaURL: ""
allowedOrientations: Orientation.All
Component.onCompleted: function(){
console.log(type)
@ -14,31 +17,35 @@ Page {
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
video.play()
videoFlickable.visible = true;
videoFlickable.visible = true
}
}
Flickable {
id: videoFlickable
visible: false
anchors.fill: parent
contentWidth: imageContainer.width; contentHeight: imageContainer.height
clip: true
contentWidth: imageContainer.width
contentHeight: imageContainer.height
anchors.fill: parent
Image {
id: videoPreview
fillMode: Image.PreserveAspectFit
anchors.fill: parent
source: previewURL
}
Video {
id: video
anchors.fill: parent
onErrorStringChanged: function(){
videoError.visible = true;
videoError.visible = true
}
onStatusChanged: {
console.log(status)
@ -49,10 +56,8 @@ Page {
case MediaPlayer.EndOfMedia:
console.log("EndOfMedia")
return;
}
}
onPlaybackStateChanged: {
console.log(playbackState)
switch (playbackState){
@ -63,12 +68,10 @@ Page {
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(){
//console.log(duration)
//console.log(bufferProgress)
@ -79,18 +82,23 @@ Page {
playerProgress.minimumValue = 0
playerProgress.value = position
}
}
onStopped: function() {
if (video.duration < 30000)
video.play()
else
video.stop()
}
}
onStopped: function(){
play()
}
IconButton {
id: playerIcon
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.leftMargin: Theme.paddingLarge
anchors.bottomMargin: Theme.paddingMedium
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()
@ -100,50 +108,17 @@ Page {
}
ProgressBar {
indeterminate: true
id: playerProgress
anchors.left: playerIcon.right
anchors.right: videoDlBtn.left
anchors.verticalCenter: playerIcon.verticalCenter
anchors.leftMargin: 0
anchors.bottomMargin: Theme.paddingMedium
}
IconButton {
id: videoDlBtn
visible: true
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: Theme.paddingLarge
anchors.bottomMargin: Theme.paddingMedium
//width: Theme.iconSizeMedium+Theme.paddingMedium*2
icon.source: "image://theme/icon-m-cloud-download"
onClicked: {
var filename = mediaURL.split("/");
FileDownloader.downloadFile(mediaURL, filename[filename.length-1]);
indeterminate: true
width: 400
anchors {
verticalCenter: playerIcon.verticalCenter
left: playerIcon.right
right: parent.right
rightMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium
bottomMargin: Theme.horizontalPageMargin
}
}
Rectangle {
visible: videoError.text != ""
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
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.WordWrap
height: contentHeight
visible: false;
font.pixelSize: Theme.fontSizeSmall;
text: video.errorString
color: Theme.highlightColor
}
}
MouseArea {
anchors.fill: parent
@ -154,17 +129,43 @@ Page {
video.play()
}
}
Rectangle {
visible: videoError.text != ""
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
color: Theme.highlightDimmerColor
height: videoError.height + 2*Theme.paddingMedium
width: parent.width
Label {
id: videoError
visible: false
text: video.errorString
font.pixelSize: Theme.fontSizeSmall
color: Theme.highlightColor
wrapMode: Text.Wrap
width: parent.width - 2*Theme.paddingMedium
height: contentHeight
anchors.centerIn: parent
}
}
}
}
Flickable {
id: imageFlickable
visible: false
anchors.fill: parent
contentWidth: imageContainer.width; contentHeight: imageContainer.height
contentWidth: imageContainer.width
contentHeight: imageContainer.height
clip: true
onHeightChanged: if (imagePreview.status === Image.Ready) imagePreview.fitToScreen();
anchors.fill: parent
onHeightChanged: if (imagePreview.status === Image.Ready) {
imagePreview.fitToScreen()
}
Item {
id: imageContainer
@ -177,18 +178,17 @@ Page {
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()
@ -221,15 +221,16 @@ Page {
PinchArea {
id: pinchArea
opacity: 0.3
property real minScale: 1.0
property real maxScale: 3.0
opacity: 0.3
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()
@ -242,6 +243,7 @@ Page {
bounceBackAnimation.start()
}
}
NumberAnimation {
id: bounceBackAnimation
target: imagePreview
@ -267,39 +269,57 @@ Page {
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.paddingMedium
//width: Theme.iconSizeMedium+Theme.paddingMedium*2
id: dismissBtn
icon.source: "image://theme/icon-m-dismiss"
anchors {
top: parent.top
topMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.horizontalPageMargin
}
onClicked: pageStack.pop()
}
IconButton {
id: mediaDlBtn
anchors {
right: parent.right
rightMargin: Theme.horizontalPageMargin
bottom: parent.bottom
bottomMargin: Theme.horizontalPageMargin
}
icon.source: "image://theme/icon-m-cloud-download"
onClicked: {
var filename = mediaURL.split("/");
FileDownloader.downloadFile(mediaURL, filename[filename.length-1]);
}
}
VerticalScrollDecorator { flickable: imageFlickable }
}

View file

@ -1,71 +1,72 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Item {
id: miniheader
id: miniHeader
height: lblName.height
width: parent.width
Label {
id: lblName
text:
if (account_display_name === "") {
account_username.split('@')[0]
}
else account_display_name
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: contentWidth > parent.width /2 ? parent.width /2 : contentWidth
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
id: icnLocked
visible: account_locked
opacity: 0.8
source: "image://theme/icon-s-secure?" + (pressed ? Theme.highlightColor : Theme.primaryColor)
width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0
height: width
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
text: '@'+account_username
font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
truncationMode: TruncationMode.Fade
anchors {
left: iconVerified.right
left: icnLocked.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 {
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.primaryColor)
horizontalAlignment: Text.AlignRight
anchors {
right: parent.right
baseline: lblName.baseline
rightMargin: Theme.horizontalPageMargin
baseline: lblName.baseline
}
}
}

View file

@ -1,13 +1,19 @@
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 {
Icon {
id: icon
visible: type.length
color: Theme.highlightColor
width: Theme.iconSizeExtraSmall
height: width
source: typeof typeIcon !== "undefined" ? typeIcon : ""
anchors {
top: parent.top
topMargin: Theme.paddingMedium
@ -15,12 +21,8 @@ Item {
left: parent.left
leftMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium - width
}
visible: type.length
width: Theme.iconSizeExtraSmall
height: width
source: typeof typeIcon !== "undefined" ? typeIcon : ""
}
Label {
id: lblRtByName
visible: type.length
@ -42,12 +44,11 @@ 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 : ''
}
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
}

View file

@ -2,34 +2,41 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import QtMultimedia 5.0
Item {
id: myImage
property string type : ""
property string previewURL: ""
property string mediaURL: ""
Rectangle {
opacity: 0.2
anchors.fill: parent
color: Theme.highlightDimmerColor
anchors.fill: parent
}
Image {
anchors.centerIn: parent
source: "image://theme/icon-m-image"
anchors.centerIn: parent
}
Rectangle {
id: progressRec
anchors.bottom: parent.bottom
width: 0
height: Theme.paddingSmall
color: Theme.highlightBackgroundColor
anchors.bottom: parent.bottom
}
Image {
id: img
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
asynchronous: true
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
source: previewURL
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
onProgressChanged: {
if (progress != 1)
progressRec.width = parent.width * progress
@ -38,36 +45,47 @@ Item {
}
}
MouseArea {
anchors.fill: parent
onClicked: {
pageStack.push(Qt.resolvedUrl("./ImageFullScreen.qml"), {"previewURL": previewURL, "mediaURL": mediaURL, "type": type})
pageStack.push(Qt.resolvedUrl("./MediaFullScreen.qml"), {
"previewURL": previewURL,
"mediaURL": mediaURL,
"type": type
})
}
}
Image {
id: videoIcon
visible: type === "video" || type === "gifv"
anchors.centerIn: parent
source: "image://theme/icon-l-play"
anchors.centerIn: parent
}
BusyIndicator {
id: mediaLoader
size: BusyIndicatorSize.Large
running: img.status !== Image.Ready
opacity: img.status === Image.Ready ? 0.0 : 1.0
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
anchors.fill: parent
id: mediaWarning
color: Theme.highlightDimmerColor
visible: typeof status_sensitive != 'undefined' && status_sensitive ? true : false
anchors.fill: parent
Image {
source: "image://theme/icon-l-attention?"+Theme.highlightColor
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: parent.visible = false;
onClicked: parent.visible = false
}
}
}

View file

@ -3,9 +3,11 @@ 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...")
@ -13,21 +15,21 @@ SilicaListView {
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)
@ -38,18 +40,16 @@ SilicaListView {
}
BusyIndicator {
size: BusyIndicatorSize.Large
running: myList.model.count === 0 && !viewPlaceHolder.visible
anchors.centerIn: parent
}
header: PageHeader {
title: myList.title
description: myList.description
}
BusyIndicator {
size: BusyIndicatorSize.Large
running: myList.model.count === 0 && !viewPlaceHolder.visible
anchors.centerIn: parent
}
ViewPlaceholder {
id: viewPlaceHolder
@ -62,7 +62,17 @@ SilicaListView {
MenuItem {
text: qsTr("Settings")
onClicked: {
pageStack.push(Qt.resolvedUrl("../Settings.qml"), {})
pageStack.push(Qt.resolvedUrl("../SettingsPage.qml"), {})
}
}
MenuItem {
text: qsTr("New Toot")
onClicked: {
pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
//headerTitle: "New Toot",
type: "new"
})
}
}
@ -73,14 +83,6 @@ SilicaListView {
}
}
}
clip: true
section {
property: 'section'
delegate: SectionHeader {
height: Theme.itemSizeExtraSmall
text: Format.formatDate(section, Formatter.DateMedium)
}
}
delegate: VisualContainer {
} //Toot {}
@ -95,10 +97,9 @@ SilicaListView {
}
onCountChanged: {
loadStarted = false;
loadStarted = false
/*contentY = scrollOffset
console.log("CountChanged!")*/
}
footer: Item{
@ -114,6 +115,7 @@ SilicaListView {
loadData("append")
}
}
BusyIndicator {
size: BusyIndicatorSize.Small
running: loadStarted;
@ -121,18 +123,18 @@ SilicaListView {
anchors.horizontalCenter: parent.horizontalCenter
}
}
onContentYChanged: {
onContentYChanged: {
if (Math.abs(contentY - scrollOffset) > Theme.itemSizeMedium) {
openDrawer(contentY - scrollOffset > 0 ? false : true )
scrollOffset = contentY
}
if(contentY+height > footerItem.y && !loadStarted && autoLoadMore){
loadData("append")
loadStarted = true;
loadStarted = true
}
}
VerticalScrollDecorator {}
WorkerScript {
@ -145,7 +147,6 @@ SilicaListView {
if (messageObject.fireNotification && notifier){
Logic.notifier(messageObject.data)
}
}
}
@ -160,17 +161,18 @@ SilicaListView {
loadData("prepend")
}
}
function loadData(mode){
var p = [];
var p = []
if (params.length)
for(var i = 0; i<params.length; i++)
p.push(params[i])
if (mode === "append" && model.count){
p.push({name: 'max_id', data: model.get(model.count-1).id});
p.push({name: 'max_id', data: model.get(model.count-1).id})
}
if (mode === "prepend" && model.count){
p.push({name:'since_id', data: model.get(0).id});
p.push({name:'since_id', data: model.get(0).id})
}
var msg = {
@ -182,7 +184,7 @@ SilicaListView {
};
console.log(JSON.stringify(msg))
if (type !== "")
worker.sendMessage(msg);
worker.sendMessage(msg)
}
}

View file

@ -2,15 +2,18 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import QtGraphicalEffects 1.0
SilicaGridView {
signal slideshowShow(int vIndex);
signal slideshowIndexChanged(int vIndex);
id: gridView
property bool isPortrait: false
signal slideshowShow(int vIndex)
signal slideshowIndexChanged(int vIndex)
onSlideshowIndexChanged: {
navigateTo(vIndex)
}
id: gridView
property bool isPortrait: false
ListModel {
id: listModel
ListElement {
@ -20,12 +23,14 @@ SilicaGridView {
active: true
unread: false
}
ListElement {
icon: "image://theme/icon-m-alarm"
slug: "notifications"
name: "Notifications"
active: false
}
ListElement {
icon: "image://theme/icon-m-whereami"
slug: "local"
@ -33,6 +38,7 @@ SilicaGridView {
active: false
unread: false
}
ListElement {
icon: "image://theme/icon-m-website"
slug: "federated"
@ -40,6 +46,7 @@ SilicaGridView {
active: false
unread: false
}
ListElement {
icon: "image://theme/icon-m-search"
slug: "search"
@ -49,16 +56,13 @@ SilicaGridView {
}
}
model: listModel
anchors.fill: parent
currentIndex: -1
cellWidth: isPortrait ? gridView.width : gridView.width / model.count
cellHeight: isPortrait ? gridView.height/model.count : gridView.height
anchors.fill: parent
delegate: BackgroundItem {
clip: true
id: rectangle
clip: true
width: gridView.cellWidth
height: gridView.cellHeight
GridView.onAdd: AddAnimation {
@ -67,28 +71,33 @@ SilicaGridView {
GridView.onRemove: RemoveAnimation {
target: rectangle
}
GlassItem {
id: effect
visible: !isPortrait && unread
dimmed: true
color: Theme.highlightColor
width: Theme.itemSizeMedium
height: Theme.itemSizeMedium
dimmed: true
anchors.bottom: parent.bottom
anchors.bottomMargin: -height/2
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.highlightColor
anchors {
bottom: parent.bottom
bottomMargin: -height/2
horizontalCenter: parent.horizontalCenter
}
}
GlassItem {
id: effect2
visible: isPortrait && unread
dimmed: false
color: Theme.highlightColor
width: Theme.itemSizeMedium
height: Theme.itemSizeMedium
dimmed: false
anchors.right: parent.right;
anchors.rightMargin: -height/2;
anchors.verticalCenter: parent.verticalCenter
color: Theme.highlightColor
anchors {
right: parent.right
rightMargin: -height/2
verticalCenter: parent.verticalCenter
}
}
OpacityRampEffect {
@ -96,68 +105,59 @@ SilicaGridView {
offset: 0.5
}
/*Image {
source: model.icon + (highlighted
? Theme.highlightColor
: (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor))
anchors.centerIn: parent
}*/
ColorOverlay {
anchors.fill: image
source: image
color: (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor))
}
source: image
color: (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor))
anchors.fill: image
}
Image {
id: image
visible: false
source: model.icon // +'?'+ (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor))
sourceSize.width: Theme.iconSizeMedium
sourceSize.height: Theme.iconSizeMedium
source: model.icon// +'?'+ (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor))
anchors.centerIn: parent
visible: false
// smooth: true
}
Text {
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.paddingSmall
anchors.left: parent.left
anchors.right: parent.right
horizontalAlignment: Text.AlignHCenter
visible: false
text: model.name
font.pixelSize: Theme.fontSizeExtraSmall/2
color: (highlighted
? Theme.highlightColor
: (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor))
horizontalAlignment: Text.AlignHCenter
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: Theme.paddingSmall
}
}
Label {
id: label
visible: false
anchors {
bottom: parent.bottom
}
horizontalAlignment : Text.AlignHCente
width: parent.width
color: (highlighted ? Theme.highlightColor : Theme.secondaryHighlightColor)
text: {
return model.name.toUpperCase();
}
font {
pixelSize: Theme.fontSizeExtraSmall
family: Theme.fontFamilyHeading
}
font.pixelSize: Theme.fontSizeExtraSmall
font.family: Theme.fontFamilyHeading
width: parent.width
horizontalAlignment : Text.AlignHCenter
anchors.bottom: parent.bottom
}
onClicked: {
slideshowShow(index)
console.log(index)
navigateTo(model.slug)
effect.state = "right"
}
}
function navigateTo(slug){
for(var i = 0; i < listModel.count; i++){
if (listModel.get(i).slug === slug || i===slug)
@ -166,10 +166,9 @@ SilicaGridView {
listModel.setProperty(i, 'active', false);
}
console.log(slug)
}
VerticalScrollDecorator {}
}

View file

@ -1,81 +1,161 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Item {
id: header
property int value: 0;
property string title: "";
property string description: "";
property string image: "";
property string bg: "";
id: profileHeader
property int value: 0
property string title: ""
property string description: ""
property string image: ""
property string bg: ""
width: parent.width
height: icon.height + Theme.paddingLarge*2
/*Image {
anchors.fill: parent
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: bg
opacity: 0.3
}*/
height: if (bot === true) {
avatarImage.height + Theme.paddingLarge*2 + infoLbl.height + Theme.paddingLarge
} else avatarImage.height + Theme.paddingLarge*2
Rectangle {
anchors.fill: parent
id: bgImage
opacity: 0.2
gradient: Gradient {
GradientStop { position: 0.0; color: Theme.highlightBackgroundColor }
GradientStop { position: 1.0; color: Theme.highlightBackgroundColor }
GradientStop { position: 1.0; color: Theme.highlightBackgroundColor }
}
anchors.fill: parent
Image {
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: bg
opacity: 0.8
anchors.fill: parent
}
}
Image {
id: icon
id: avatarImage
asynchronous: true
source:
if (avatarImage.status === Image.Error)
source = "../../images/icon-l-profile.svg?" + (pressed
? Theme.highlightColor
: Theme.primaryColor)
else image
width: description === "" ? Theme.iconSizeMedium : Theme.iconSizeLarge
height: width
anchors {
left: parent.left
leftMargin: Theme.paddingLarge
top: parent.top
topMargin: Theme.paddingLarge
}
asynchronous: true
width: description === "" ? Theme.iconSizeMedium : Theme.iconSizeLarge
height: width
source:
if (icon.status === Image.Error)
source = "../../images/icon-l-profile.svg?" + (pressed
? Theme.highlightColor
: Theme.primaryColor)
else image
Button {
id: imageButton
opacity: 0
width: Theme.iconSizeExtraLarge * 1.2
anchors {
top: parent.top
left: parent.left
bottom: parent.bottom
}
onClicked: {
pageStack.push(Qt.resolvedUrl("ProfileImage.qml"), {
"image": image
})
}
}
}
Column {
anchors {
left: icon.right
top: parent.top
topMargin: Theme.paddingLarge
left: avatarImage.right
leftMargin: Theme.paddingLarge
right: parent.right
rightMargin: Theme.paddingLarge
verticalCenter: parent.verticalCenter
}
Label {
id: ttl
text:
if (title === "") {
description.split('@')[0]
}
else title
height: contentHeight
color: Theme.highlightColor
id: profileTitle
text: if (title === "") {
description.split('@')[0]
}
else title
font.pixelSize: Theme.fontSizeLarge
font.family: Theme.fontFamilyHeading
horizontalAlignment: Text.AlignRight
color: Theme.highlightColor
truncationMode: TruncationMode.Fade
width: parent.width
height: contentHeight
horizontalAlignment: Text.AlignRight
}
Label {
height: description === "" ? 0 : contentHeight
id: profileDescription
text: "@"+description
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeSmall
font.family: Theme.fontFamilyHeading
horizontalAlignment: Text.AlignRight
color: Theme.secondaryHighlightColor
truncationMode: TruncationMode.Fade
width: parent.width
height: description === "" ? 0 : contentHeight
horizontalAlignment: Text.AlignRight
}
}
Row {
id: infoLbl
spacing: Theme.paddingLarge
layoutDirection: Qt.RightToLeft
height: Theme.iconSizeSmall + Theme.paddingSmall
anchors {
top: avatarImage.bottom
topMargin: Theme.paddingLarge
left: parent.left
leftMargin: Theme.paddingLarge
right: parent.right
rightMargin: Theme.paddingLarge
}
/* Rectangle {
id: followingBg
visible: (following ? true : false)
radius: Theme.paddingSmall
color: Theme.secondaryHighlightColor
width: followingLbl.width + 2*Theme.paddingLarge
height: parent.height
Label {
id: followingLbl
text: qsTr("Follows you")
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.primaryColor
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
} */
Rectangle {
id: botBg
visible: (bot ? true : false)
radius: Theme.paddingSmall
color: Theme.secondaryHighlightColor
width: botLbl.width + 2*Theme.paddingLarge
height: parent.height
Label {
id: botLbl
text: qsTr("Bot")
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.primaryColor
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
}

View file

@ -0,0 +1,28 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
FullscreenContentPage {
id: profileImage
property string image: ""
allowedOrientations: Orientation.All
Image {
source: image
fillMode: Image.PreserveAspectFit
anchors.fill: parent
}
IconButton {
icon.source: "image://theme/icon-m-dismiss"
anchors {
top: profileImage.top
topMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.horizontalPageMargin
}
onClicked: pageStack.pop()
}
}

View file

@ -2,32 +2,33 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import QtGraphicalEffects 1.0
BackgroundItem {
signal send (string notice)
BackgroundItem {
id: delegate
//property string text: "0"
width: parent.width
signal send (string notice)
signal navigateTo(string link)
width: parent.width
height: lblText.paintedHeight + (lblText.text.length > 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
}
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
}
anchors.left: lblName.left
anchors.bottom: iconRT.bottom
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: {
var action;
switch(type){
@ -45,10 +46,8 @@ BackgroundItem {
}
return '@' + retweetScreenName + ' ' + action
}
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
}
Image {
id: avatar
x: Theme.horizontalPageMargin
@ -62,71 +61,70 @@ BackgroundItem {
MouseArea {
anchors.fill: parent
onClicked: {
pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
pageStack.push(Qt.resolvedUrl("../ProfilePage.qml"), {
"display_name": account_display_name,
"username": account_username,
"profileImage": account_avatar
})
}
}
}
Label {
id: lblName
text: account_display_name
font.weight: Font.Bold
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
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
id: iconLocked
visible: account_locked
y: Theme.paddingLarge
opacity: 0.8
source: "image://theme/icon-s-secure?" + (pressed
? Theme.highlightColor
: Theme.primaryColor)
width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0
height: width
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)
anchors {
left: iconLocked.right
right: lblDate.left
leftMargin: Theme.paddingMedium
baseline: lblName.baseline
}
}
Label {
id: lblDate
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
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
horizontalAlignment: Text.AlignRight
anchors {
right: parent.right
@ -135,15 +133,8 @@ BackgroundItem {
}
}
Label {
Text {
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)
@ -154,34 +145,40 @@ BackgroundItem {
"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
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
linkColor : Theme.highlightColor
wrapMode: Text.Wrap
maximumLineCount: 6
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
anchors {
left: lblName.left
right: parent.right
top: lblScreenName.bottom
topMargin: Theme.paddingSmall
rightMargin: Theme.paddingLarge
}
}
onClicked: {
pageStack.push(Qt.resolvedUrl("../Conversation.qml"), {
pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
headerTitle: "Conversation",
toot_id: id,
title: account_display_name,
description: '@'+account_username,
toot_url: status_url,
//title: account_display_name,
description: '@'+account_acc,
avatar: account_avatar,
type: "reply"
})

View file

@ -2,25 +2,48 @@ import QtQuick 2.2
import Sailfish.Silica 1.0
import "../../lib/API.js" as Logic
BackgroundItem {
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)
Rectangle {
x: 0;
y: 0;
visible: status_visibility == 'direct'
id: bgDirect
x: 0
y: 0
visible: 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 }
}
}
Rectangle {
id: bgNotifications
x: 0
y: 0
visible: myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )
width: parent.width
height: parent.height
opacity: 0.5
gradient: Gradient {
GradientStop { position: -0.5; color: "transparent" }
GradientStop { position: 0.4; color: Theme.highlightDimmerColor }
}
}
MiniStatus {
id: ministatus
id: miniStatus
anchors {
leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin
@ -28,56 +51,80 @@ BackgroundItem {
topMargin: Theme.paddingMedium
}
}
Image {
id: avatar
anchors {
top: ministatus.visible ? ministatus.bottom : parent.top
topMargin: ministatus.visible ? Theme.paddingMedium : Theme.paddingLarge
left: parent.left
leftMargin: Theme.horizontalPageMargin
}
visible: true
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)
? Theme.highlightColor
: 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
"profileImage": model.account_avatar,
"profileBackground": model.account_header
})
}
}
Rectangle {
visible: myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )
opacity: 0.5
color: Theme.highlightDimmerColor
anchors.fill: avatar
}
Image {
id: iconTR
visible: typeof status_reblogged !== "undefined" && status_reblogged
width: Theme.iconSizeExtraSmall
height: width
source: "image://theme/icon-s-retweet"
anchors {
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"
}
Image {
id: iconDirectMsg
visible: status_visibility === "direct"
width: Theme.iconSizeMedium
height: width
source: "image://theme/icon-m-mail"
anchors {
horizontalCenter: avatar.horizontalCenter
top: avatar.bottom
topMargin: Theme.paddingMedium
left: avatar.left
}
}
Rectangle {
color: Theme.highlightDimmerColor
id: bgReblogAvatar
color: Theme.secondaryColor
width: Theme.iconSizeSmall
height: width
visible: typeof status_reblog !== "undefined" && status_reblog
@ -87,18 +134,21 @@ 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
}
}
}
MiniHeader {
id: miniHeader
anchors {
@ -107,8 +157,23 @@ BackgroundItem {
right: parent.right
}
}
Text {
id: lblContent
visible: model.type !== "follow"
text: content.replace(new RegExp("<a ", 'g'), '<a style="text-decoration: none; color:'+(pressed ? Theme.secondaryColor : Theme.highlightColor)+'" ')
textFormat: Text.RichText
font.pixelSize: Theme.fontSizeSmall
linkColor: if (myList.type === "notifications" && ( model.type === "favourite" || model.type === "reblog" )) {
Theme.secondaryHighlightColor
} else Theme.highlightColor
wrapMode: Text.Wrap
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))
height: if (model.type === "follow") {
Theme.paddingLarge
} else content.length ? (contentWarningLabel.paintedHeight > paintedHeight ? contentWarningLabel.paintedHeight : paintedHeight) : 0
anchors {
left: miniHeader.left
leftMargin: Theme.paddingMedium
@ -118,7 +183,6 @@ BackgroundItem {
topMargin: Theme.paddingSmall
bottomMargin: Theme.paddingLarge
}
height: content.length ? (contentWarningLabel.paintedHeight > paintedHeight ? contentWarningLabel.paintedHeight : paintedHeight) : 0
onLinkActivated: {
var test = link.split("/")
console.log(link)
@ -134,29 +198,32 @@ BackgroundItem {
}));
send(link)
} 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')
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("<a ", 'g'), '<a style="text-decoration: none; color:'+(pressed ? Theme.secondaryColor : Theme.highlightColor)+'" ')
linkColor : Theme.highlightColor
wrapMode: Text.WordWrap
textFormat: Text.RichText
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : (!highlight ? Theme.primaryColor : Theme.secondaryColor))
Rectangle {
anchors.fill: parent
radius: 2
color: Theme.highlightDimmerColor
visible: status_spoiler_text.length > 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
@ -166,21 +233,21 @@ BackgroundItem {
rightMargin: Theme.paddingMedium
bottomMargin: Theme.paddingSmall
}
width: parent.width
truncationMode: TruncationMode.Fade
color: Theme.highlightColor
wrapMode: Text.WordWrap
text: model.status_spoiler_text
}
MouseArea {
anchors.fill: parent
onClicked: parent.visible = false;
onClicked: parent.visible = false
}
}
}
MediaBlock {
id: media
visible: myList.type !== "notifications" && ( model.type !== "favourite" || model.type !== "reblog" )
model: typeof attachments !== "undefined" ? attachments : Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
height: Theme.iconSizeExtraLarge * 2
anchors {
left: lblContent.left
right: lblContent.right
@ -188,13 +255,15 @@ BackgroundItem {
topMargin: Theme.paddingSmall
bottomMargin: Theme.paddingLarge
}
model: typeof attachments !== "undefined" ? attachments : Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
height: 100
}
ContextMenu {
id: mnu
MenuItem {
enabled: model.type !== "follow"
id: mnuBoost
visible: model.type !== "follow"
enabled: status_visibility !== "direct"
text: typeof model.reblogged !== "undefined" && model.reblogged ? qsTr("Unboost") : qsTr("Boost")
onClicked: {
var status = typeof model.reblogged !== "undefined" && model.reblogged
@ -208,30 +277,34 @@ BackgroundItem {
model.reblogs_count = !status ? model.reblogs_count+1 : (model.reblogs_count > 0 ? model.reblogs_count-1 : model.reblogs_count);
model.reblogged = !model.reblogged
}
Image {
id: icRT
source: "image://theme/icon-s-retweet?" + (!model.reblogged ? Theme.highlightColor : Theme.primaryColor)
width: Theme.iconSizeExtraSmall
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: reblogs_count
font.pixelSize: Theme.fontSizeExtraSmall
color: !model.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"
id: mnuFavourite
visible: model.type !== "follow"
text: typeof model.favourited !== "undefined" && model.favourited ? qsTr("Unfavorite") : qsTr("Favorite")
onClicked: {
var status = typeof model.favourited !== "undefined" && model.favourited
@ -245,6 +318,7 @@ BackgroundItem {
model.favourites_count = !status ? model.favourites_count+1 : (model.favourites_count > 0 ? model.favourites_count-1 : model.favourites_count);
model.favourited = !model.favourited
}
Image {
id: icFA
anchors {
@ -256,28 +330,54 @@ BackgroundItem {
height: width
source: "image://theme/icon-s-favorite?" + (!model.favourited ? Theme.highlightColor : Theme.primaryColor)
}
Label {
text: favourites_count
font.pixelSize: Theme.fontSizeExtraSmall
color: !model.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: mnuMention
visible: model.type === "follow"
text: qsTr("Mention")
onClicked: {
pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
headerTitle: "Mention",
description: "@"+reblog_account_acct,
type: "new"
})
}
Image {
id: icMT
anchors {
leftMargin: Theme.horizontalPageMargin
left: parent.left
verticalCenter: parent.verticalCenter
}
width: Theme.iconSizeExtraSmall
height: width
source: "image://theme/icon-s-chat?" + (!model.favourited ? Theme.highlightColor : Theme.primaryColor)
}
}
}
onClicked: {
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"), {
pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
headerTitle: "Conversation",
toot_id: status_id,
toot_url: status_url,
toot_uri: status_uri,
title: account_display_name,
description: '@'+account_acct,
avatar: account_avatar,

View file

@ -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);
};

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Konversation</translation>
</message>
<message>
<source>Delete</source>
<translation>Löschen</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation>Was gibt&apos;s Neues?</translation>
</message>
<message>
<source>Toot sent!</source>
<translation>Toot gesendet!</translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation>Link kopieren</translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Fehler beim Laden</translation>
<translation>Ladefehler</translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Συνομιλία</translation>
</message>
<message>
<source>Delete</source>
<translation>Διαγραφή</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Σφάλμα φόρτωσης</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Conversación</translation>
</message>
<message>
<source>Delete</source>
<translation>Borrar</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation>¿En qué estás pensando?</translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Error al cargar</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Delete</source>
<translation type="unfinished"></translation>
@ -62,6 +58,14 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Conversation</translation>
</message>
<message>
<source>Delete</source>
<translation>Supprimer</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation>Qu&apos;avez-vous en tête?</translation>
</message>
<message>
<source>Toot sent!</source>
<translation>Pouet envoyé !</translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation>Copier le lien</translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Erreur de chargement</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -28,52 +28,57 @@
<context>
<name>Conversation</name>
<message>
<location filename="../qml/pages/Conversation.qml" line="65"/>
<source>Conversation</source>
<translation>Conversazione</translation>
<location filename="../qml/pages/Conversation.qml" line="108"/>
<source>Copy Link to Clipboard</source>
<translation>Copia link</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="182"/>
<location filename="../qml/pages/Conversation.qml" line="200"/>
<source>Write your warning here</source>
<translation>Contenuto avviso</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="213"/>
<location filename="../qml/pages/Conversation.qml" line="230"/>
<source>What&apos;s on your mind?</source>
<translation>A cosa stai pensando?</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="276"/>
<location filename="../qml/pages/Conversation.qml" line="293"/>
<source>Delete</source>
<translation>Elimina</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="376"/>
<location filename="../qml/pages/Conversation.qml" line="392"/>
<source>Public</source>
<translation>Pubblico</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="379"/>
<location filename="../qml/pages/Conversation.qml" line="395"/>
<source>Unlisted</source>
<translation>Non elencato</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="382"/>
<location filename="../qml/pages/Conversation.qml" line="398"/>
<source>Followers-only</source>
<translation>Solo ai seguaci</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="385"/>
<location filename="../qml/pages/Conversation.qml" line="401"/>
<source>Direct</source>
<translation>Diretto</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="499"/>
<location filename="../qml/pages/Conversation.qml" line="449"/>
<source>Toot sent!</source>
<translation>Toot è stato pubblicato!</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="515"/>
<source>Emojis</source>
<translation>Emojis</translation>
</message>
<message>
<location filename="../qml/pages/Conversation.qml" line="500"/>
<location filename="../qml/pages/Conversation.qml" line="516"/>
<source>Tap to insert</source>
<translation>Tap per inserire</translation>
</message>
@ -81,9 +86,9 @@
<context>
<name>ImageFullScreen</name>
<message>
<location filename="../qml/pages/components/ImageFullScreen.qml" line="287"/>
<location filename="../qml/pages/components/ImageFullScreen.qml" line="298"/>
<source>Error loading</source>
<translation>Errore caricamento</translation>
<translation>Errore durante caricamento</translation>
</message>
</context>
<context>
@ -97,27 +102,27 @@
<context>
<name>LoginPage</name>
<message>
<location filename="../qml/pages/LoginPage.qml" line="56"/>
<location filename="../qml/pages/LoginPage.qml" line="52"/>
<source>Login</source>
<translation>Accesso</translation>
</message>
<message>
<location filename="../qml/pages/LoginPage.qml" line="59"/>
<location filename="../qml/pages/LoginPage.qml" line="56"/>
<source>Instance</source>
<translation>Istanza</translation>
</message>
<message>
<location filename="../qml/pages/LoginPage.qml" line="65"/>
<location filename="../qml/pages/LoginPage.qml" line="62"/>
<source>Enter a valid Mastodon instance URL</source>
<translation>Inserire URL di una istanza Mastodon valida</translation>
</message>
<message>
<location filename="../qml/pages/LoginPage.qml" line="123"/>
<location filename="../qml/pages/LoginPage.qml" line="119"/>
<source>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.</source>
<translation>Mastodon è un servizio di rete sociale in software libero, costituito in una federazione d&apos;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.</translation>
</message>
<message>
<location filename="../qml/pages/LoginPage.qml" line="194"/>
<location filename="../qml/pages/LoginPage.qml" line="190"/>
<source>Reload</source>
<translation>Ricarica</translation>
</message>
@ -125,37 +130,37 @@
<context>
<name>MainPage</name>
<message>
<location filename="../qml/pages/MainPage.qml" line="64"/>
<location filename="../qml/pages/MainPage.qml" line="65"/>
<source>Home</source>
<translation>Home</translation>
</message>
<message>
<location filename="../qml/pages/MainPage.qml" line="73"/>
<location filename="../qml/pages/MainPage.qml" line="74"/>
<source>Notifications</source>
<translation>Notifiche</translation>
</message>
<message>
<location filename="../qml/pages/MainPage.qml" line="83"/>
<location filename="../qml/pages/MainPage.qml" line="84"/>
<source>Local</source>
<translation>Locale</translation>
</message>
<message>
<location filename="../qml/pages/MainPage.qml" line="93"/>
<location filename="../qml/pages/MainPage.qml" line="94"/>
<source>Federated</source>
<translation>Federazione</translation>
</message>
<message>
<location filename="../qml/pages/MainPage.qml" line="120"/>
<location filename="../qml/pages/MainPage.qml" line="121"/>
<source>Search</source>
<translation>Cerca</translation>
</message>
<message>
<location filename="../qml/pages/MainPage.qml" line="125"/>
<location filename="../qml/pages/MainPage.qml" line="126"/>
<source>@user or #term</source>
<translation>@utente o #termine</translation>
</message>
<message>
<location filename="../qml/pages/MainPage.qml" line="249"/>
<location filename="../qml/pages/MainPage.qml" line="251"/>
<source>New Toot</source>
<translation>Nuovo toot</translation>
</message>
@ -269,7 +274,7 @@
<translation>Biografia</translation>
</message>
<message>
<location filename="../qml/pages/Profile.qml" line="294"/>
<location filename="../qml/pages/Profile.qml" line="291"/>
<source>Open Profile in Browser</source>
<translation>Aprire profile nel browser</translation>
</message>
@ -388,22 +393,22 @@
<context>
<name>VisualContainer</name>
<message>
<location filename="../qml/pages/components/VisualContainer.qml" line="198"/>
<location filename="../qml/pages/components/VisualContainer.qml" line="204"/>
<source>Unboost</source>
<translation>Annulla condivisione</translation>
</message>
<message>
<location filename="../qml/pages/components/VisualContainer.qml" line="198"/>
<location filename="../qml/pages/components/VisualContainer.qml" line="204"/>
<source>Boost</source>
<translation>Condividi</translation>
</message>
<message>
<location filename="../qml/pages/components/VisualContainer.qml" line="235"/>
<location filename="../qml/pages/components/VisualContainer.qml" line="241"/>
<source>Unfavorite</source>
<translation>Annulla apprezzamento</translation>
</message>
<message>
<location filename="../qml/pages/components/VisualContainer.qml" line="235"/>
<location filename="../qml/pages/components/VisualContainer.qml" line="241"/>
<source>Favorite</source>
<translation>Apprezzato</translation>
</message>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Gesprek</translation>
</message>
<message>
<source>Delete</source>
<translation>Verwijderen</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Fout bij laden</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Gesprek</translation>
</message>
<message>
<source>Delete</source>
<translation>Verwijderen</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Fout bij laden</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Discutida</translation>
</message>
<message>
<source>Delete</source>
<translation>Escafar</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Error en cargar</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Konwersacja</translation>
</message>
<message>
<source>Delete</source>
<translation>Usuń</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Błąd ładowania</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Беседа</translation>
</message>
<message>
<source>Delete</source>
<translation>Удалить</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Ошибка при загрузке</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Разговор</translation>
</message>
<message>
<source>Delete</source>
<translation>Обриши</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Greška u učitavanju</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Konversation</translation>
</message>
<message>
<source>Delete</source>
<translation>Radera</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation>Problem att ladda</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -22,10 +22,6 @@
</context>
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation></translation>
</message>
<message>
<source>Delete</source>
<translation></translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source>
<translation>?</translation>
</message>
<message>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Copy Link to Clipboard</source>
<translation></translation>
</message>
</context>
<context>
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -23,25 +23,21 @@
<context>
<name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Conversation</translation>
</message>
<message>
<source>Delete</source>
<translation>Delete</translation>
</message>
<message>
<source>Emojis</source>
<translation>Emojis</translation>
</message>
<message>
<source>Tap to insert</source>
<translation>Tap to insert</translation>
<source>Copy Link to Clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Write your warning here</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Public</source>
<translation type="unfinished"></translation>
@ -59,7 +55,18 @@
<translation type="unfinished"></translation>
</message>
<message>
<source>What&apos;s on your mind?</source>
<source>Toot sent!</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EmojiPage</name>
<message>
<source>Emojis</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Tap to insert</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -67,7 +74,7 @@
<name>ImageFullScreen</name>
<message>
<source>Error loading</source>
<translation></translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>