ui-improvements

- open profile picture
- improved media viewer
- improved user suggestion
- better responsive UI design
- code refactoring
- updated settings page
This commit is contained in:
molan-git 2020-06-03 07:34:33 +02:00
parent fd2f317f25
commit 16e211ddb9
23 changed files with 525 additions and 370 deletions

View file

@ -57,6 +57,8 @@ DISTFILES += qml/harbour-tooter.qml \
qml/pages/ProfilePage.qml \ qml/pages/ProfilePage.qml \
qml/pages/SettingsPage.qml \ qml/pages/SettingsPage.qml \
qml/pages/components/InfoBanner.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 \
@ -66,7 +68,6 @@ 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 \

View file

@ -57,7 +57,6 @@ CoverBackground {
horizontalAlignment: Image.AlignLeft horizontalAlignment: Image.AlignLeft
verticalAlignment: Image.AlignBottom verticalAlignment: Image.AlignBottom
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
source: "../images/tooter.svg" source: "../images/tooter.svg"
} }
Timer { Timer {
@ -78,6 +77,7 @@ CoverBackground {
} }
source: "image://theme/icon-s-alarm?" + Theme.highlightColor source: "image://theme/icon-s-alarm?" + Theme.highlightColor
} }
Label { Label {
id: notificationsLbl id: notificationsLbl
anchors { anchors {
@ -112,8 +112,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()
} }
} }
} }

View file

