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 Icon=harbour-tooter
Exec=harbour-tooter Exec=harbour-tooter
Name=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

@ -53,6 +53,13 @@ HEADERS += src/dbusAdaptor.h
HEADERS += src/dbus.h HEADERS += src/dbus.h
DISTFILES += qml/harbour-tooter.qml \ 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/VisualContainer.qml \
qml/pages/components/MiniStatus.qml \ qml/pages/components/MiniStatus.qml \
qml/pages/components/MiniHeader.qml \ qml/pages/components/MiniHeader.qml \
@ -62,21 +69,14 @@ DISTFILES += qml/harbour-tooter.qml \
qml/pages/components/ProfileHeader.qml \ qml/pages/components/ProfileHeader.qml \
qml/pages/components/MediaBlock.qml \ qml/pages/components/MediaBlock.qml \
qml/pages/components/MyImage.qml \ qml/pages/components/MyImage.qml \
qml/pages/components/ImageFullScreen.qml \
qml/cover/CoverPage.qml \ qml/cover/CoverPage.qml \
qml/pages/MainPage.qml \ qml/pages/MainPage.qml \
qml/pages/LoginPage.qml \ qml/pages/LoginPage.qml \
qml/pages/Conversation.qml \
qml/pages/components/Toot.qml \ qml/pages/components/Toot.qml \
qml/pages/Browser.qml \ qml/pages/Browser.qml \
qml/pages/Profile.qml \
qml/pages/Settings.qml \
qml/lib/API.js \ qml/lib/API.js \
qml/images/notification.svg \ qml/images/icon-s-following \
qml/images/verified.svg \ qml/images/icon-m-emoji.svg \
qml/images/boosted.svg \
qml/images/tooter.svg \
qml/images/emojiselect.svg \
qml/images/icon-m-profile.svg \ qml/images/icon-m-profile.svg \
qml/images/icon-l-profile.svg \ qml/images/icon-l-profile.svg \
qml/lib/Mastodon.js \ qml/lib/Mastodon.js \
@ -94,7 +94,7 @@ SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the # to disable building translations every time, comment out the
# following CONFIG line # following CONFIG line
CONFIG += sailfishapp_i18n # CONFIG += sailfishapp_i18n
# German translation is enabled as an example. If you aren't # German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the # planning to localize your app, remember to comment out the

View file