@ -47,7 +47,7 @@ ApplicationWindow {
Logic.conf['notificationLastID'] = 0 Logic.conf['notificationLastID'] = 0
if (Logic.conf['instance']) { if (Logic.conf['instance']) {
Logic.api = new Logic.MastodonAPI({ Logic.api = Logic.mastodonAPI({
"instance": Logic.conf['instance'], "instance": Logic.conf['instance'],
"api_user_token": "" "api_user_token": ""
}) })

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) {
@ -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){
@ -91,7 +91,7 @@ WorkerScript.onMessage = function(msg) {
addDataToModel (msg.model, "append", items); addDataToModel (msg.model, "append", items);
items = []; items = [];
} else if (data[i].hasOwnProperty("content")){ } else if (data[i].hasOwnProperty("content")){
//console.log("Is toot... parsing...") //console.log("Is toot... parsing...")
item = parseToot(data[i]); item = parseToot(data[i]);
item['id'] = item['status_id'] item['id'] = item['status_id']
@ -298,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

@ -43,10 +43,6 @@ Page {
} }
} }
InfoBanner {
id: sentBanner
}
ListModel { ListModel {
id: mediaModel id: mediaModel
onCountChanged: { onCountChanged: {
@ -73,12 +69,14 @@ Page {
title: headerTitle // pageTitle pushed from MainPage.qml or VisualContainer.qml 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 {
property: 'section' property: 'section'
@ -100,12 +98,7 @@ Page {
} }
PullDownMenu { PullDownMenu {
visible: type == "reply" && toot_url != "" visible: type === "reply" && toot_url !== ""
/* MenuItem {
text: qsTr("Open in Browser")
onClicked: Qt.openUrlExternally(toot_url);
} */
// ! url isn't always fetched. Needs a solution.
MenuItem { MenuItem {
text: qsTr("Copy Link to Clipboard") text: qsTr("Copy Link to Clipboard")
onClicked: Clipboard.text = toot_url; onClicked: Clipboard.text = toot_url;
@ -121,16 +114,17 @@ Page {
anchors.right: panel.right anchors.right: panel.right
anchors.top: parent.top anchors.top: parent.top
height: implicitHeight height: implicitHeight
//height: suggestedModel.count > 6 ? Theme.itemSizeMedium * 6 : Theme.itemSizeMedium * suggestedModel.count
color: Theme.highlightDimmerColor color: Theme.highlightDimmerColor
SilicaListView { SilicaListView {
rotation: 180
anchors.fill: parent anchors.fill: parent
model: suggestedModel model: suggestedModel
clip: true clip: true
quickScroll: false quickScroll: false
VerticalScrollDecorator {} 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) {
@ -149,24 +143,20 @@ 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
@ -260,8 +250,12 @@ Page {
IconButton { IconButton {
id: btnSmileys id: btnSmileys
property string selection property string selection
onSelectionChanged: { opacity: 0.7
console.log(selection) icon {
color: Theme.highlightColor
width: Theme.iconSizeSmallPlus
fillMode: Image.PreserveAspectFit
source: "../../qml/images/emojiselect.svg"
} }
anchors { anchors {
top: warningContent.bottom top: warningContent.bottom
@ -269,8 +263,9 @@ Page {
right: parent.right right: parent.right
rightMargin: Theme.paddingSmall rightMargin: Theme.paddingSmall
} }
opacity: 0.6 onSelectionChanged: {
icon.source: "../../qml/images/emojiselect.svg" console.log(selection)
}
onClicked: pageStack.push(emojiSelect) onClicked: pageStack.push(emojiSelect)
} }
@ -501,12 +496,12 @@ Page {
} }
BackgroundItem { BackgroundItem {
id: showPanel id: hiddenPanel
visible: !panel.open visible: !panel.open
height: Theme.paddingMedium height: Theme.paddingLarge * 0.5
width: parent.width width: parent.width
opacity: enabled ? 1.0 : 0.0 opacity: enabled ? 0.6 : 0.0
Behavior on opacity { FadeAnimator {} } Behavior on opacity { FadeAnimator { duration: 400 } }
anchors { anchors {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
bottom: parent.bottom bottom: parent.bottom
@ -518,8 +513,18 @@ Page {
} }
Rectangle { Rectangle {
id: hiddenPanelBackground
width: parent.width width: parent.width
height: progressBarShowPanel.height height: parent.height
color: Theme.highlightBackgroundColor
opacity: 0.4
anchors.fill: parent
}
Rectangle {
id: progressBarBackground
width: parent.width
height: progressBarHiddenPanel.height
color: Theme.highlightBackgroundColor color: Theme.highlightBackgroundColor
opacity: 0.2 opacity: 0.2
anchors { anchors {
@ -530,19 +535,7 @@ Page {
} }
Rectangle { Rectangle {
color: Theme.highlightBackgroundColor id: progressBarHiddenPanel
opacity: 0.2
height: showPanel.height
width: showPanel.width
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
bottom: parent.bottom
}
}
Rectangle {
id: progressBarShowPanel
width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0 width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0
height: Theme.itemSizeSmall * 0.05 height: Theme.itemSizeSmall * 0.05
color: Theme.highlightBackgroundColor color: Theme.highlightBackgroundColor
@ -559,4 +552,8 @@ Page {
id: emojiSelect id: emojiSelect
} }
InfoBanner {
id: sentBanner
}
} }

View file

@ -6,6 +6,7 @@ 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
@ -39,6 +40,7 @@ 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")
@ -49,6 +51,7 @@ 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")
@ -59,6 +62,7 @@ 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")
@ -68,6 +72,7 @@ Page {
height: parent.itemHeight height: parent.itemHeight
onOpenDrawer: infoPanel.open = setDrawer onOpenDrawer: infoPanel.open = setDrawer
} }
Item { Item {
id: tlSearch; id: tlSearch;
width: parent.itemWidth width: parent.itemWidth
@ -84,6 +89,7 @@ Page {
id: loader id: loader
anchors.fill: parent anchors.fill: parent
} }
Column { Column {
id: headerContainer id: headerContainer
width: tlSearch.width width: tlSearch.width
@ -103,6 +109,7 @@ Page {
} }
} }
} }
Component { Component {
id: loading id: loading
BusyIndicator { BusyIndicator {
@ -111,6 +118,7 @@ Page {
running: true running: true
} }
} }
Component { Component {
id: tagListComponent id: tagListComponent
MyList { MyList {
@ -135,6 +143,7 @@ Page {
} }
} }
} }
Component { Component {
id: userListComponent id: userListComponent
MyList { MyList {
@ -172,9 +181,7 @@ Page {
} }
} }
} }
} }
} }
SlideshowView { SlideshowView {
@ -187,12 +194,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
} }
@ -209,11 +213,9 @@ Page {
icon.source: "image://theme/icon-l-add" icon.source: "image://theme/icon-l-add"
anchors { anchors {
right: (mainPage.isPortrait ? parent.right : infoPanel.left) right: (mainPage.isPortrait ? parent.right : infoPanel.left)
rightMargin: Theme.paddingLarge
bottom: (mainPage.isPortrait ? infoPanel.top : parent.bottom) bottom: (mainPage.isPortrait ? infoPanel.top : parent.bottom)
margins: { bottomMargin: Theme.paddingLarge
left: Theme.paddingLarge
bottom: Theme.paddingLarge
}
} }
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), { pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), {
@ -242,6 +244,7 @@ Page {
Qt.openUrlExternally(href); Qt.openUrlExternally(href);
} }
} }
Component.onCompleted: { Component.onCompleted: {
console.log("aaa") console.log("aaa")
} }

View file

@ -7,6 +7,7 @@ import QtGraphicalEffects 1.0
Page { Page {
id: profilePage id: profilePage
property ListModel tweets property ListModel tweets
property string display_name: "" property string display_name: ""
property string username: "" property string username: ""
@ -141,27 +142,28 @@ Page {
image: profileImage image: profileImage
bg: profileBackground bg: profileBackground
} }
anchors {
top: parent.top
bottom: expander.top
left: parent.left
right: parent.right
}
clip: true clip: true
mdl: ListModel {} mdl: ListModel {}
type: "accounts/"+user_id+"/statuses" type: "accounts/"+user_id+"/statuses"
vars: {} vars: {}
conf: Logic.conf conf: Logic.conf
anchors {
top: parent.top
bottom: profileExpander.top
left: parent.left
right: parent.right
}
} }
// ProfilePage ExpandingSection // ProfilePage ExpandingSection
ExpandingSectionGroup { ExpandingSectionGroup {
id: expander id: profileExpander
anchors { anchors {
bottom: parent.bottom bottom: parent.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
ExpandingSection { ExpandingSection {
id: expandingSection1 id: expandingSection1
title: qsTr("About") title: qsTr("About")
@ -172,22 +174,23 @@ Page {
Rectangle { Rectangle {
id: txtContainer id: txtContainer
width: expander.width width: parent.width
height: Math.min(txtNote.height, parent.height*0.488) height: Math.min(txtNote.height, parent.height*0.488)
color: "transparent" color: "transparent"
visible: { visible: {
if ((note.text === "") && (note.text === "<p></p>") ) { if ((note.text === "") || (note.text === "<p></p>") ) {
false false
} else { } else {
true true
} }
} }
SilicaListView { SilicaListView {
id: txtFlickable id: txtFlickable
anchors.fill: txtContainer anchors.fill: parent
clip: true clip: true
quickScroll: false quickScroll: false
VerticalScrollDecorator { flickable: txtNote } VerticalScrollDecorator {}
Text { Text {
id: txtNote id: txtNote
@ -228,6 +231,7 @@ Page {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.leftMargin: Theme.paddingLarge anchors.leftMargin: Theme.paddingLarge
anchors.rightMargin: Theme.paddingLarge anchors.rightMargin: Theme.paddingLarge
Text { Text {
id: txtFollowers id: txtFollowers
visible: followers_count ? true : false visible: followers_count ? true : false
@ -236,6 +240,7 @@ Page {
color: Theme.highlightColor color: Theme.highlightColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
} }
Text { Text {
id: txtFollowing id: txtFollowing
visible: following_count ? true : false visible: following_count ? true : false
@ -244,6 +249,7 @@ Page {
color: Theme.highlightColor color: Theme.highlightColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
} }
Text { Text {
id: txtStatuses id: txtStatuses
visible: statuses_count ? true : false visible: statuses_count ? true : false
@ -252,6 +258,7 @@ Page {
color: Theme.highlightColor color: Theme.highlightColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
} }
/*Text { /*Text {
id: txtFavourites id: txtFavourites
visible: favourites_count ? true : false visible: favourites_count ? true : false
@ -304,11 +311,12 @@ Page {
// to-do: create notification banner "Follow request sent!" // to-do: create notification banner "Follow request sent!"
} }
} }
Button { Button {
id: btnMute id: btnMute
preferredWidth: Theme.buttonWidthSmall preferredWidth: Theme.buttonWidthSmall
text: (muting ? qsTr("Unmute") : qsTr("Mute")) text: (muting ? qsTr("Unmute") : qsTr("Mute"))
color: (muting ? highlightColor : palette.primaryColor) color: (muting ? palette.errorColor : palette.primaryColor)
onClicked: { onClicked: {
var msg = { var msg = {
'method' : 'POST', 'method' : 'POST',
@ -319,6 +327,7 @@ Page {
worker.sendMessage(msg); worker.sendMessage(msg);
} }
} }
Button { Button {
id: btnBlock id: btnBlock
preferredWidth: Theme.buttonWidthSmall preferredWidth: Theme.buttonWidthSmall

View file

@ -5,81 +5,137 @@ import "../lib/API.js" as Logic
Page { Page {
id: settingsPage 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: "Options"}
IconTextSwitch {
text: qsTr("Load Images in Toots")
description: qsTr("Disable this option if you want to preserve your data connection")
icon.source: "image://theme/icon-m-image"
enabled: true
checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages']
onClicked: {
Logic.conf['loadImages'] = checked
}
}
IconTextSwitch {
text: qsTr("Use smaller Font Size in Toots")
description: qsTr("Enable this option if you prefer to use a smaller font size in displayed Toots")
icon.source: "image://theme/icon-m-font-size"
enabled: false
//checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages']
//onClicked: {
// Logic.conf['loadImages'] = checked
//}
}
SectionHeader { text: "Account"}
Item {
id: removeAccount
width: parent.width width: parent.width
height: txtRemoveAccount.height + btnRemoveAccount.height + Theme.paddingLarge
IconTextSwitch { anchors {
id: removeAccount left: parent.left
text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account") leftMargin: Theme.paddingLarge
description: Logic.conf['login'] ? qsTr("Deauthorize this app and remove your account") : qsTr("Authorize this app to access your Mastodon account") right: parent.right
icon.source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add" rightMargin: Theme.paddingLarge
onCheckedChanged: {
remorsePopup.execute(removeAccount.text, function() {
busy = true;
checked = false;
timer1.start();
if (Logic.conf['login']) {
Logic.conf['login'] = false
Logic.conf['instance'] = null;
Logic.conf['api_user_token'] = null;
}
pageStack.push(Qt.resolvedUrl("LoginPage.qml"))
})
}
/* busy = true;
checked = false;
timer1.start()
}*/
Timer {
id: timer1
interval: 4700
onTriggered: parent.busy = false
}
} }
IconTextSwitch { Icon {
//enabled: false id: icnRemoveAccount
checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages'] color: Theme.secondaryColor
text: qsTr("Load images in toots") width: Theme.iconSizeMedium
description: qsTr("Disable this option if you want to preserve your data connection") fillMode: Image.PreserveAspectFit
icon.source: "image://theme/icon-m-image" source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add"
onClicked: { anchors.right: parent.right
Logic.conf['loadImages'] = checked
}
} }
IconTextSwitch { Column {
text: qsTr("Translate") id: clnRemoveAccount
description: qsTr("Use Transifex to help with app translation to your language") spacing: Theme.paddingMedium
icon.source: "image://theme/icon-m-font-size" anchors {
onCheckedChanged: { left: parent.left
busy = true; right: icnRemoveAccount.left
checked = false;
Qt.openUrlExternally("https://www.transifex.com/dysko/tooter/");
timer2.start()
} }
Timer {
id: timer2 Button {
interval: 4700 id: btnRemoveAccount
onTriggered: parent.busy = false text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account")
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
remorsePopup.execute(btnRemoveAccount.text, function() {
if (Logic.conf['login']) {
Logic.conf['login'] = false
Logic.conf['instance'] = null;
Logic.conf['api_user_token'] = null;
}
pageStack.push(Qt.resolvedUrl("LoginPage.qml"))
})
}
Timer {
id: timer1
interval: 4700
onTriggered: parent.busy = false
}
}
Label {
id: txtRemoveAccount
text: Logic.conf['login'] ? qsTr("Deauthorize this app from using your account and remove account data from phone") : qsTr("Authorize this app to access your Mastodon account")
font.pixelSize: Theme.fontSizeExtraSmall
wrapMode: Text.Wrap
color: Theme.secondaryColor
anchors {
left: parent.left
leftMargin: Theme.paddingLarge * 1.9
right: parent.right
rightMargin: Theme.paddingLarge * 1.2
}
} }
} }
} }
/* SectionHeader { text: "Support"}
IconTextSwitch {
text: qsTr("Translate")
description: qsTr("Use Transifex to help with app translation to your language")
icon.source: "image://theme/icon-m-font-size"
onCheckedChanged: {
busy = true;
checked = false;
Qt.openUrlExternally("https://www.transifex.com/dysko/tooter/");
timer2.start()
}
Timer {
id: timer2
interval: 4700
onTriggered: parent.busy = false
}
} */
SectionHeader { SectionHeader {
text: qsTr("Credits") text: qsTr("Credits")
} }
@ -89,52 +145,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: "molan@fosstodon.org" mastodon: "molan@fosstodon.org"
mail: "" 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")
@ -146,31 +211,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("ConversationPage.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
@ -183,9 +246,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

View file

@ -4,6 +4,7 @@ import Sailfish.Silica 1.0
Component { Component {
id: emojiComponent id: emojiComponent
Dialog { Dialog {
id: emoticonsDialog id: emoticonsDialog
canAccept: false //selector.currentIndex >= 0 canAccept: false //selector.currentIndex >= 0
@ -13,20 +14,17 @@ Component {
// acceptDestinationInstance.category = selector.value // acceptDestinationInstance.category = selector.value
} }
} }
SilicaGridView { SilicaGridView {
id: gridView id: gridView
anchors.fill: parent
//anchors.rightMargin: Theme.paddingLarge
//anchors.leftMargin: Theme.paddingLarge
cellWidth: gridView.width / 6
cellHeight: cellWidth
VerticalScrollDecorator {flickable: listEmojis }
header: PageHeader { header: PageHeader {
title: qsTr("Emojis") title: qsTr("Emojis")
description: qsTr("Tap to insert") description: qsTr("Tap to insert")
} }
cellWidth: gridView.width / 6
cellHeight: cellWidth
anchors.fill: parent
model: ListModel { model: ListModel {
id: listEmojis
ListElement { section: "smileys"; glyph: "😁" } ListElement { section: "smileys"; glyph: "😁" }
ListElement { section: "smileys"; glyph: "😂" } ListElement { section: "smileys"; glyph: "😂" }
ListElement { section: "smileys"; glyph: "😃" } ListElement { section: "smileys"; glyph: "😃" }
@ -142,11 +140,12 @@ Component {
delegate: BackgroundItem { delegate: BackgroundItem {
width: gridView.cellWidth width: gridView.cellWidth
height: gridView.cellHeight height: gridView.cellHeight
Label { Label {
anchors.centerIn: parent
color: (highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
font.pixelSize: Theme.fontSizeLarge
text: glyph text: glyph
font.pixelSize: Theme.fontSizeLarge
color: (highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
anchors.centerIn: parent
} }
onClicked: { onClicked: {
var cursorPosition = toot.cursorPosition var cursorPosition = toot.cursorPosition
@ -158,6 +157,8 @@ Component {
emoticonsDialog.accept() emoticonsDialog.accept()
} }
} }
VerticalScrollDecorator {flickable: listEmojis }
} }
} }

View file

@ -4,28 +4,24 @@ import Sailfish.Silica 1.0
DockedPanel { DockedPanel {
id: root id: root
z: 100 dock: Dock.Top
width: parent.width width: parent.width
height: content.height height: content.height
dock: Dock.Top
Rectangle { Rectangle {
id: content id: content
width: root.width
height: infoLabel.height + 5*Theme.paddingMedium
//anchors.topMargin: 20
color: Theme.highlightBackgroundColor color: Theme.highlightBackgroundColor
opacity: 1.0 width: root.width
height: infoLabel.height + 3*Theme.paddingMedium
Label { Label {
id: infoLabel id: infoLabel
text : "" text : ""
color: Theme.primaryColor
font.family: Theme.fontFamilyHeading font.family: Theme.fontFamilyHeading
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
//font.weight: Font.Bold color: Theme.highlightColor
width: parent.width
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
width: parent.width
anchors { anchors {
left: parent.left left: parent.left
leftMargin: Theme.horizontalPageMargin*2 leftMargin: Theme.horizontalPageMargin*2
@ -34,6 +30,7 @@ DockedPanel {
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {

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,6 +33,7 @@ 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("./../ProfilePage.qml"), { onClicked: pageStack.push(Qt.resolvedUrl("./../ProfilePage.qml"), {

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: {
@ -92,6 +94,7 @@ Item {
} }
} }
} }
MyImage { MyImage {
id: placeholder2 id: placeholder2
width: 2 width: 2
@ -110,6 +113,7 @@ Item {
} }
} }
} }
MyImage { MyImage {
id: placeholder3 id: placeholder3
width: 2 width: 2
@ -128,6 +132,7 @@ Item {
} }
} }
} }
MyImage { MyImage {
id: placeholder4 id: placeholder4
width: 2 width: 2

View file

@ -4,12 +4,13 @@ import QtMultimedia 5.0
FullscreenContentPage { FullscreenContentPage {
id: mediaPage
allowedOrientations: Orientation.All
property string type: "" property string type: ""
property string previewURL: "" property string previewURL: ""
property string mediaURL: "" property string mediaURL: ""
id: imagePage
allowedOrientations: Orientation.All
Component.onCompleted: function(){ Component.onCompleted: function(){
console.log(type) console.log(type)
console.log(previewURL) console.log(previewURL)
@ -29,8 +30,6 @@ FullscreenContentPage {
id: videoFlickable id: videoFlickable
visible: false visible: false
anchors.fill: parent anchors.fill: parent
contentWidth: imageContainer.width
contentHeight: imageContainer.height
clip: true clip: true
Image { Image {
@ -57,7 +56,6 @@ FullscreenContentPage {
return; return;
} }
} }
onPlaybackStateChanged: { onPlaybackStateChanged: {
console.log(playbackState) console.log(playbackState)
switch (playbackState){ switch (playbackState){
@ -72,7 +70,6 @@ FullscreenContentPage {
return; return;
} }
} }
onPositionChanged: function(){ onPositionChanged: function(){
//console.log(duration) //console.log(duration)
//console.log(bufferProgress) //console.log(bufferProgress)
@ -84,17 +81,18 @@ FullscreenContentPage {
playerProgress.value = position playerProgress.value = position
} }
} }
onStopped: function(){ onStopped: function(){
stop() stop()
} }
IconButton { IconButton {
id: playerIcon id: playerIcon
anchors.left: parent.left anchors {
anchors.bottom: parent.bottom left: parent.left
anchors.leftMargin: Theme.paddingLarge bottom: parent.bottom
anchors.bottomMargin: Theme.paddingLarge*1.5 leftMargin: Theme.horizontalPageMargin
bottomMargin: Theme.horizontalPageMargin
}
icon.source: "image://theme/icon-m-play" icon.source: "image://theme/icon-m-play"
onClicked: function() { onClicked: function() {
if (video.playbackState === MediaPlayer.PlayingState) if (video.playbackState === MediaPlayer.PlayingState)
@ -105,56 +103,47 @@ FullscreenContentPage {
} }
ProgressBar { ProgressBar {
indeterminate: true
id: playerProgress id: playerProgress
anchors.left: playerIcon.right indeterminate: true
anchors.right: videoDlBtn.left width: 400
anchors.verticalCenter: playerIcon.verticalCenter anchors {
anchors.leftMargin: 0 verticalCenter: playerIcon.verticalCenter
anchors.bottomMargin: Theme.paddingLarge*1.5 left: playerIcon.right
} right: parent.right
rightMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium
IconButton { bottomMargin: Theme.horizontalPageMargin
id: videoDlBtn
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: Theme.paddingLarge
anchors.bottomMargin: Theme.paddingLarge*1.5
icon.source: "image://theme/icon-m-cloud-download"
onClicked: {
var filename = mediaURL.split("/");
FileDownloader.downloadFile(mediaURL, filename[filename.length-1]);
} }
}
Rectangle { Rectangle {
visible: videoError.text != "" visible: videoError.text != ""
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
color: Theme.highlightDimmerColor color: Theme.highlightDimmerColor
height: videoError.height + 2*Theme.paddingMedium height: videoError.height + 2*Theme.paddingMedium
width: parent.width width: parent.width
Label {
anchors.centerIn: parent Label {
id: videoError id: videoError
width: parent.width - 2*Theme.paddingMedium visible: false
wrapMode: Text.Wrap text: video.errorString
height: contentHeight font.pixelSize: Theme.fontSizeSmall
visible: false; color: Theme.highlightColor
font.pixelSize: Theme.fontSizeSmall; wrapMode: Text.Wrap
text: video.errorString width: parent.width - 2*Theme.paddingMedium
color: Theme.highlightColor height: contentHeight
anchors.centerIn: parent
}
} }
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: function() { onClicked: function() {
if (video.playbackState === MediaPlayer.PlayingState) if (video.playbackState === MediaPlayer.PlayingState)
video.pause() video.pause()
else else
video.play() video.play()
}
} }
} }
} }
@ -163,11 +152,12 @@ FullscreenContentPage {
Flickable { Flickable {
id: imageFlickable id: imageFlickable
visible: false visible: false
anchors.fill: parent contentWidth: imageContainer.width; contentHeight: imageContainer.height
contentWidth: imageContainer.width
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
@ -176,18 +166,21 @@ FullscreenContentPage {
Image { Image {
id: imagePreview id: imagePreview
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: 2000; sourceSize.width: mediaPage.width
smooth: true // might slower performance smooth: false
anchors.centerIn: parent
onStatusChanged: { onStatusChanged: {
if (status == Image.Ready) { if (status == Image.Ready) {
fitToScreen() fitToScreen()
@ -195,15 +188,6 @@ FullscreenContentPage {
} }
} }
NumberAnimation {
id: loadedAnimation
target: imagePreview
property: "opacity"
duration: 250
from: 0; to: 1
easing.type: Easing.InOutQuad
}
onScaleChanged: { onScaleChanged: {
if ((width * scale) > imageFlickable.width) { if ((width * scale) > imageFlickable.width) {
var xoff = (imageFlickable.width / 2 + imageFlickable.contentX) * scale / prevScale; var xoff = (imageFlickable.width / 2 + imageFlickable.contentX) * scale / prevScale;
@ -215,19 +199,30 @@ FullscreenContentPage {
} }
prevScale = scale prevScale = scale
} }
NumberAnimation {
id: loadedAnimation
target: imagePreview
property: "opacity"
duration: 250
from: 0; to: 1
easing.type: Easing.InOutQuad
}
} }
} }
PinchArea { PinchArea {
id: pinchArea id: pinchArea
opacity: 0.3 opacity: 0.3
property real minScale: 1.0 property real minScale: 1.0
property real maxScale: 3.0 property real maxScale: 3.0
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()
@ -249,67 +244,74 @@ FullscreenContentPage {
from: imagePreview.scale from: imagePreview.scale
} }
} }
}
Loader { Loader {
anchors.centerIn: parent anchors.centerIn: parent
sourceComponent: { sourceComponent: {
switch (imagePreview.status) { switch (imagePreview.status) {
case Image.Loading: case Image.Loading:
return loadingIndicator return loadingIndicator
case Image.Error: case Image.Error:
return failedLoading return failedLoading
default: default:
return undefined return undefined
}
} }
}
Component { Component {
id: loadingIndicator id: loadingIndicator
Item {
width: mediaPage.width
height: childrenRect.height
Item { ProgressCircle {
height: childrenRect.height id: imageLoadingIndicator
width: imagePage.width progressValue: imagePreview.progress
progressColor: inAlternateCycle ? Theme.highlightColor : Theme.highlightDimmerColor
backgroundColor: inAlternateCycle ? Theme.highlightDimmerColor : Theme.highlightColor
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
ProgressCircle { Component {
id: imageLoadingIndicator id: failedLoading
progressColor: inAlternateCycle ? Theme.highlightColor : Theme.highlightDimmerColor Text {
backgroundColor: inAlternateCycle ? Theme.highlightDimmerColor : Theme.highlightColor text: qsTr("Error loading")
anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: Theme.fontSizeSmall;
progressValue: imagePreview.progress color: Theme.highlightColor
} }
} }
} }
}
Component { VerticalScrollDecorator { flickable: imageFlickable }
id: failedLoading
Text {
font.pixelSize: Theme.fontSizeSmall;
text: qsTr("Error loading")
color: Theme.highlightColor
}
} }
IconButton { IconButton {
y: Theme.paddingLarge id: dismissBtn
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
icon.source: "image://theme/icon-m-dismiss" icon.source: "image://theme/icon-m-dismiss"
anchors {
top: parent.top
topMargin: Theme.horizontalPageMargin
right: parent.right
rightMargin: Theme.horizontalPageMargin
}
onClicked: pageStack.pop() onClicked: pageStack.pop()
} }
IconButton { IconButton {
anchors.right: parent.right id: mediaDlBtn
anchors.bottom: parent.bottom anchors {
anchors.rightMargin: Theme.paddingLarge right: parent.right
anchors.bottomMargin: Theme.paddingLarge*1.5 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 }
} }

View file

@ -37,26 +37,24 @@ Item {
width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0 width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0
opacity: 0.8 opacity: 0.8
height: width height: width
source: "image://theme/icon-s-secure?" + (pressed source: "image://theme/icon-s-secure?" + (pressed ? Theme.highlightColor : Theme.primaryColor)
? Theme.highlightColor
: Theme.primaryColor)
} }
Label { Label {
id: lblScreenName id: lblScreenName
truncationMode: TruncationMode.Fade
text: '@'+account_username
font.pixelSize: Theme.fontSizeExtraSmall
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
anchors { anchors {
left: iconVerified.right left: iconVerified.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) 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)
@ -64,8 +62,8 @@ Item {
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

@ -9,6 +9,10 @@ Item {
width: parent.width width: parent.width
Image { Image {
id: icon id: icon
visible: type.length
width: Theme.iconSizeExtraSmall
height: width
source: typeof typeIcon !== "undefined" ? typeIcon : ""
anchors { anchors {
top: parent.top top: parent.top
topMargin: Theme.paddingMedium topMargin: Theme.paddingMedium
@ -16,12 +20,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
@ -48,7 +48,6 @@ Item {
} }
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

@ -5,33 +5,38 @@ import QtMultimedia 5.0
Item { Item {
id: myImage 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
@ -39,35 +44,48 @@ Item {
progressRec.width = 0; progressRec.width = 0;
} }
} }
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

@ -61,13 +61,7 @@ SilicaListView {
pageStack.push(Qt.resolvedUrl("../SettingsPage.qml"), {}) pageStack.push(Qt.resolvedUrl("../SettingsPage.qml"), {})
} }
} }
/* MenuItem {
text: qsTr("Open in Browser")
visible: profile_url != ""
onClicked: {
Clipboard.text = profile_url
}
} */
MenuItem { MenuItem {
text: qsTr("Load more") text: qsTr("Load more")
onClicked: { onClicked: {

View file

@ -4,13 +4,16 @@ import QtGraphicalEffects 1.0
SilicaGridView { SilicaGridView {
id: gridView
property bool isPortrait: false
signal slideshowShow(int vIndex) signal slideshowShow(int vIndex)
signal slideshowIndexChanged(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,15 +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 {
@ -66,88 +71,93 @@ 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 {
sourceItem: label sourceItem: label
offset: 0.5 offset: 0.5
} }
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 { font.family: Theme.fontFamilyHeading
pixelSize: Theme.fontSizeExtraSmall width: parent.width
family: Theme.fontFamilyHeading horizontalAlignment : Text.AlignHCenter
} anchors.bottom: parent.bottom
} }
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)
@ -156,9 +166,9 @@ SilicaGridView {
listModel.setProperty(i, 'active', false); listModel.setProperty(i, 'active', false);
} }
console.log(slug) console.log(slug)
} }
VerticalScrollDecorator {} VerticalScrollDecorator {}
} }

View file

@ -4,48 +4,69 @@ import Sailfish.Silica 1.0
Item { Item {
id: profileHeader id: profileHeader
property int value: 0 property int value: 0
property string title: "" property string title: ""
property string description: "" property string description: ""
property string image: "" property string image: ""
property string bg: "" property string bg: ""
width: parent.width width: parent.width
height: icon.height + Theme.paddingLarge*2 height: icon.height + Theme.paddingLarge*2
Rectangle { Rectangle {
id: bgImage id: bgImage
anchors.fill: parent
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 {
anchors.fill: bgImage
asynchronous: true asynchronous: true
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
source: bg source: bg
opacity: 0.8 opacity: 0.8
anchors.fill: parent
} }
} }
Image { Image {
id: icon id: icon
asynchronous: true
source:
if (icon.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 left: icon.right
@ -54,6 +75,7 @@ Item {
rightMargin: Theme.paddingLarge rightMargin: Theme.paddingLarge
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
Label { Label {
id: ttl id: ttl
text: text:
@ -61,23 +83,24 @@ Item {
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
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
} }
} }

View file

@ -0,0 +1,27 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
FullscreenContentPage {
id: profileImage
allowedOrientations: Orientation.All
property string image: ""
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

@ -26,6 +26,8 @@ BackgroundItem {
visible: type.length visible: type.length
anchors.left: lblName.left anchors.left: lblName.left
anchors.bottom: iconRT.bottom anchors.bottom: iconRT.bottom
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
text: { text: {
var action; var action;
switch(type){ switch(type){
@ -43,8 +45,6 @@ BackgroundItem {
} }
return '@' + retweetScreenName + ' ' + action return '@' + retweetScreenName + ' ' + action
} }
font.pixelSize: Theme.fontSizeExtraSmall
color: Theme.secondaryColor
} }
Image { Image {
@ -116,12 +116,12 @@ BackgroundItem {
} }
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) 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

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