@ -30,9 +30,9 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../lib/API.js" as Logic import "../lib/API.js" as Logic
CoverBackground { CoverBackground {
onStatusChanged: { onStatusChanged: {
switch (status ){ switch (status ){
@ -46,20 +46,21 @@ CoverBackground {
break; break;
} }
} }
Image { Image {
id: bg id: bg
source: "../images/tooter-cover.svg"
horizontalAlignment: Image.AlignLeft
verticalAlignment: Image.AlignBottom
fillMode: Image.PreserveAspectFit
anchors { anchors {
bottom : parent.bottom bottom : parent.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
top: parent.top top: parent.top
} }
horizontalAlignment: Image.AlignLeft
verticalAlignment: Image.AlignBottom
fillMode: Image.PreserveAspectFit
source: "../images/tooter.svg"
} }
Timer { Timer {
id: timer id: timer
interval: 60*1000 interval: 60*1000
@ -70,33 +71,34 @@ CoverBackground {
Image { Image {
id: iconNot id: iconNot
source: "image://theme/icon-s-alarm?" + Theme.highlightColor
anchors { anchors {
left: parent.left left: parent.left
top: parent.top top: parent.top
leftMargin: Theme.paddingLarge leftMargin: Theme.paddingLarge
topMargin: Theme.paddingLarge topMargin: Theme.paddingLarge
} }
source: "image://theme/icon-s-alarm?" + Theme.highlightColor
} }
Label { Label {
id: notificationsLbl id: notificationsLbl
text: " "
color: Theme.highlightColor
anchors { anchors {
left: iconNot.right left: iconNot.right
leftMargin: Theme.paddingMedium leftMargin: Theme.paddingMedium
verticalCenter: iconNot.verticalCenter verticalCenter: iconNot.verticalCenter
} }
text: " "
color: Theme.highlightColor
} }
Label { Label {
text: "Tooter"
color: Theme.secondaryColor
anchors { anchors {
right: parent.right right: parent.right
rightMargin: Theme.paddingLarge rightMargin: Theme.paddingLarge
verticalCenter: iconNot.verticalCenter verticalCenter: iconNot.verticalCenter
} }
text: "Tooter"
color: Theme.primaryColor
} }
signal activateapp(string person, string notice) signal activateapp(string person, string notice)
@ -112,8 +114,11 @@ CoverBackground {
CoverAction { CoverAction {
iconSource: "image://theme/icon-cover-new" iconSource: "image://theme/icon-cover-new"
onTriggered: { onTriggered: {
pageStack.push(Qt.resolvedUrl("./../pages/Conversation.qml"), {}) pageStack.push(Qt.resolvedUrl("./../pages/ConversationPage.qml"), {
appWindow.activate(); headerTitle: qsTr("New Toot"),
type: "new"
})
appWindow.activate()
} }
} }
} }
@ -135,5 +140,5 @@ CoverBackground {
notificationsLbl.text = notificationsNum; notificationsLbl.text = notificationsNum;
Logic.conf.notificationLastID = notificationLastID; Logic.conf.notificationLastID = notificationLastID;
} }
}
}

View file

@ -33,23 +33,26 @@ import Sailfish.Silica 1.0
import "pages" import "pages"
import "./lib/API.js" as Logic import "./lib/API.js" as Logic
ApplicationWindow ApplicationWindow {
{
id: appWindow id: appWindow
//initialPage: Component { FirstPage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: defaultAllowedOrientations allowedOrientations: defaultAllowedOrientations
cover: Qt.resolvedUrl("cover/CoverPage.qml")
Component.onCompleted: { Component.onCompleted: {
var obj = {}; var obj = {}
Logic.mediator.installTo(obj); Logic.mediator.installTo(obj)
obj.subscribe('confLoaded', function(){ obj.subscribe('confLoaded', function() {
console.log('confLoaded'); console.log('confLoaded');
//console.log(JSON.stringify(Logic.conf)) //console.log(JSON.stringify(Logic.conf))
if (!Logic.conf['notificationLastID']) if (!Logic.conf['notificationLastID'])
Logic.conf['notificationLastID'] = 0; Logic.conf['notificationLastID'] = 0
if (Logic.conf['instance']) { 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']) { if (Logic.conf['login']) {
//Logic.conf['notificationLastID'] = 0 //Logic.conf['notificationLastID'] = 0
Logic.api.setConfig("api_user_token", Logic.conf['api_user_token']) Logic.api.setConfig("api_user_token", Logic.conf['api_user_token'])
@ -57,17 +60,12 @@ ApplicationWindow
Logic.api.get('instance', [], function(data) { Logic.api.get('instance', [], function(data) {
console.log(JSON.stringify(data)) console.log(JSON.stringify(data))
pageStack.push(Qt.resolvedUrl("./pages/MainPage.qml"), {}) pageStack.push(Qt.resolvedUrl("./pages/MainPage.qml"), {})
}); })
//
//
//pageStack.push(Qt.resolvedUrl("./pages/Conversation.qml"), {}) //pageStack.push(Qt.resolvedUrl("./pages/Conversation.qml"), {})
} else { } else {
pageStack.push(Qt.resolvedUrl("./pages/LoginPage.qml"), {}) pageStack.push(Qt.resolvedUrl("./pages/LoginPage.qml"), {})
} }
})
});
Logic.init() Logic.init()
} }
@ -75,19 +73,19 @@ ApplicationWindow
//Logic.conf.notificationLastID = 0; //Logic.conf.notificationLastID = 0;
Logic.saveData() Logic.saveData()
} }
Connections
{ Connections {
target: Dbus target: Dbus
onViewtoot: onViewtoot: {
{
console.log(key, "dbus onViewtoot") console.log(key, "dbus onViewtoot")
} }
onActivateapp: onActivateapp: {
{
console.log ("dbus activate app") console.log ("dbus activate app")
pageStack.pop(pageStack.find( function(page){ return (page._depth === 0) })) pageStack.pop(pageStack.find( function(page) {
return (page._depth === 0)
}))
activate() 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.display_name = data.account.display_name
ret.avatar_static = data.account.avatar_static ret.avatar_static = data.account.avatar_static
ret.favourited = data.favourited ? true : false ret.favourited = data.favourited ? true : false
ret.favourites_count = data.favourites_count ? data.favourites_count : 0 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.sensitive = data.sensitive ? true : false
ret.visibility = data.visibility ? data.visibility : false ret.visibility = data.visibility ? data.visibility : false
console.log(ret) console.log(ret)
} }
var test = 1; var test = 1;

View file

@ -3,7 +3,7 @@
// do whatever you want with it // do whatever you want with it
// but please don't hurt it (and keep this header) // but please don't hurt it (and keep this header)
var MastodonAPI = function(config) { var mastodonAPI = function(config) {
var apiBase = config.instance + "/api/v1/"; var apiBase = config.instance + "/api/v1/";
return { return {
setConfig: function (key, value) { setConfig: function (key, value) {
@ -56,8 +56,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader("Connection", "close"); http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() { // Call a function when the state changes. http.onreadystatechange = function() { // Call a function when the state changes.
if (http.readyState == 4) { if (http.readyState === 4) {
if (http.status == 200) { if (http.status === 200) {
console.log("Successful GET API request to " +apiBase+endpoint); console.log("Successful GET API request to " +apiBase+endpoint);
callback(JSON.parse(http.response),http.status) callback(JSON.parse(http.response),http.status)
} else { } else {
@ -91,8 +91,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader("Connection", "close"); http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() { // Call a function when the state changes. http.onreadystatechange = function() { // Call a function when the state changes.
if (http.readyState == 4) { if (http.readyState === 4) {
if (http.status == 200) { if (http.status === 200) {
console.log("Successful POST API request to " +apiBase+endpoint); console.log("Successful POST API request to " +apiBase+endpoint);
callback(JSON.parse(http.response),http.status) callback(JSON.parse(http.response),http.status)
} else { } else {
@ -180,8 +180,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() { // Call a function when the state changes. http.onreadystatechange = function() { // Call a function when the state changes.
if (http.readyState == 4) { if (http.readyState === 4) {
if (http.status == 200) { if (http.status === 200) {
console.log("Registered Application: " + http.response); console.log("Registered Application: " + http.response);
callback(http.response) callback(http.response)
} else { } else {
@ -221,8 +221,8 @@ var MastodonAPI = function(config) {
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() { // Call a function when the state changes. http.onreadystatechange = function() { // Call a function when the state changes.
if (http.readyState == 4) { if (http.readyState === 4) {
if (http.status == 200) { if (http.status === 200) {
console.log("Got Token: " + http.response); console.log("Got Token: " + http.response);
callback(http.response) callback(http.response)
} else { } else {
@ -236,7 +236,7 @@ var MastodonAPI = function(config) {
}; };
// node.js // node.js
if (typeof module !== 'undefined') { module.exports = MastodonAPI; }; if (typeof module !== 'undefined') { module.exports = mastodonAPI; };
String.prototype.replaceAll = function(search, replacement) { String.prototype.replaceAll = function(search, replacement) {
var target = this; var target = this;

View file

@ -22,7 +22,7 @@ WorkerScript.onMessage = function(msg) {
if (typeof msg.conf['loadImages'] !== "undefined") if (typeof msg.conf['loadImages'] !== "undefined")
loadImages = msg.conf['loadImages'] 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"){ if (msg.method === "POST"){
API.post(msg.action, msg.params, function(data) { API.post(msg.action, msg.params, function(data) {
if (msg.bgAction){ if (msg.bgAction){
@ -132,11 +132,13 @@ function parseAccounts(collection, prefix, data){
res[prefix + 'account_username'] = data["username"] res[prefix + 'account_username'] = data["username"]
res[prefix + 'account_acct'] = data["acct"] res[prefix + 'account_acct'] = data["acct"]
res[prefix + 'account_display_name'] = data["display_name"] res[prefix + 'account_display_name'] = data["display_name"]
res[prefix + 'account_discoverable'] = data["discoverable"]
res[prefix + 'account_locked'] = data["locked"] res[prefix + 'account_locked'] = data["locked"]
res[prefix + 'account_created_at'] = data["created_at"] res[prefix + 'account_created_at'] = data["created_at"]
res[prefix + 'account_avatar'] = data["avatar"] res[prefix + 'account_avatar'] = data["avatar"]
res[prefix + 'account_header'] = data["header"]
// /console.log(JSON.stringify(res)) // console.log(JSON.stringify(res))
return (res); return (res);
} }
@ -188,7 +190,7 @@ function parseNotification(data){
item = parseAccounts(item, "", data["account"]) item = parseAccounts(item, "", data["account"])
item = parseAccounts(item, "reblog_", data["account"]) item = parseAccounts(item, "reblog_", data["account"])
item['content'] = data['account']['note'] item['content'] = data['account']['note']
item['typeIcon'] = "image://theme/icon-s-installed" item['typeIcon'] = "../../images/icon-s-following.svg"
item['attachments'] = [] item['attachments'] = []
break; break;
@ -226,6 +228,7 @@ function parseToot (data){
item['highlight'] = false item['highlight'] = false
item['status_id'] = data["id"] item['status_id'] = data["id"]
item['status_uri'] = data["uri"] 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_id'] = data["in_reply_to_id"]
item['status_in_reply_to_account_id'] = data["in_reply_to_account_id"] item['status_in_reply_to_account_id'] = data["in_reply_to_account_id"]
item['status_reblog'] = data["reblog"] ? true : false item['status_reblog'] = data["reblog"] ? true : false
@ -236,6 +239,7 @@ function parseToot (data){
item['favourites_count'] = data["favourites_count"] item['favourites_count'] = data["favourites_count"]
item['reblogged'] = data["reblogged"] item['reblogged'] = data["reblogged"]
item['favourited'] = data["favourited"] item['favourited'] = data["favourited"]
item['bookmarked'] = data["bookmarked"]
item['status_sensitive'] = data["sensitive"] item['status_sensitive'] = data["sensitive"]
item['status_spoiler_text'] = data["spoiler_text"] item['status_spoiler_text'] = data["spoiler_text"]
item['status_visibility'] = data["visibility"] item['status_visibility'] = data["visibility"]
@ -294,13 +298,13 @@ function addEmojis(item, data){
var emoji, i; var emoji, i;
for (i = 0; i < data["emojis"].length; i++){ for (i = 0; i < data["emojis"].length; i++){
emoji = data["emojis"][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])) //console.log(JSON.stringify(data["emojis"][i]))
} }
if (data["reblog"]) if (data["reblog"])
for (i = 0; i < data["reblog"]["emojis"].length; i++){ for (i = 0; i < data["reblog"]["emojis"].length; i++){
emoji = data["reblog"]["emojis"][i]; 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; return item;

View file

@ -4,8 +4,11 @@ import harbour.tooter.Uploader 1.0
import "../lib/API.js" as Logic import "../lib/API.js" as Logic
import "./components/" import "./components/"
Page { Page {
id: conversationPage id: conversationPage
property string headerTitle: ""
property string type property string type
property alias title: header.title property alias title: header.title
property alias description: header.description property alias description: header.description
@ -13,8 +16,12 @@ Page {
property string suggestedUser: "" property string suggestedUser: ""
property ListModel suggestedModel property ListModel suggestedModel
property string toot_id: "" property string toot_id: ""
property string toot_url: ""
property string toot_uri: ""
property int tootMaxChar: 500; property int tootMaxChar: 500;
property bool bot: false
property ListModel mdl property ListModel mdl
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
onSuggestedUserChanged: { onSuggestedUserChanged: {
console.log(suggestedUser) console.log(suggestedUser)
@ -59,17 +66,20 @@ Page {
id: header id: header
visible: false visible: false
} }
SilicaListView { SilicaListView {
id: conversationList id: myList
header: PageHeader { header: PageHeader {
title: qsTr("Conversation") title: headerTitle // pageTitle pushed from MainPage.qml or VisualContainer.qml
} }
clip: true clip: true
anchors { anchors.top: parent.top
top: parent.top anchors.left: parent.left
bottom: panel.top anchors.right: parent.right
left: parent.left anchors.bottom: if (panel.open == true) {
right: parent.right panel.top
} else {
hiddenPanel.top
} }
model: mdl model: mdl
section { 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 { Rectangle {
id: predictionList id: predictionList
visible: false 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 { SilicaListView {
rotation: 180
anchors.fill: parent anchors.fill: parent
model: suggestedModel model: suggestedModel
clip: true clip: true
quickScroll: false
VerticalScrollDecorator {}
delegate: ItemUser { delegate: ItemUser {
rotation: 180
onClicked: { onClicked: {
var start = toot.cursorPosition var start = toot.cursorPosition
while (toot.text[start] !== "@" && start > 0) { while (toot.text[start] !== "@" && start > 0) {
@ -124,25 +165,21 @@ Page {
} }
} }
onCountChanged: { onCountChanged: {
positionViewAtIndex(suggestedModel.count - 1, ListView.End) positionViewAtBeginning(suggestedModel.count - 1, ListView.Beginning)
} }
} }
} }
DockedPanel { DockedPanel {
id: panel id: panel
open: true
onExpandedChanged: {
if (!expanded) {
show()
}
}
width: parent.width 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 + btnContentWarning.height + Theme.paddingMedium
+ (warningContent.visible ? warningContent.height : 0) + (warningContent.visible ? warningContent.height : 0)
dock: Dock.Bottom dock: Dock.Bottom
open: true
animationDuration: 200
Rectangle { Rectangle {
width: parent.width width: parent.width
height: progressBar.height height: progressBar.height
@ -154,6 +191,7 @@ Page {
top: parent.top top: parent.top
} }
} }
Rectangle { Rectangle {
id: progressBar id: progressBar
width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0 width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0
@ -183,10 +221,9 @@ Page {
placeholderColor: palette.highlightColor placeholderColor: palette.highlightColor
color: palette.highlightColor color: palette.highlightColor
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
EnterKey.onClicked: { EnterKey.onClicked: {}
//tweet()
}
} }
TextInput { TextInput {
id: textOperations id: textOperations
visible: false visible: false
@ -203,18 +240,19 @@ Page {
} }
autoScrollEnabled: true autoScrollEnabled: true
labelVisible: false labelVisible: false
//focus: true text: description !== "" && (description.charAt(0) === '@'
text: description !== "" && (description.charAt(0) == '@'
|| description.charAt( || description.charAt(
0) == '#') ? description + ' ' : '' 0) === '#') ? description + ' ' : ''
height: Math.max(270, Math.min(900, implicitHeight)) height: if (type !== "reply") {
//height: implicitHeight 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 horizontalAlignment: Text.AlignLeft
placeholderText: qsTr("What's on your mind?") placeholderText: qsTr("What's on your mind?")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
EnterKey.onClicked: { EnterKey.onClicked: {}
//tweet()
}
onTextChanged: { onTextChanged: {
textOperations.text = toot.text textOperations.text = toot.text
textOperations.cursorPosition = toot.cursorPosition textOperations.cursorPosition = toot.cursorPosition
@ -230,32 +268,38 @@ Page {
} }
} }
} }
IconButton { IconButton {
id: btnSmileys 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 { anchors {
top: warningContent.bottom top: warningContent.bottom
bottom: bottom.top bottom: bottom.top
right: parent.right right: parent.right
rightMargin: Theme.paddingSmall rightMargin: Theme.paddingSmall
} }
opacity: 0.8 onSelectionChanged: { console.log(selection) }
icon.source: "../../qml/images/emojiselect.svg" + (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor)) onClicked: pageStack.push(emojiSelect)
onClicked: pageStack.push(firstWizardPage)
} }
SilicaGridView { SilicaGridView {
id: uploadedImages id: uploadedImages
width: parent.width width: parent.width
anchors.top: bottom.toot anchors.top: bottom.toot
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
height: mediaModel.count ? Theme.itemSizeSmall : 0 height: mediaModel.count ? Theme.itemSizeExtraLarge : 0
model: mediaModel model: mediaModel
cellWidth: uploadedImages.width / 4 cellWidth: uploadedImages.width / 4
cellHeight: Theme.itemSizeSmall cellHeight: Theme.itemSizeExtraLarge
delegate: BackgroundItem { delegate: BackgroundItem {
id: myDelegate id: myDelegate
width: uploadedImages.cellWidth width: uploadedImages.cellWidth
@ -263,12 +307,12 @@ Page {
RemorseItem { RemorseItem {
id: remorse id: remorse
} }
Image { Image {
anchors.fill: parent anchors.fill: parent
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
source: model.preview_url source: model.preview_url
} }
onClicked: { onClicked: {
var idx = index var idx = index
console.log(idx) console.log(idx)
@ -286,7 +330,6 @@ Page {
duration: 800 duration: 800
} }
} }
remove: Transition { remove: Transition {
NumberAnimation { NumberAnimation {
property: "opacity" property: "opacity"
@ -303,8 +346,8 @@ Page {
} }
} }
} }
IconButton {
IconButton {
id: btnContentWarning id: btnContentWarning
anchors { anchors {
top: toot.bottom top: toot.bottom
@ -316,6 +359,7 @@ Page {
+ (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor)) + (pressed ? Theme.highlightColor : (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
onClicked: warningContent.visible = !warningContent.visible onClicked: warningContent.visible = !warningContent.visible
} }
IconButton { IconButton {
id: btnAddImage id: btnAddImage
enabled: mediaModel.count < 4 enabled: mediaModel.count < 4
@ -341,21 +385,18 @@ Page {
}) })
} }
} }
ImageUploader { ImageUploader {
id: imageUploader id: imageUploader
onProgressChanged: { onProgressChanged: {
console.log("progress " + progress) console.log("progress " + progress)
uploadProgress.width = parent.width * progress uploadProgress.width = parent.width * progress
} }
onSuccess: { onSuccess: {
uploadProgress.width = 0 uploadProgress.width = 0
console.log(replyData) console.log(replyData)
mediaModel.append(JSON.parse(replyData)) mediaModel.append(JSON.parse(replyData))
} }
onFailure: { onFailure: {
uploadProgress.width = 0 uploadProgress.width = 0
btnAddImage.enabled = true btnAddImage.enabled = true
@ -363,6 +404,7 @@ Page {
console.log(statusText) console.log(statusText)
} }
} }
ComboBox { ComboBox {
id: privacy id: privacy
anchors { anchors {
@ -405,7 +447,6 @@ Page {
console.log(mediaModel.get(k).id) console.log(mediaModel.get(k).id)
media_ids.push(mediaModel.get(k).id) media_ids.push(mediaModel.get(k).id)
} }
var msg = { var msg = {
"action": 'statuses', "action": 'statuses',
"method": 'POST', "method": 'POST',
@ -430,7 +471,7 @@ Page {
warningContent.text = "" warningContent.text = ""
toot.text = "" toot.text = ""
mediaModel.clear() mediaModel.clear()
pageStack.pop() sentBanner.showText(qsTr("Toot sent!"))
} }
} }
@ -439,9 +480,10 @@ Page {
color: Theme.highlightBackgroundColor color: Theme.highlightBackgroundColor
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
height: 3 height: Theme.itemSizeSmall * 0.05
} }
} }
Component.onCompleted: { Component.onCompleted: {
toot.cursorPosition = toot.text.length toot.cursorPosition = toot.text.length
if (mdl.count > 0) { if (mdl.count > 0) {
@ -474,157 +516,66 @@ Page {
"conf": Logic.conf "conf": Logic.conf
}) })
} }
Component {
id: firstWizardPage
Dialog { BackgroundItem {
id: emoticonsDialog id: hiddenPanel
canAccept: false //selector.currentIndex >= 0 visible: !panel.open
height: Theme.paddingLarge * 0.5
//acceptDestination: conversationPage width: parent.width
onAcceptPendingChanged: { opacity: enabled ? 0.6 : 0.0
if (acceptPending) { Behavior on opacity { FadeAnimator { duration: 400 } }
anchors {
// Tell the destination page what the selected category is horizontalCenter: parent.horizontalCenter
// acceptDestinationInstance.category = selector.value bottom: parent.bottom
}
} }
SilicaGridView { MouseArea {
id: gridView
anchors.fill: parent anchors.fill: parent
cellWidth: gridView.width / 6 onClicked: panel.open = !panel.open
cellHeight: cellWidth
header: PageHeader {
title: qsTr("Emojis")
description: qsTr("Tap to insert")
} }
model: ListModel {
ListElement { section: "smileys"; glyph: "😁" }
ListElement { section: "smileys"; glyph: "😂" }
ListElement { section: "smileys"; glyph: "😃" }
ListElement { section: "smileys"; glyph: "😄" }
ListElement { section: "smileys"; glyph: "😅" }
ListElement { section: "smileys"; glyph: "😆" }
ListElement { section: "smileys"; glyph: "😉" }
ListElement { section: "smileys"; glyph: "😊" }
ListElement { section: "smileys"; glyph: "😋" }
ListElement { section: "smileys"; glyph: "😌" }
ListElement { section: "smileys"; glyph: "😍" }
ListElement { section: "smileys"; glyph: "😏" }
ListElement { section: "smileys"; glyph: "😒" }
ListElement { section: "smileys"; glyph: "😓" }
ListElement { section: "smileys"; glyph: "😔" }
ListElement { section: "smileys"; glyph: "😖" }
ListElement { section: "smileys"; glyph: "😘" }
ListElement { section: "smileys"; glyph: "😚" }
ListElement { section: "smileys"; glyph: "😜" }
ListElement { section: "smileys"; glyph: "😝" }
ListElement { section: "smileys"; glyph: "😞" }
ListElement { section: "smileys"; glyph: "😠" }
ListElement { section: "smileys"; glyph: "😡" }
ListElement { section: "smileys"; glyph: "😢" }
ListElement { section: "smileys"; glyph: "😣" }
ListElement { section: "smileys"; glyph: "😤" }
ListElement { section: "smileys"; glyph: "😥" }
ListElement { section: "smileys"; glyph: "😨" }
ListElement { section: "smileys"; glyph: "😩" }
ListElement { section: "smileys"; glyph: "😪" }
ListElement { section: "smileys"; glyph: "😫" }
ListElement { section: "smileys"; glyph: "😭" }
ListElement { section: "smileys"; glyph: "😰" }
ListElement { section: "smileys"; glyph: "😱" }
ListElement { section: "smileys"; glyph: "😲" }
ListElement { section: "smileys"; glyph: "😳" }
ListElement { section: "smileys"; glyph: "😵" }
ListElement { section: "smileys"; glyph: "😷" }
ListElement { section: "smileys"; glyph: "😸" }
ListElement { section: "smileys"; glyph: "😹" }
ListElement { section: "smileys"; glyph: "😺" }
ListElement { section: "smileys"; glyph: "😻" }
ListElement { section: "smileys"; glyph: "😼" }
ListElement { section: "smileys"; glyph: "😽" }
ListElement { section: "smileys"; glyph: "😾" }
ListElement { section: "smileys"; glyph: "😿" }
ListElement { section: "smileys"; glyph: "🙀" }
ListElement { section: "smileys"; glyph: "🙅" }
ListElement { section: "smileys"; glyph: "🙆" }
ListElement { section: "smileys"; glyph: "🙇" }
ListElement { section: "smileys"; glyph: "🙈" }
ListElement { section: "smileys"; glyph: "🙉" }
ListElement { section: "smileys"; glyph: "🙊" }
ListElement { section: "smileys"; glyph: "🙋" }
ListElement { section: "smileys"; glyph: "🙌" }
ListElement { section: "smileys"; glyph: "🙍" }
ListElement { section: "smileys"; glyph: "🙎" }
ListElement { section: "smileys"; glyph: "🙏" }
ListElement { section: "Transport and map"; glyph: "🚀" } Rectangle {
ListElement { section: "Transport and map"; glyph: "🚃" } id: hiddenPanelBackground
ListElement { section: "Transport and map"; glyph: "🚀" } width: parent.width
ListElement { section: "Transport and map"; glyph: "🚄" } height: parent.height
ListElement { section: "Transport and map"; glyph: "🚅" } color: Theme.highlightBackgroundColor
ListElement { section: "Transport and map"; glyph: "🚇" } opacity: 0.4
ListElement { section: "Transport and map"; glyph: "🚉" } anchors.fill: parent
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: "♈" } Rectangle {
ListElement { section: "Horoscope Signs"; glyph: "♉" } id: progressBarBackground
ListElement { section: "Horoscope Signs"; glyph: "♊" } width: parent.width
ListElement { section: "Horoscope Signs"; glyph: "♋" } height: progressBarHiddenPanel.height
ListElement { section: "Horoscope Signs"; glyph: "♌" } color: Theme.highlightBackgroundColor
ListElement { section: "Horoscope Signs"; glyph: "♍" } opacity: 0.2
ListElement { section: "Horoscope Signs"; glyph: "♎" } anchors {
ListElement { section: "Horoscope Signs"; glyph: "♏" } left: parent.left
ListElement { section: "Horoscope Signs"; glyph: "♐" } right: parent.right
ListElement { section: "Horoscope Signs"; glyph: "♑" } top: parent.top
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()
} }
} }
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
} }
} }
} }
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 QtQuick 2.0
import QtWebKit 3.0 import QtWebKit 3.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../lib/API.js" as Logic import "../lib/API.js" as Logic
Page { Page {
id: loginPage id: loginPage
// The effective value will be restricted by ApplicationWindow.allowedOrientations // The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
SilicaFlickable { SilicaFlickable {
anchors.fill: parent anchors.fill: parent
contentHeight: column.height + Theme.paddingLarge contentHeight: column.height + Theme.paddingLarge
@ -52,8 +18,9 @@ Page {
Column { Column {
id: column id: column
width: parent.width width: parent.width
PageHeader {
PageHeader { title: qsTr("Login") } title: qsTr("Login")
}
SectionHeader { SectionHeader {
text: qsTr("Instance") text: qsTr("Instance")
@ -64,14 +31,13 @@ Page {
focus: true focus: true
label: qsTr("Enter a valid Mastodon instance URL") label: qsTr("Enter a valid Mastodon instance URL")
text: "https://" text: "https://"
placeholderText: "https://mastodon.social"
width: parent.width width: parent.width
validator: RegExpValidator { regExp: /^(ftp|http|https):\/\/[^ "]+$/ } validator: RegExpValidator { regExp: /^(ftp|http|https):\/\/[^ "]+$/ }
EnterKey.enabled: instance.acceptableInput; EnterKey.enabled: instance.acceptableInput;
EnterKey.highlighted: instance.acceptableInput; EnterKey.highlighted: instance.acceptableInput;
EnterKey.iconSource: "image://theme/icon-m-accept" EnterKey.iconSource: "image://theme/icon-m-accept"
EnterKey.onClicked: { 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", Logic.api.registerApplication("Tooter",
'http://localhost/harbour-tooter', // redirect uri, we will need this later on 'http://localhost/harbour-tooter', // redirect uri, we will need this later on
["read", "write", "follow"], //scopes ["read", "write", "follow"], //scopes
@ -83,7 +49,6 @@ Page {
conf.instance = instance.text; conf.instance = instance.text;
conf.login = false; conf.login = false;
/*conf['login'] = false; /*conf['login'] = false;
conf['mastodon_client_id'] = data['mastodon_client_id']; conf['mastodon_client_id'] = data['mastodon_client_id'];
conf['mastodon_client_secret'] = data['mastodon_client_secret']; conf['mastodon_client_secret'] = data['mastodon_client_secret'];
@ -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 QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../lib/API.js" as Logic import "../lib/API.js" as Logic
@ -36,8 +6,9 @@ import "./components/"
Page { Page {
id: mainPage id: mainPage
property bool isFirstPage: true 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 // The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
@ -57,10 +28,11 @@ Page {
} }
} }
} }
VisualItemModel { VisualItemModel {
id: visualModel id: visualModel
MyList{ MyList{
id: tlHome; id: tlHome
title: qsTr("Home") title: qsTr("Home")
type: "timelines/home" type: "timelines/home"
mdl: Logic.modelTLhome mdl: Logic.modelTLhome
@ -68,8 +40,9 @@ Page {
height: parent.itemHeight height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer onOpenDrawer: infoPanel.open = setDrawer
} }
MyList{ MyList{
id: tlNotifications; id: tlNotifications
title: qsTr("Notifications") title: qsTr("Notifications")
type: "notifications" type: "notifications"
notifier: true notifier: true
@ -78,8 +51,9 @@ Page {
height: parent.itemHeight height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer onOpenDrawer: infoPanel.open = setDrawer
} }
MyList{ MyList{
id: tlLocal; id: tlLocal
title: qsTr("Local") title: qsTr("Local")
type: "timelines/public?local=true" type: "timelines/public?local=true"
//params: ["local", true] //params: ["local", true]
@ -88,8 +62,9 @@ Page {
height: parent.itemHeight height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer onOpenDrawer: infoPanel.open = setDrawer
} }
MyList{ MyList{
id: tlPublic; id: tlPublic
title: qsTr("Federated") title: qsTr("Federated")
type: "timelines/public" type: "timelines/public"
mdl: Logic.modelTLpublic mdl: Logic.modelTLpublic
@ -97,22 +72,30 @@ Page {
height: parent.itemHeight height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer onOpenDrawer: infoPanel.open = setDrawer
} }
Item { Item {
id: tlSearch; id: tlSearch
property ListModel mdl: ListModel {}
property string search
width: parent.itemWidth width: parent.itemWidth
height: parent.itemHeight height: parent.itemHeight
property ListModel mdl: ListModel {}
property string search;
onSearchChanged: { onSearchChanged: {
console.log(search) console.log(search)
loader.sourceComponent = loading 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 { Loader {
id: loader id: loader
anchors.fill: parent anchors.fill: parent
} }
Column { Column {
id: headerContainer id: headerContainer
width: tlSearch.width width: tlSearch.width
@ -132,6 +115,7 @@ Page {
} }
} }
} }
Component { Component {
id: loading id: loading
BusyIndicator { BusyIndicator {
@ -140,6 +124,7 @@ Page {
running: true running: true
} }
} }
Component { Component {
id: tagListComponent id: tagListComponent
MyList { MyList {
@ -164,6 +149,7 @@ Page {
} }
} }
} }
Component { Component {
id: userListComponent id: userListComponent
MyList { MyList {
@ -184,11 +170,12 @@ Page {
delegate: ItemUser { delegate: ItemUser {
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("Profile.qml"), { pageStack.push(Qt.resolvedUrl("ProfilePage.qml"), {
"display_name": model.account_display_name, "display_name": model.account_display_name,
"username": model.account_acct, "username": model.account_acct,
"user_id": model.account_id, "user_id": model.account_id,
"profileImage": model.account_avatar "profileImage": model.account_avatar,
"profileBackground": model.account_header
}) })
} }
} }
@ -201,10 +188,32 @@ 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 { SlideshowView {
id: slideshow id: slideshow
@ -216,12 +225,9 @@ Page {
onCurrentIndexChanged: { onCurrentIndexChanged: {
navigation.slideshowIndexChanged(currentIndex) navigation.slideshowIndexChanged(currentIndex)
} }
anchors { anchors {
fill: parent fill: parent
leftMargin: 0
top: parent.top top: parent.top
topMargin: 0
rightMargin: mainPage.isPortrait ? 0 : infoPanel.visibleSize rightMargin: mainPage.isPortrait ? 0 : infoPanel.visibleSize
bottomMargin: mainPage.isPortrait ? infoPanel.visibleSize : 0 bottomMargin: mainPage.isPortrait ? infoPanel.visibleSize : 0
} }
@ -231,22 +237,22 @@ Page {
} }
IconButton { IconButton {
anchors { id: newToot
right: (mainPage.isPortrait ? parent.right : infoPanel.left)
bottom: (mainPage.isPortrait ? infoPanel.top : parent.bottom)
margins: {
left: Theme.paddingLarge
bottom: Theme.paddingLarge
}
}
id: newTweet
width: Theme.iconSizeLarge width: Theme.iconSizeLarge
height: width height: width
visible: !isPortrait ? true : !infoPanel.open visible: !isPortrait ? true : !infoPanel.open
icon.source: "image://theme/icon-l-add" 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: { 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') navigation.navigateTo('search')
} else { } else {
Qt.openUrlExternally(href); Qt.openUrlExternally(href)
} }
} }
Component.onCompleted: { Component.onCompleted: {
console.log("aaa") 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,39 +1,80 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../lib/API.js" as Logic import "../lib/API.js" as Logic
Page { Page {
id: settingsPage
allowedOrientations: Orientation.All
SilicaFlickable { SilicaFlickable {
anchors.fill: parent
contentHeight: column.height + Theme.paddingLarge contentHeight: column.height + Theme.paddingLarge
contentWidth: parent.width contentWidth: parent.width
anchors.fill: parent
RemorsePopup { id: remorsePopup } RemorsePopup { id: remorsePopup }
VerticalScrollDecorator {} VerticalScrollDecorator {}
Column { Column {
id: column id: column
spacing: Theme.paddingSmall spacing: Theme.paddingMedium
width: parent.width width: parent.width
PageHeader { PageHeader {
title: qsTr("Settings") title: qsTr("Settings")
} }
Column {
// No spacing in this column SectionHeader { text: qsTr("Options")}
width: parent.width
IconTextSwitch { 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 id: removeAccount
width: parent.width
height: txtRemoveAccount.height + btnRemoveAccount.height + Theme.paddingLarge
anchors {
left: parent.left
leftMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.paddingLarge
}
Icon {
id: icnRemoveAccount
color: Theme.highlightColor
width: Theme.iconSizeMedium
fillMode: Image.PreserveAspectFit
source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add"
anchors.right: parent.right
}
Column {
id: clnRemoveAccount
spacing: Theme.paddingMedium
anchors {
left: parent.left
right: icnRemoveAccount.left
}
Button {
id: btnRemoveAccount
text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account") 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") width: Theme.buttonWidthMedium
icon.source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add" anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
remorsePopup.execute(btnRemoveAccount.text, function() {
onCheckedChanged: {
remorsePopup.execute(removeAccount.text, function() {
busy = true;
checked = false;
timer1.start();
if (Logic.conf['login']) { if (Logic.conf['login']) {
Logic.conf['login'] = false Logic.conf['login'] = false
Logic.conf['instance'] = null; Logic.conf['instance'] = null;
@ -43,44 +84,48 @@ Page {
}) })
} }
/* busy = true;
checked = false;
timer1.start()
}*/
Timer { Timer {
id: timer1 id: timer1
interval: 4700 interval: 4700
onTriggered: parent.busy = false onTriggered: parent.busy = false
} }
} }
IconTextSwitch {
//enabled: false Label {
checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages'] id: txtRemoveAccount
text: qsTr("Load images in toots") 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")
description: qsTr("Disable this option if you want to preserve your data connection") font.pixelSize: Theme.fontSizeExtraSmall
icon.source: "image://theme/icon-m-image" wrapMode: Text.Wrap
onClicked: { color: Theme.highlightColor
Logic.conf['loadImages'] = checked anchors {
left: parent.left
right: parent.right
rightMargin: Theme.paddingLarge + icnRemoveAccount
} }
} }
IconTextSwitch { }
}
SectionHeader {
text: qsTr("Translate") text: qsTr("Translate")
description: qsTr("Use Transifex to help with app translation to your language")
icon.source: "image://theme/icon-m-font-size"
onCheckedChanged: {
busy = true;
checked = false;
Qt.openUrlExternally("https://www.transifex.com/dysko/tooter/");
timer2.start()
}
Timer {
id: timer2
interval: 4700
onTriggered: parent.busy = false
} }
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 { SectionHeader {
text: qsTr("Credits") text: qsTr("Credits")
} }
@ -90,52 +135,61 @@ Page {
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
rightMargin: Theme.horizontalPageMargin rightMargin: Theme.paddingLarge
} }
Repeater { Repeater {
model: ListModel { model: ListModel {
ListElement { ListElement {
name: "Duško Angirević" name: "Duško Angirević"
desc: qsTr("UI/UX design and development") desc: qsTr("UI/UX design and development")
mastodon: "dysko@mastodon.social" mastodon: "dysko@mastodon.social"
mail: "" mail: ""
} }
ListElement { ListElement {
name: "Miodrag Nikolić" name: "Miodrag Nikolić"
desc: qsTr("Visual identity") desc: qsTr("Visual identity")
mastodon: "" mastodon: ""
mail: "micotakis@gmail.com" mail: "micotakis@gmail.com"
} }
ListElement { ListElement {
name: "Molan" name: "Molan"
desc: qsTr("Development and translations") desc: qsTr("Development and translations")
mastodon: "" mastodon: "molan@fosstodon.org"
mail: "mol_an@sunrise.ch" mail: ""
} }
ListElement { ListElement {
name: "Quentin PAGÈS / Quenti ♏" name: "Quentin PAGÈS / Quenti ♏"
desc: qsTr("Occitan & French translation") desc: qsTr("Occitan & French translation")
mastodon: "Quenti@framapiaf.org" mastodon: "Quenti@framapiaf.org"
mail: "" mail: ""
} }
ListElement { ListElement {
name: "Luchy Kon / dashinfantry" name: "Luchy Kon / dashinfantry"
desc: qsTr("Chinese translation") desc: qsTr("Chinese translation")
mastodon: "" mastodon: ""
mail: "dashinfantry@gmail.com" mail: "dashinfantry@gmail.com"
} }
ListElement { ListElement {
name: "André Koot" name: "André Koot"
desc: qsTr("Dutch translation") desc: qsTr("Dutch translation")
mastodon: "meneer@mastodon.social" mastodon: "meneer@mastodon.social"
mail: "https://twitter.com/meneer" mail: "https://twitter.com/meneer"
} }
ListElement { ListElement {
name: "CarmenFdez" name: "CarmenFdez"
desc: qsTr("Spanish translation") desc: qsTr("Spanish translation")
mastodon: "" mastodon: ""
mail: "" mail: ""
} }
ListElement { ListElement {
name: "Mohamed-Touhami MAHDI" name: "Mohamed-Touhami MAHDI"
desc: qsTr("Added README file") desc: qsTr("Added README file")
@ -147,31 +201,29 @@ Page {
Item { Item {
width: parent.width width: parent.width
height: Theme.itemSizeMedium height: Theme.itemSizeMedium
IconButton { IconButton {
id: btn id: btn
icon.source: "image://theme/" + (model.mastodon !== "" ? "icon-m-outline-chat" : "icon-m-mail") + "?" + (pressed
? Theme.highlightColor : Theme.primaryColor)
anchors { anchors {
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
right: parent.right right: parent.right
} }
icon.source: "image://theme/" + (model.mastodon !== "" ? "icon-m-contact" : "icon-m-mail") + "?" + (pressed
? Theme.highlightColor
: Theme.primaryColor)
onClicked: { onClicked: {
if (model.mastodon !== ""){ if (model.mastodon !== ""){
var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
pageStack.push(Qt.resolvedUrl("Conversation.qml"), { pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
toot_id: 0, headerTitle: "Mention",
title: model.name,
description: '@'+model.mastodon, description: '@'+model.mastodon,
avatar: "", type: "new"
mdl: m,
type: "reply"
}) })
} else { } else {
Qt.openUrlExternally("mailto:"+model.mail); Qt.openUrlExternally("mailto:"+model.mail);
} }
} }
} }
Column { Column {
anchors { anchors {
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
@ -184,9 +236,10 @@ Page {
Label { Label {
id: lblName id: lblName
text: model.name text: model.name
color: Theme.secondaryColor color: Theme.highlightColor
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
} }
Label { Label {
text: model.desc text: model.desc
color: Theme.secondaryHighlightColor 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 { BackgroundItem {
id: delegate id: delegate
signal openUser (string notice) signal openUser (string notice)
height: Theme.itemSizeMedium
width: parent.width width: parent.width
height: Theme.itemSizeMedium
Rectangle { Rectangle {
id: avatar id: avatar
@ -23,6 +25,7 @@ BackgroundItem {
anchors.fill: parent anchors.fill: parent
source: model.account_avatar source: model.account_avatar
} }
BusyIndicator { BusyIndicator {
size: BusyIndicatorSize.Small size: BusyIndicatorSize.Small
opacity: img.status === Image.Ready ? 0.0 : 1.0 opacity: img.status === Image.Ready ? 0.0 : 1.0
@ -30,16 +33,19 @@ BackgroundItem {
running: avatar.status !== Image.Ready; running: avatar.status !== Image.Ready;
anchors.centerIn: parent anchors.centerIn: parent
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: pageStack.push(Qt.resolvedUrl("./../Profile.qml"), { onClicked: pageStack.push(Qt.resolvedUrl("./../ProfilePage.qml"), {
"display_name": model.account_display_name, "display_name": model.account_display_name,
"username": model.account_acct, "username": model.account_acct,
"user_id": model.account_id, "user_id": model.account_id,
"profileImage": model.account_avatar "profileImage": model.account_avatar,
"profileBackground": model.account_header
}) })
} }
} }
Column { Column {
anchors.left: avatar.right anchors.left: avatar.right
anchors.leftMargin: Theme.paddingLarge anchors.leftMargin: Theme.paddingLarge
@ -63,6 +69,8 @@ BackgroundItem {
"display_name": model.account_display_name, "display_name": model.account_display_name,
"username": model.account_acct, "username": model.account_acct,
"user_id": model.account_id, "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 { Item {
id: holder
property ListModel model property ListModel model
property double wRatio : 16/9 property double wRatio : 16/9
property double hRatio : 9/16 property double hRatio : 9/16
id: holder
width: width width: width
height: height height: height
Component.onCompleted: { Component.onCompleted: {
@ -74,8 +76,6 @@ Item {
} }
} }
MyImage { MyImage {
id: placeholder1 id: placeholder1
width: 2 width: 2
@ -94,6 +94,7 @@ Item {
} }
} }
} }
MyImage { MyImage {
id: placeholder2 id: placeholder2
width: 2 width: 2
@ -112,6 +113,7 @@ Item {
} }
} }
} }
MyImage { MyImage {
id: placeholder3 id: placeholder3
width: 2 width: 2
@ -130,6 +132,7 @@ Item {
} }
} }
} }
MyImage { MyImage {
id: placeholder4 id: placeholder4
width: 2 width: 2
@ -148,8 +151,5 @@ Item {
} }
} }
} }
} }

View file

@ -2,11 +2,14 @@ import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import QtMultimedia 5.0 import QtMultimedia 5.0
Page {
id: imagePage FullscreenContentPage {
id: mediaPage
property string type: "" property string type: ""
property string previewURL: "" property string previewURL: ""
property string mediaURL: "" property string mediaURL: ""
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
Component.onCompleted: function(){ Component.onCompleted: function(){
console.log(type) console.log(type)
@ -14,31 +17,35 @@ Page {
console.log(mediaURL) console.log(mediaURL)
if (type != 'gifv' && type != 'video') { if (type != 'gifv' && type != 'video') {
imagePreview.source = mediaURL imagePreview.source = mediaURL
imageFlickable.visible = true; imageFlickable.visible = true
} else { } else {
video.source = mediaURL video.source = mediaURL
video.fillMode = VideoOutput.PreserveAspectFit video.fillMode = VideoOutput.PreserveAspectFit
video.play() video.play()
videoFlickable.visible = true; videoFlickable.visible = true
} }
} }
Flickable { Flickable {
id: videoFlickable id: videoFlickable
visible: false visible: false
anchors.fill: parent
contentWidth: imageContainer.width; contentHeight: imageContainer.height
clip: true clip: true
contentWidth: imageContainer.width
contentHeight: imageContainer.height
anchors.fill: parent
Image { Image {
id: videoPreview id: videoPreview
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
anchors.fill: parent anchors.fill: parent
source: previewURL source: previewURL
} }
Video { Video {
id: video id: video
anchors.fill: parent anchors.fill: parent
onErrorStringChanged: function(){ onErrorStringChanged: function(){
videoError.visible = true; videoError.visible = true
} }
onStatusChanged: { onStatusChanged: {
console.log(status) console.log(status)
@ -49,10 +56,8 @@ Page {
case MediaPlayer.EndOfMedia: case MediaPlayer.EndOfMedia:
console.log("EndOfMedia") console.log("EndOfMedia")
return; return;
} }
} }
onPlaybackStateChanged: { onPlaybackStateChanged: {
console.log(playbackState) console.log(playbackState)
switch (playbackState){ switch (playbackState){
@ -63,12 +68,10 @@ Page {
playerIcon.icon.source = "image://theme/icon-m-play" playerIcon.icon.source = "image://theme/icon-m-play"
return; return;
case MediaPlayer.StoppedState: case MediaPlayer.StoppedState:
playerIcon.icon.source = "image://theme/icon-m-stop" playerIcon.icon.source = "image://theme/icon-m-reload"
return; return;
} }
} }
onPositionChanged: function(){ onPositionChanged: function(){
//console.log(duration) //console.log(duration)
//console.log(bufferProgress) //console.log(bufferProgress)
@ -79,18 +82,23 @@ Page {
playerProgress.minimumValue = 0 playerProgress.minimumValue = 0
playerProgress.value = position playerProgress.value = position
} }
}
onStopped: function() {
if (video.duration < 30000)
video.play()
else
video.stop()
}
}
onStopped: function(){
play()
}
IconButton { IconButton {
id: playerIcon 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" icon.source: "image://theme/icon-m-play"
anchors {
left: parent.left
bottom: parent.bottom
leftMargin: Theme.horizontalPageMargin
bottomMargin: Theme.horizontalPageMargin
}
onClicked: function() { onClicked: function() {
if (video.playbackState === MediaPlayer.PlayingState) if (video.playbackState === MediaPlayer.PlayingState)
video.pause() video.pause()
@ -100,50 +108,17 @@ Page {
} }
ProgressBar { ProgressBar {
indeterminate: true
id: playerProgress id: playerProgress
anchors.left: playerIcon.right indeterminate: true
anchors.right: videoDlBtn.left width: 400
anchors {
anchors.verticalCenter: playerIcon.verticalCenter verticalCenter: playerIcon.verticalCenter
anchors.leftMargin: 0 left: playerIcon.right
anchors.bottomMargin: Theme.paddingMedium right: parent.right
} rightMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium
IconButton { bottomMargin: Theme.horizontalPageMargin
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]);
} }
} }
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 { MouseArea {
anchors.fill: parent anchors.fill: parent
@ -154,17 +129,43 @@ Page {
video.play() 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 { Flickable {
id: imageFlickable id: imageFlickable
visible: false visible: false
anchors.fill: parent contentWidth: imageContainer.width
contentWidth: imageContainer.width; contentHeight: imageContainer.height contentHeight: imageContainer.height
clip: true clip: true
onHeightChanged: if (imagePreview.status === Image.Ready) imagePreview.fitToScreen(); anchors.fill: parent
onHeightChanged: if (imagePreview.status === Image.Ready) {
imagePreview.fitToScreen()
}
Item { Item {
id: imageContainer id: imageContainer
@ -177,18 +178,17 @@ Page {
property real prevScale property real prevScale
function fitToScreen() { 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 pinchArea.minScale = scale
prevScale = scale prevScale = scale
} }
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
cache: true cache: true
asynchronous: true asynchronous: true
sourceSize.height: 1000; sourceSize.width: mediaPage.width
smooth: false smooth: true
anchors.centerIn: parent
onStatusChanged: { onStatusChanged: {
if (status == Image.Ready) { if (status == Image.Ready) {
fitToScreen() fitToScreen()
@ -221,15 +221,16 @@ Page {
PinchArea { PinchArea {
id: pinchArea id: pinchArea
opacity: 0.3
property real minScale: 1.0 property real minScale: 1.0
property real maxScale: 3.0 property real maxScale: 3.0
opacity: 0.3
anchors.fill: parent anchors.fill: parent
enabled: imagePreview.status === Image.Ready enabled: imagePreview.status === Image.Ready
pinch.target: imagePreview pinch.target: imagePreview
pinch.minimumScale: minScale * 0.5 // This is to create "bounce back effect" 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: { onPinchFinished: {
imageFlickable.returnToBounds() imageFlickable.returnToBounds()
@ -242,6 +243,7 @@ Page {
bounceBackAnimation.start() bounceBackAnimation.start()
} }
} }
NumberAnimation { NumberAnimation {
id: bounceBackAnimation id: bounceBackAnimation
target: imagePreview target: imagePreview
@ -267,39 +269,57 @@ Page {
Component { Component {
id: loadingIndicator id: loadingIndicator
Item { Item {
width: mediaPage.width
height: childrenRect.height height: childrenRect.height
width: imagePage.width
ProgressCircle { ProgressCircle {
id: imageLoadingIndicator id: imageLoadingIndicator
anchors.horizontalCenter: parent.horizontalCenter
progressValue: imagePreview.progress progressValue: imagePreview.progress
progressColor: inAlternateCycle ? Theme.highlightColor : Theme.highlightDimmerColor
backgroundColor: inAlternateCycle ? Theme.highlightDimmerColor : Theme.highlightColor
anchors.horizontalCenter: parent.horizontalCenter
} }
} }
} }
} }
Component { Component {
id: failedLoading id: failedLoading
Text { Text {
font.pixelSize: Theme.fontSizeSmall;
text: qsTr("Error loading") text: qsTr("Error loading")
font.pixelSize: Theme.fontSizeSmall;
color: Theme.highlightColor color: Theme.highlightColor
} }
} }
IconButton { IconButton {
visible: true id: dismissBtn
anchors.right: parent.right icon.source: "image://theme/icon-m-dismiss"
anchors.bottom: parent.bottom anchors {
anchors.rightMargin: Theme.paddingLarge top: parent.top
anchors.bottomMargin: Theme.paddingMedium topMargin: Theme.horizontalPageMargin
//width: Theme.iconSizeMedium+Theme.paddingMedium*2 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" icon.source: "image://theme/icon-m-cloud-download"
onClicked: { onClicked: {
var filename = mediaURL.split("/"); var filename = mediaURL.split("/");
FileDownloader.downloadFile(mediaURL, filename[filename.length-1]); FileDownloader.downloadFile(mediaURL, filename[filename.length-1]);
} }
} }
VerticalScrollDecorator { flickable: imageFlickable } VerticalScrollDecorator { flickable: imageFlickable }
} }

View file

@ -1,71 +1,72 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
Item { Item {
id: miniheader id: miniHeader
height: lblName.height height: lblName.height
width: parent.width width: parent.width
Label { Label {
id: lblName id: lblName
anchors {
left: parent.left
leftMargin: Theme.paddingMedium
}
text: text:
if (account_display_name === "") { if (account_display_name === "") {
account_username.split('@')[0] account_username.split('@')[0]
} }
else account_display_name else account_display_name
width: contentWidth > parent.width /2 ? parent.width /2 : contentWidth
truncationMode: TruncationMode.Fade
font.weight: Font.Bold font.weight: Font.Bold
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor) 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
}
} }
Image { 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 y: Theme.paddingLarge
anchors { anchors {
left: lblName.right left: lblName.right
leftMargin: Theme.paddingSmall leftMargin: Theme.paddingSmall
verticalCenter: lblName.verticalCenter 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 { Label {
id: lblScreenName id: lblScreenName
text: '@'+account_username
font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
truncationMode: TruncationMode.Fade
anchors { anchors {
left: iconVerified.right left: icnLocked.right
right: lblDate.left right: lblDate.left
leftMargin: Theme.paddingMedium leftMargin: Theme.paddingMedium
baseline: lblName.baseline baseline: lblName.baseline
} }
truncationMode: TruncationMode.Fade
text: '@'+account_username
font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
} }
Label {
Label {
id: lblDate id: lblDate
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours) text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours)
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
anchors { anchors {
right: parent.right right: parent.right
baseline: lblName.baseline
rightMargin: Theme.horizontalPageMargin rightMargin: Theme.horizontalPageMargin
baseline: lblName.baseline
} }
} }
} }

View file

@ -1,13 +1,19 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
Item { Item {
id: ministatus id: miniStatus
visible: true visible: true
height: icon.height+Theme.paddingMedium height: icon.height+Theme.paddingMedium
width: parent.width width: parent.width
Image { Icon {
id: icon id: icon
visible: type.length
color: Theme.highlightColor
width: Theme.iconSizeExtraSmall
height: width
source: typeof typeIcon !== "undefined" ? typeIcon : ""
anchors { anchors {
top: parent.top top: parent.top
topMargin: Theme.paddingMedium topMargin: Theme.paddingMedium
@ -15,12 +21,8 @@ Item {
left: parent.left left: parent.left
leftMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium - width leftMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium - width
} }
visible: type.length
width: Theme.iconSizeExtraSmall
height: width
source: typeof typeIcon !== "undefined" ? typeIcon : ""
} }
Label { Label {
id: lblRtByName id: lblRtByName
visible: type.length visible: type.length
@ -42,12 +44,11 @@ Item {
action = qsTr('followed you'); action = qsTr('followed you');
break; break;
default: default:
ministatus.visible = false miniStatus.visible = false
action = type; action = type;
} }
return typeof reblog_account_username !== "undefined" ? '@' + reblog_account_username + ' ' + action : '' return typeof reblog_account_username !== "undefined" ? '@' + reblog_account_username + ' ' + action : ''
} }
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor color: Theme.highlightColor
} }

View file

@ -2,34 +2,41 @@ import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import QtMultimedia 5.0 import QtMultimedia 5.0
Item { Item {
id: myImage
property string type : "" property string type : ""
property string previewURL: "" property string previewURL: ""
property string mediaURL: "" property string mediaURL: ""
Rectangle { Rectangle {
opacity: 0.2 opacity: 0.2
anchors.fill: parent
color: Theme.highlightDimmerColor color: Theme.highlightDimmerColor
anchors.fill: parent
} }
Image { Image {
anchors.centerIn: parent
source: "image://theme/icon-m-image" source: "image://theme/icon-m-image"
anchors.centerIn: parent
} }
Rectangle { Rectangle {
id: progressRec id: progressRec
anchors.bottom: parent.bottom
width: 0 width: 0
height: Theme.paddingSmall height: Theme.paddingSmall
color: Theme.highlightBackgroundColor color: Theme.highlightBackgroundColor
anchors.bottom: parent.bottom
} }
Image { Image {
id: img id: img
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
asynchronous: true asynchronous: true
opacity: status === Image.Ready ? 1.0 : 0.0 opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} } Behavior on opacity { FadeAnimator {} }
source: previewURL source: previewURL
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
onProgressChanged: { onProgressChanged: {
if (progress != 1) if (progress != 1)
progressRec.width = parent.width * progress progressRec.width = parent.width * progress
@ -38,36 +45,47 @@ Item {
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { 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 { Image {
id: videoIcon
visible: type === "video" || type === "gifv" visible: type === "video" || type === "gifv"
anchors.centerIn: parent
source: "image://theme/icon-l-play" source: "image://theme/icon-l-play"
anchors.centerIn: parent
} }
BusyIndicator { BusyIndicator {
id: mediaLoader
size: BusyIndicatorSize.Large size: BusyIndicatorSize.Large
running: img.status !== Image.Ready running: img.status !== Image.Ready
opacity: img.status === Image.Ready ? 0.0 : 1.0 opacity: img.status === Image.Ready ? 0.0 : 1.0
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
Rectangle { Rectangle {
anchors.fill: parent id: mediaWarning
color: Theme.highlightDimmerColor color: Theme.highlightDimmerColor
visible: typeof status_sensitive != 'undefined' && status_sensitive ? true : false visible: typeof status_sensitive != 'undefined' && status_sensitive ? true : false
anchors.fill: parent
Image { Image {
source: "image://theme/icon-l-attention?"+Theme.highlightColor source: "image://theme/icon-l-attention?"+Theme.highlightColor
anchors.centerIn: parent anchors.centerIn: parent
} }
MouseArea { MouseArea {
anchors.fill: parent 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 "../../lib/API.js" as Logic
import "." import "."
SilicaListView { SilicaListView {
id: myList id: myList
property string type;
property string type
property string title property string title
property string vwPlaceholderText: qsTr("Loading") property string vwPlaceholderText: qsTr("Loading")
property string vwPlaceholderHint: qsTr("please wait...") property string vwPlaceholderHint: qsTr("please wait...")
@ -13,21 +15,21 @@ SilicaListView {
property ListModel mdl: [] property ListModel mdl: []
property variant params: [] property variant params: []
property var locale: Qt.locale() property var locale: Qt.locale()
property bool autoLoadMore : true; property bool autoLoadMore: true
property bool loadStarted : false; property bool loadStarted: false
property int scrollOffset; property int scrollOffset
property string action: "" property string action: ""
property variant vars property variant vars
property variant conf property variant conf
property bool notifier : false; property bool notifier: false
model: mdl model: mdl
signal notify (string what, int num) signal notify (string what, int num)
onNotify: { onNotify: {
console.log(what + " - " + num) console.log(what + " - " + num)
} }
signal openDrawer (bool setDrawer) signal openDrawer (bool setDrawer)
onOpenDrawer: { onOpenDrawer: {
//console.log("Open drawer: " + setDrawer) //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 { header: PageHeader {
title: myList.title title: myList.title
description: myList.description description: myList.description
} }
BusyIndicator {
size: BusyIndicatorSize.Large
running: myList.model.count === 0 && !viewPlaceHolder.visible
anchors.centerIn: parent
}
ViewPlaceholder { ViewPlaceholder {
id: viewPlaceHolder id: viewPlaceHolder
@ -62,7 +62,17 @@ SilicaListView {
MenuItem { MenuItem {
text: qsTr("Settings") text: qsTr("Settings")
onClicked: { 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 { delegate: VisualContainer {
} //Toot {} } //Toot {}
@ -95,10 +97,9 @@ SilicaListView {
} }
onCountChanged: { onCountChanged: {
loadStarted = false; loadStarted = false
/*contentY = scrollOffset /*contentY = scrollOffset
console.log("CountChanged!")*/ console.log("CountChanged!")*/
} }
footer: Item{ footer: Item{
@ -114,6 +115,7 @@ SilicaListView {
loadData("append") loadData("append")
} }
} }
BusyIndicator { BusyIndicator {
size: BusyIndicatorSize.Small size: BusyIndicatorSize.Small
running: loadStarted; running: loadStarted;
@ -121,18 +123,18 @@ SilicaListView {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
} }
onContentYChanged: {
onContentYChanged: {
if (Math.abs(contentY - scrollOffset) > Theme.itemSizeMedium) { if (Math.abs(contentY - scrollOffset) > Theme.itemSizeMedium) {
openDrawer(contentY - scrollOffset > 0 ? false : true ) openDrawer(contentY - scrollOffset > 0 ? false : true )
scrollOffset = contentY scrollOffset = contentY
} }
if(contentY+height > footerItem.y && !loadStarted && autoLoadMore){ if(contentY+height > footerItem.y && !loadStarted && autoLoadMore){
loadData("append") loadData("append")
loadStarted = true; loadStarted = true
} }
} }
VerticalScrollDecorator {} VerticalScrollDecorator {}
WorkerScript { WorkerScript {
@ -145,7 +147,6 @@ SilicaListView {
if (messageObject.fireNotification && notifier){ if (messageObject.fireNotification && notifier){
Logic.notifier(messageObject.data) Logic.notifier(messageObject.data)
} }
} }
} }
@ -160,17 +161,18 @@ SilicaListView {
loadData("prepend") loadData("prepend")
} }
} }
function loadData(mode){ function loadData(mode){
var p = []; var p = []
if (params.length) if (params.length)
for(var i = 0; i<params.length; i++) for(var i = 0; i<params.length; i++)
p.push(params[i]) p.push(params[i])
if (mode === "append" && model.count){ 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){ 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 = { var msg = {
@ -182,7 +184,7 @@ SilicaListView {
}; };
console.log(JSON.stringify(msg)) console.log(JSON.stringify(msg))
if (type !== "") if (type !== "")
worker.sendMessage(msg); worker.sendMessage(msg)
} }
} }

View file

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

View file

@ -1,81 +1,161 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
Item { Item {
id: header id: profileHeader
property int value: 0;
property string title: ""; property int value: 0
property string description: ""; property string title: ""
property string image: ""; property string description: ""
property string bg: ""; property string image: ""
property string bg: ""
width: parent.width width: parent.width
height: icon.height + Theme.paddingLarge*2 height: if (bot === true) {
/*Image { avatarImage.height + Theme.paddingLarge*2 + infoLbl.height + Theme.paddingLarge
anchors.fill: parent } else avatarImage.height + Theme.paddingLarge*2
asynchronous: true
fillMode: Image.PreserveAspectCrop
source: bg
opacity: 0.3
}*/
Rectangle { Rectangle {
anchors.fill: parent id: bgImage
opacity: 0.2 opacity: 0.2
gradient: Gradient { gradient: Gradient {
GradientStop { position: 0.0; color: Theme.highlightBackgroundColor } 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 { Image {
id: icon asynchronous: true
fillMode: Image.PreserveAspectCrop
source: bg
opacity: 0.8
anchors.fill: parent
}
}
Image {
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 { anchors {
left: parent.left left: parent.left
leftMargin: Theme.paddingLarge leftMargin: Theme.paddingLarge
top: parent.top top: parent.top
topMargin: Theme.paddingLarge topMargin: Theme.paddingLarge
} }
asynchronous: true
width: description === "" ? Theme.iconSizeMedium : Theme.iconSizeLarge Button {
height: width id: imageButton
source: opacity: 0
if (icon.status === Image.Error) width: Theme.iconSizeExtraLarge * 1.2
source = "../../images/icon-l-profile.svg?" + (pressed anchors {
? Theme.highlightColor top: parent.top
: Theme.primaryColor) left: parent.left
else image bottom: parent.bottom
} }
onClicked: {
pageStack.push(Qt.resolvedUrl("ProfileImage.qml"), {
"image": image
})
}
}
}
Column { Column {
anchors { anchors {
left: icon.right top: parent.top
topMargin: Theme.paddingLarge
left: avatarImage.right
leftMargin: Theme.paddingLarge leftMargin: Theme.paddingLarge
right: parent.right right: parent.right
rightMargin: Theme.paddingLarge rightMargin: Theme.paddingLarge
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
Label { Label {
id: ttl id: profileTitle
text: text: if (title === "") {
if (title === "") {
description.split('@')[0] description.split('@')[0]
} }
else title else title
height: contentHeight
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
font.family: Theme.fontFamilyHeading font.family: Theme.fontFamilyHeading
horizontalAlignment: Text.AlignRight color: Theme.highlightColor
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
width: parent.width width: parent.width
height: contentHeight
horizontalAlignment: Text.AlignRight
} }
Label { Label {
height: description === "" ? 0 : contentHeight id: profileDescription
text: "@"+description text: "@"+description
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: Theme.fontFamilyHeading font.family: Theme.fontFamilyHeading
horizontalAlignment: Text.AlignRight color: Theme.secondaryHighlightColor
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
width: parent.width 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 Sailfish.Silica 1.0
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
BackgroundItem {
signal send (string notice)
BackgroundItem {
id: delegate id: delegate
//property string text: "0"
width: parent.width signal send (string notice)
signal navigateTo(string link) 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 height: lblText.paintedHeight + (lblText.text.length > 0 ? Theme.paddingLarge : 0 )+ lblName.paintedHeight + (type.length ? Theme.paddingLarge + iconRT.height : 0) + Theme.paddingLarge
Image { Image {
id: iconRT id: iconRT
y: Theme.paddingLarge y: Theme.paddingLarge
anchors { anchors.right: avatar.right
right: avatar.right
}
visible: type.length visible: type.length
width: Theme.iconSizeExtraSmall width: Theme.iconSizeExtraSmall
height: width height: width
source: "../../images/boosted.svg" source: "../../images/boosted.svg"
} }
Label { Label {
id: lblRtByName id: lblRtByName
visible: type.length visible: type.length
anchors { anchors.left: lblName.left
left: lblName.left anchors.bottom: iconRT.bottom
bottom: iconRT.bottom font.pixelSize: Theme.fontSizeExtraSmall
} color: Theme.secondaryColor
text: { text: {
var action; var action;
switch(type){ switch(type){
@ -45,10 +46,8 @@ BackgroundItem {
} }
return '@' + retweetScreenName + ' ' + action return '@' + retweetScreenName + ' ' + action
} }
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
} }
Image { Image {
id: avatar id: avatar
x: Theme.horizontalPageMargin x: Theme.horizontalPageMargin
@ -62,71 +61,70 @@ BackgroundItem {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../Profile.qml"), { pageStack.push(Qt.resolvedUrl("../ProfilePage.qml"), {
"display_name": account_display_name, "display_name": account_display_name,
"username": account_username, "username": account_username,
"profileImage": account_avatar "profileImage": account_avatar
}) })
} }
}
} }
}
Label { Label {
id: lblName id: lblName
text: account_display_name
font.weight: Font.Bold
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
anchors { anchors {
top: avatar.top top: avatar.top
topMargin: 0 topMargin: 0
left: avatar.right left: avatar.right
leftMargin: Theme.paddingMedium leftMargin: Theme.paddingMedium
} }
text: account_display_name
font.weight: Font.Bold
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
} }
Image { Image {
id: iconVerified id: iconLocked
visible: account_locked
y: Theme.paddingLarge 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 { anchors {
left: lblName.right left: lblName.right
leftMargin: Theme.paddingSmall leftMargin: Theme.paddingSmall
verticalCenter: lblName.verticalCenter 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 { Label {
id: lblScreenName id: lblScreenName
anchors {
left: iconVerified.right
right: lblDate.left
leftMargin: Theme.paddingMedium
baseline: lblName.baseline
}
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
text: '@'+account_username text: '@'+account_username
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor) color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
anchors {
left: iconLocked.right
right: lblDate.left
leftMargin: Theme.paddingMedium
baseline: lblName.baseline
} }
}
Label { Label {
id: lblDate
function timestamp() { function timestamp() {
var txt = Format.formatDate(created_at, Formatter.Timepoint) var txt = Format.formatDate(created_at, Formatter.Timepoint)
var elapsed = Format.formatDate(created_at, Formatter.DurationElapsedShort) var elapsed = Format.formatDate(created_at, Formatter.DurationElapsedShort)
return (elapsed ? elapsed : txt ) 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) text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours)
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
anchors { anchors {
right: parent.right right: parent.right
@ -135,15 +133,8 @@ BackgroundItem {
} }
} }
Label { Text {
id: lblText id: lblText
anchors {
left: lblName.left
right: parent.right
top: lblScreenName.bottom
topMargin: Theme.paddingSmall
rightMargin: Theme.paddingLarge
}
height: content.length ? paintedHeight : 0 height: content.length ? paintedHeight : 0
onLinkActivated: { onLinkActivated: {
console.log(link) console.log(link)
@ -154,34 +145,40 @@ BackgroundItem {
"profileImage": "" "profileImage": ""
}) })
} else if (link[0] === "#") { } else if (link[0] === "#") {
pageStack.pop(pageStack.find(function(page) { pageStack.pop(pageStack.find(function(page) {
var check = page.isFirstPage === true; var check = page.isFirstPage === true;
if (check) if (check)
page.onLinkActivated(link) page.onLinkActivated(link)
return check; return check;
})); }));
send(link) send(link)
} else { } else {
Qt.openUrlExternally(link); Qt.openUrlExternally(link);
} }
} }
text: content text: content
textFormat: Text.RichText textFormat: Text.RichText
font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
linkColor : Theme.highlightColor linkColor : Theme.highlightColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
maximumLineCount: 6 maximumLineCount: 6
font.pixelSize: Theme.fontSizeSmall anchors {
color: (pressed ? Theme.highlightColor : Theme.primaryColor) left: lblName.left
right: parent.right
top: lblScreenName.bottom
topMargin: Theme.paddingSmall
rightMargin: Theme.paddingLarge
} }
}
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../Conversation.qml"), { pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
headerTitle: "Conversation",
toot_id: id, toot_id: id,
title: account_display_name, toot_url: status_url,
description: '@'+account_username, //title: account_display_name,
description: '@'+account_acc,
avatar: account_avatar, avatar: account_avatar,
type: "reply" type: "reply"
}) })

View file

@ -2,25 +2,48 @@ import QtQuick 2.2
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../../lib/API.js" as Logic import "../../lib/API.js" as Logic
BackgroundItem {
BackgroundItem {
id: delegate id: delegate
signal send (string notice) signal send (string notice)
signal navigateTo(string link) signal navigateTo(string link)
width: parent.width 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 { Rectangle {
x: 0; id: bgDirect
y: 0; x: 0
visible: status_visibility == 'direct' y: 0
visible: status_visibility === "direct"
width: parent.width width: parent.width
height: parent.height height: parent.height
opacity: 0.3 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 { MiniStatus {
id: ministatus id: miniStatus
anchors { anchors {
leftMargin: Theme.horizontalPageMargin leftMargin: Theme.horizontalPageMargin
rightMargin: Theme.horizontalPageMargin rightMargin: Theme.horizontalPageMargin
@ -28,22 +51,23 @@ BackgroundItem {
topMargin: Theme.paddingMedium topMargin: Theme.paddingMedium
} }
} }
Image { Image {
id: avatar id: avatar
anchors { visible: true
top: ministatus.visible ? ministatus.bottom : parent.top
topMargin: ministatus.visible ? Theme.paddingMedium : Theme.paddingLarge
left: parent.left
leftMargin: Theme.horizontalPageMargin
}
opacity: status === Image.Ready ? 1.0 : 0.0 opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} } Behavior on opacity { FadeAnimator {} }
asynchronous: true asynchronous: true
width: Theme.iconSizeMedium
height: width
smooth: true smooth: true
source: account_avatar 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: { onStatusChanged: {
if (avatar.status === Image.Error) if (avatar.status === Image.Error)
source = "../../images/icon-m-profile.svg?" + (pressed source = "../../images/icon-m-profile.svg?" + (pressed
@ -54,30 +78,53 @@ BackgroundItem {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../Profile.qml"), { pageStack.push(Qt.resolvedUrl("../ProfilePage.qml"), {
"display_name": model.account_display_name, "display_name": model.account_display_name,
"username": model.account_acct, "username": model.account_acct,
"user_id": model.account_id, "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 { Image {
id: iconTR id: iconTR
visible: typeof status_reblogged !== "undefined" && status_reblogged
width: Theme.iconSizeExtraSmall
height: width
source: "image://theme/icon-s-retweet"
anchors { anchors {
top: avatar.bottom top: avatar.bottom
topMargin: Theme.paddingMedium topMargin: Theme.paddingMedium
left: avatar.left 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 { Rectangle {
color: Theme.highlightDimmerColor id: bgReblogAvatar
color: Theme.secondaryColor
width: Theme.iconSizeSmall width: Theme.iconSizeSmall
height: width height: width
visible: typeof status_reblog !== "undefined" && status_reblog visible: typeof status_reblog !== "undefined" && status_reblog
@ -87,18 +134,21 @@ BackgroundItem {
left: parent.left left: parent.left
leftMargin: -width/3 leftMargin: -width/3
} }
Image { Image {
id: reblogAvatar
asynchronous: true asynchronous: true
width: Theme.iconSizeSmall
height: width
smooth: true smooth: true
opacity: status === Image.Ready ? 1.0 : 0.0 opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} } Behavior on opacity { FadeAnimator {} }
source: typeof reblog_account_avatar !== "undefined" ? reblog_account_avatar : '' source: typeof reblog_account_avatar !== "undefined" ? reblog_account_avatar : ''
visible: typeof status_reblog !== "undefined" && status_reblog visible: typeof status_reblog !== "undefined" && status_reblog
width: Theme.iconSizeSmall
height: width
} }
} }
} }
MiniHeader { MiniHeader {
id: miniHeader id: miniHeader
anchors { anchors {
@ -107,8 +157,23 @@ BackgroundItem {
right: parent.right right: parent.right
} }
} }
Text { Text {
id: lblContent 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 { anchors {
left: miniHeader.left left: miniHeader.left
leftMargin: Theme.paddingMedium leftMargin: Theme.paddingMedium
@ -118,7 +183,6 @@ BackgroundItem {
topMargin: Theme.paddingSmall topMargin: Theme.paddingSmall
bottomMargin: Theme.paddingLarge bottomMargin: Theme.paddingLarge
} }
height: content.length ? (contentWarningLabel.paintedHeight > paintedHeight ? contentWarningLabel.paintedHeight : paintedHeight) : 0
onLinkActivated: { onLinkActivated: {
var test = link.split("/") var test = link.split("/")
console.log(link) console.log(link)
@ -134,29 +198,32 @@ BackgroundItem {
})); }));
send(link) send(link)
} else if (test.length === 4 && test[3][0] === "@" ) { } else if (test.length === 4 && test[3][0] === "@" ) {
tlSearch.search = decodeURIComponent("@"+test[3].substring(1)+"@"+test[2]) pageStack.pop(pageStack.find(function(page) {
slideshow.positionViewAtIndex(4, ListView.SnapToItem) var check = page.isFirstPage === true;
navigation.navigateTo('search') if (check)
page.onLinkActivated(link)
return check;
}));
} else { } else {
Qt.openUrlExternally(link); 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 { Rectangle {
anchors.fill: parent
radius: 2 radius: 2
color: Theme.highlightDimmerColor color: Theme.highlightDimmerColor
visible: status_spoiler_text.length > 0 visible: status_spoiler_text.length > 0
anchors.fill: parent
Label { Label {
id: contentWarningLabel id: contentWarningLabel
text: model.status_spoiler_text
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.highlightColor
truncationMode: TruncationMode.Fade
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
width: parent.width
anchors { anchors {
topMargin: Theme.paddingSmall topMargin: Theme.paddingSmall
left: parent.left left: parent.left
@ -166,21 +233,21 @@ BackgroundItem {
rightMargin: Theme.paddingMedium rightMargin: Theme.paddingMedium
bottomMargin: Theme.paddingSmall bottomMargin: Theme.paddingSmall
} }
width: parent.width
truncationMode: TruncationMode.Fade
color: Theme.highlightColor
wrapMode: Text.WordWrap
text: model.status_spoiler_text
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: parent.visible = false; onClicked: parent.visible = false
} }
} }
} }
MediaBlock { MediaBlock {
id: media 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 { anchors {
left: lblContent.left left: lblContent.left
right: lblContent.right right: lblContent.right
@ -188,13 +255,15 @@ BackgroundItem {
topMargin: Theme.paddingSmall topMargin: Theme.paddingSmall
bottomMargin: Theme.paddingLarge bottomMargin: Theme.paddingLarge
} }
model: typeof attachments !== "undefined" ? attachments : Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
height: 100
} }
ContextMenu { ContextMenu {
id: mnu id: mnu
MenuItem { 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") text: typeof model.reblogged !== "undefined" && model.reblogged ? qsTr("Unboost") : qsTr("Boost")
onClicked: { onClicked: {
var status = typeof model.reblogged !== "undefined" && model.reblogged 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.reblogs_count = !status ? model.reblogs_count+1 : (model.reblogs_count > 0 ? model.reblogs_count-1 : model.reblogs_count);
model.reblogged = !model.reblogged model.reblogged = !model.reblogged
} }
Image { Image {
id: icRT id: icRT
source: "image://theme/icon-s-retweet?" + (!model.reblogged ? Theme.highlightColor : Theme.primaryColor)
width: Theme.iconSizeExtraSmall
height: width
anchors { anchors {
leftMargin: Theme.horizontalPageMargin leftMargin: Theme.horizontalPageMargin
left: parent.left left: parent.left
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
width: Theme.iconSizeExtraSmall
height: width
source: "image://theme/icon-s-retweet?" + (!model.reblogged ? Theme.highlightColor : Theme.primaryColor)
} }
Label { Label {
text: reblogs_count
font.pixelSize: Theme.fontSizeExtraSmall
color: !model.reblogged ? Theme.highlightColor : Theme.primaryColor
anchors { anchors {
left: icRT.right left: icRT.right
leftMargin: Theme.paddingMedium leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
text: reblogs_count
font.pixelSize: Theme.fontSizeExtraSmall
color: !model.reblogged ? Theme.highlightColor : Theme.primaryColor
} }
} }
MenuItem { MenuItem {
enabled: model.type !== "follow" id: mnuFavourite
visible: model.type !== "follow"
text: typeof model.favourited !== "undefined" && model.favourited ? qsTr("Unfavorite") : qsTr("Favorite") text: typeof model.favourited !== "undefined" && model.favourited ? qsTr("Unfavorite") : qsTr("Favorite")
onClicked: { onClicked: {
var status = typeof model.favourited !== "undefined" && model.favourited 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.favourites_count = !status ? model.favourites_count+1 : (model.favourites_count > 0 ? model.favourites_count-1 : model.favourites_count);
model.favourited = !model.favourited model.favourited = !model.favourited
} }
Image { Image {
id: icFA id: icFA
anchors { anchors {
@ -256,28 +330,54 @@ BackgroundItem {
height: width height: width
source: "image://theme/icon-s-favorite?" + (!model.favourited ? Theme.highlightColor : Theme.primaryColor) source: "image://theme/icon-s-favorite?" + (!model.favourited ? Theme.highlightColor : Theme.primaryColor)
} }
Label { Label {
text: favourites_count
font.pixelSize: Theme.fontSizeExtraSmall
color: !model.favourited ? Theme.highlightColor : Theme.primaryColor
anchors { anchors {
left: icFA.right left: icFA.right
leftMargin: Theme.paddingMedium leftMargin: Theme.paddingMedium
verticalCenter: parent.verticalCenter 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: { onClicked: {
var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
if (typeof mdl !== "undefined") if (typeof mdl !== "undefined")
m.append(mdl.get(index)) m.append(mdl.get(index))
pageStack.push(Qt.resolvedUrl("../Conversation.qml"), { pageStack.push(Qt.resolvedUrl("../ConversationPage.qml"), {
headerTitle: "Conversation",
toot_id: status_id, toot_id: status_id,
toot_url: status_url,
toot_uri: status_uri,
title: account_display_name, title: account_display_name,
description: '@'+account_acct, description: '@'+account_acct,
avatar: account_avatar, avatar: account_avatar,

View file

@ -17,7 +17,7 @@ class Notifications : public QObject
{ {
Q_OBJECT Q_OBJECT
public: 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); Q_INVOKABLE void notify(QString appName, QString summary, QString body, bool preview, QString ts, QString issuekey);
}; };

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Konversation</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Löschen</translation> <translation>Löschen</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation>Was gibt&apos;s Neues?</translation> <translation>Was gibt&apos;s Neues?</translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Fehler beim Laden</translation> <translation>Ladefehler</translation>
</message> </message>
</context> </context>
<context> <context>

View file

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

View file

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

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -62,6 +58,14 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Conversation</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Supprimer</translation> <translation>Supprimer</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation>Qu&apos;avez-vous en tête?</translation> <translation>Qu&apos;avez-vous en tête?</translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Erreur de chargement</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

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

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Gesprek</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Verwijderen</translation> <translation>Verwijderen</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Fout bij laden</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Gesprek</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Verwijderen</translation> <translation>Verwijderen</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Fout bij laden</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Discutida</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Escafar</translation> <translation>Escafar</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Error en cargar</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Konwersacja</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Usuń</translation> <translation>Usuń</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Błąd ładowania</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

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

View file

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

View file

@ -22,10 +22,6 @@
</context> </context>
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message>
<source>Conversation</source>
<translation>Konversation</translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation>Radera</translation> <translation>Radera</translation>
@ -62,12 +58,20 @@
<source>What&apos;s on your mind?</source> <source>What&apos;s on your mind?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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>
<context> <context>
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation>Problem att ladda</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

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

View file

@ -23,25 +23,21 @@
<context> <context>
<name>Conversation</name> <name>Conversation</name>
<message> <message>
<source>Conversation</source> <source>Copy Link to Clipboard</source>
<translation>Conversation</translation> <translation type="unfinished"></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>
</message> </message>
<message> <message>
<source>Write your warning here</source> <source>Write your warning here</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </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> <message>
<source>Public</source> <source>Public</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -59,7 +55,18 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<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> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -67,7 +74,7 @@
<name>ImageFullScreen</name> <name>ImageFullScreen</name>
<message> <message>
<source>Error loading</source> <source>Error loading</source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>