From 16e211ddb971d6d4c5a1e09d1f4ed26bbe6e1175 Mon Sep 17 00:00:00 2001 From: molan-git Date: Wed, 3 Jun 2020 07:34:33 +0200 Subject: [PATCH] ui-improvements - open profile picture - improved media viewer - improved user suggestion - better responsive UI design - code refactoring - updated settings page --- harbour-tooter.pro | 3 +- qml/cover/CoverPage.qml | 9 +- qml/harbour-tooter.qml | 2 +- qml/lib/Mastodon.js | 4 +- qml/lib/Worker.js | 8 +- qml/pages/ConversationPage.qml | 89 ++++--- qml/pages/MainPage.qml | 21 +- qml/pages/ProfilePage.qml | 33 ++- qml/pages/SettingsPage.qml | 192 ++++++++++----- qml/pages/components/EmojiSelect.qml | 21 +- qml/pages/components/InfoBanner.qml | 15 +- qml/pages/components/ItemUser.qml | 6 +- qml/pages/components/MediaBlock.qml | 7 +- ...mageFullScreen.qml => MediaFullScreen.qml} | 230 +++++++++--------- qml/pages/components/MiniHeader.qml | 16 +- qml/pages/components/MiniStatus.qml | 11 +- qml/pages/components/MyImage.qml | 36 ++- qml/pages/components/MyList.qml | 8 +- qml/pages/components/Navigation.qml | 92 +++---- qml/pages/components/ProfileHeader.qml | 57 +++-- qml/pages/components/ProfileImage.qml | 27 ++ qml/pages/components/Toot.qml | 6 +- src/notifications.h | 2 +- 23 files changed, 525 insertions(+), 370 deletions(-) rename qml/pages/components/{ImageFullScreen.qml => MediaFullScreen.qml} (64%) create mode 100644 qml/pages/components/ProfileImage.qml diff --git a/harbour-tooter.pro b/harbour-tooter.pro index 5242229..a7c61ae 100644 --- a/harbour-tooter.pro +++ b/harbour-tooter.pro @@ -57,6 +57,8 @@ DISTFILES += qml/harbour-tooter.qml \ qml/pages/ProfilePage.qml \ qml/pages/SettingsPage.qml \ qml/pages/components/InfoBanner.qml \ + qml/pages/components/MediaFullScreen.qml \ + qml/pages/components/ProfileImage.qml \ qml/pages/components/VisualContainer.qml \ qml/pages/components/MiniStatus.qml \ qml/pages/components/MiniHeader.qml \ @@ -66,7 +68,6 @@ DISTFILES += qml/harbour-tooter.qml \ qml/pages/components/ProfileHeader.qml \ qml/pages/components/MediaBlock.qml \ qml/pages/components/MyImage.qml \ - qml/pages/components/ImageFullScreen.qml \ qml/cover/CoverPage.qml \ qml/pages/MainPage.qml \ qml/pages/LoginPage.qml \ diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml index 4080b51..63b9d01 100644 --- a/qml/cover/CoverPage.qml +++ b/qml/cover/CoverPage.qml @@ -57,7 +57,6 @@ CoverBackground { horizontalAlignment: Image.AlignLeft verticalAlignment: Image.AlignBottom fillMode: Image.PreserveAspectFit - source: "../images/tooter.svg" } Timer { @@ -78,6 +77,7 @@ CoverBackground { } source: "image://theme/icon-s-alarm?" + Theme.highlightColor } + Label { id: notificationsLbl anchors { @@ -112,8 +112,11 @@ CoverBackground { CoverAction { iconSource: "image://theme/icon-cover-new" onTriggered: { - pageStack.push(Qt.resolvedUrl("./../pages/Conversation.qml"), {}) - appWindow.activate(); + pageStack.push(Qt.resolvedUrl("./../pages/ConversationPage.qml"), { + headerTitle: qsTr("New Toot"), + type: "new" + }) + appWindow.activate() } } } diff --git a/qml/harbour-tooter.qml b/qml/harbour-tooter.qml index 60b34c8..b0f9abd 100644 --- a/qml/harbour-tooter.qml +++ b/qml/harbour-tooter.qml @@ -47,7 +47,7 @@ ApplicationWindow { Logic.conf['notificationLastID'] = 0 if (Logic.conf['instance']) { - Logic.api = new Logic.MastodonAPI({ + Logic.api = Logic.mastodonAPI({ "instance": Logic.conf['instance'], "api_user_token": "" }) diff --git a/qml/lib/Mastodon.js b/qml/lib/Mastodon.js index 03cfb17..55265be 100644 --- a/qml/lib/Mastodon.js +++ b/qml/lib/Mastodon.js @@ -3,7 +3,7 @@ // do whatever you want with it // but please don't hurt it (and keep this header) -var MastodonAPI = function(config) { +var mastodonAPI = function(config) { var apiBase = config.instance + "/api/v1/"; return { setConfig: function (key, value) { @@ -236,7 +236,7 @@ var MastodonAPI = function(config) { }; // node.js -if (typeof module !== 'undefined') { module.exports = MastodonAPI; }; +if (typeof module !== 'undefined') { module.exports = mastodonAPI; }; String.prototype.replaceAll = function(search, replacement) { var target = this; diff --git a/qml/lib/Worker.js b/qml/lib/Worker.js index 8b53e8c..19469c6 100644 --- a/qml/lib/Worker.js +++ b/qml/lib/Worker.js @@ -22,7 +22,7 @@ WorkerScript.onMessage = function(msg) { if (typeof msg.conf['loadImages'] !== "undefined") loadImages = msg.conf['loadImages'] - var API = MastodonAPI({ instance: msg.conf.instance, api_user_token: msg.conf.api_user_token}); + var API = mastodonAPI({ instance: msg.conf.instance, api_user_token: msg.conf.api_user_token}); if (msg.method === "POST"){ API.post(msg.action, msg.params, function(data) { if (msg.bgAction){ @@ -91,7 +91,7 @@ WorkerScript.onMessage = function(msg) { addDataToModel (msg.model, "append", items); items = []; - } else if (data[i].hasOwnProperty("content")){ + } else if (data[i].hasOwnProperty("content")){ //console.log("Is toot... parsing...") item = parseToot(data[i]); item['id'] = item['status_id'] @@ -298,13 +298,13 @@ function addEmojis(item, data){ var emoji, i; for (i = 0; i < data["emojis"].length; i++){ emoji = data["emojis"][i]; - item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "") + item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "") //console.log(JSON.stringify(data["emojis"][i])) } if (data["reblog"]) for (i = 0; i < data["reblog"]["emojis"].length; i++){ emoji = data["reblog"]["emojis"][i]; - item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "") + item['content'] = item['content'].replaceAll(":"+emoji.shortcode+":", "") } return item; diff --git a/qml/pages/ConversationPage.qml b/qml/pages/ConversationPage.qml index c39f9d3..611329f 100644 --- a/qml/pages/ConversationPage.qml +++ b/qml/pages/ConversationPage.qml @@ -43,10 +43,6 @@ Page { } } - InfoBanner { - id: sentBanner - } - ListModel { id: mediaModel onCountChanged: { @@ -73,12 +69,14 @@ Page { title: headerTitle // pageTitle pushed from MainPage.qml or VisualContainer.qml } clip: true - anchors { - top: parent.top - bottom: panel.top - left: parent.left - right: parent.right - } + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: if (panel.open == true) { + panel.top + } else { + hiddenPanel.top + } model: mdl section { property: 'section' @@ -100,12 +98,7 @@ Page { } PullDownMenu { - visible: type == "reply" && toot_url != "" - /* MenuItem { - text: qsTr("Open in Browser") - onClicked: Qt.openUrlExternally(toot_url); - } */ - // ! url isn't always fetched. Needs a solution. + visible: type === "reply" && toot_url !== "" MenuItem { text: qsTr("Copy Link to Clipboard") onClicked: Clipboard.text = toot_url; @@ -121,16 +114,17 @@ Page { anchors.right: panel.right anchors.top: parent.top height: implicitHeight - //height: suggestedModel.count > 6 ? Theme.itemSizeMedium * 6 : Theme.itemSizeMedium * suggestedModel.count color: Theme.highlightDimmerColor SilicaListView { + rotation: 180 anchors.fill: parent model: suggestedModel clip: true quickScroll: false VerticalScrollDecorator {} delegate: ItemUser { + rotation: 180 onClicked: { var start = toot.cursorPosition while (toot.text[start] !== "@" && start > 0) { @@ -149,24 +143,20 @@ Page { } } onCountChanged: { - positionViewAtIndex(suggestedModel.count - 1, ListView.End) + positionViewAtBeginning(suggestedModel.count - 1, ListView.Beginning) } } } DockedPanel { id: panel - open: true - //onExpandedChanged: { - // if (!expanded) { - // show() - // } - //} width: parent.width height: progressBar.height + toot.height + (mediaModel.count ? uploadedImages.height : 0) + btnContentWarning.height + Theme.paddingMedium + (warningContent.visible ? warningContent.height : 0) dock: Dock.Bottom + open: true + animationDuration: 200 Rectangle { width: parent.width @@ -260,8 +250,12 @@ Page { IconButton { id: btnSmileys property string selection - onSelectionChanged: { - console.log(selection) + opacity: 0.7 + icon { + color: Theme.highlightColor + width: Theme.iconSizeSmallPlus + fillMode: Image.PreserveAspectFit + source: "../../qml/images/emojiselect.svg" } anchors { top: warningContent.bottom @@ -269,8 +263,9 @@ Page { right: parent.right rightMargin: Theme.paddingSmall } - opacity: 0.6 - icon.source: "../../qml/images/emojiselect.svg" + onSelectionChanged: { + console.log(selection) + } onClicked: pageStack.push(emojiSelect) } @@ -501,12 +496,12 @@ Page { } BackgroundItem { - id: showPanel + id: hiddenPanel visible: !panel.open - height: Theme.paddingMedium + height: Theme.paddingLarge * 0.5 width: parent.width - opacity: enabled ? 1.0 : 0.0 - Behavior on opacity { FadeAnimator {} } + opacity: enabled ? 0.6 : 0.0 + Behavior on opacity { FadeAnimator { duration: 400 } } anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom @@ -518,8 +513,18 @@ Page { } Rectangle { + id: hiddenPanelBackground 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 opacity: 0.2 anchors { @@ -530,19 +535,7 @@ Page { } Rectangle { - color: Theme.highlightBackgroundColor - opacity: 0.2 - height: showPanel.height - width: showPanel.width - anchors { - horizontalCenter: parent.horizontalCenter - top: parent.top - bottom: parent.bottom - } - } - - Rectangle { - id: progressBarShowPanel + id: progressBarHiddenPanel width: toot.text.length ? panel.width * (toot.text.length / tootMaxChar) : 0 height: Theme.itemSizeSmall * 0.05 color: Theme.highlightBackgroundColor @@ -559,4 +552,8 @@ Page { id: emojiSelect } + InfoBanner { + id: sentBanner + } + } diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml index 9dcff9a..b254496 100644 --- a/qml/pages/MainPage.qml +++ b/qml/pages/MainPage.qml @@ -6,6 +6,7 @@ import "./components/" Page { id: mainPage + property bool isFirstPage: true property bool isTablet: true //Screen.sizeCategory >= Screen.Large @@ -39,6 +40,7 @@ Page { height: parent.itemHeight onOpenDrawer: infoPanel.open = setDrawer } + MyList{ id: tlNotifications; title: qsTr("Notifications") @@ -49,6 +51,7 @@ Page { height: parent.itemHeight onOpenDrawer: infoPanel.open = setDrawer } + MyList{ id: tlLocal; title: qsTr("Local") @@ -59,6 +62,7 @@ Page { height: parent.itemHeight onOpenDrawer: infoPanel.open = setDrawer } + MyList{ id: tlPublic; title: qsTr("Federated") @@ -68,6 +72,7 @@ Page { height: parent.itemHeight onOpenDrawer: infoPanel.open = setDrawer } + Item { id: tlSearch; width: parent.itemWidth @@ -84,6 +89,7 @@ Page { id: loader anchors.fill: parent } + Column { id: headerContainer width: tlSearch.width @@ -103,6 +109,7 @@ Page { } } } + Component { id: loading BusyIndicator { @@ -111,6 +118,7 @@ Page { running: true } } + Component { id: tagListComponent MyList { @@ -135,6 +143,7 @@ Page { } } } + Component { id: userListComponent MyList { @@ -172,9 +181,7 @@ Page { } } } - } - } SlideshowView { @@ -187,12 +194,9 @@ Page { onCurrentIndexChanged: { navigation.slideshowIndexChanged(currentIndex) } - anchors { fill: parent - leftMargin: 0 top: parent.top - topMargin: 0 rightMargin: mainPage.isPortrait ? 0 : infoPanel.visibleSize bottomMargin: mainPage.isPortrait ? infoPanel.visibleSize : 0 } @@ -209,11 +213,9 @@ Page { 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) - margins: { - left: Theme.paddingLarge - bottom: Theme.paddingLarge - } + bottomMargin: Theme.paddingLarge } onClicked: { pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), { @@ -242,6 +244,7 @@ Page { Qt.openUrlExternally(href); } } + Component.onCompleted: { console.log("aaa") } diff --git a/qml/pages/ProfilePage.qml b/qml/pages/ProfilePage.qml index 0247b72..a0316e4 100644 --- a/qml/pages/ProfilePage.qml +++ b/qml/pages/ProfilePage.qml @@ -7,6 +7,7 @@ import QtGraphicalEffects 1.0 Page { id: profilePage + property ListModel tweets property string display_name: "" property string username: "" @@ -141,27 +142,28 @@ Page { image: profileImage bg: profileBackground } - anchors { - top: parent.top - bottom: expander.top - left: parent.left - right: parent.right - } clip: true mdl: ListModel {} type: "accounts/"+user_id+"/statuses" vars: {} conf: Logic.conf + anchors { + top: parent.top + bottom: profileExpander.top + left: parent.left + right: parent.right + } } // ProfilePage ExpandingSection ExpandingSectionGroup { - id: expander + id: profileExpander anchors { bottom: parent.bottom left: parent.left right: parent.right } + ExpandingSection { id: expandingSection1 title: qsTr("About") @@ -172,22 +174,23 @@ Page { Rectangle { id: txtContainer - width: expander.width + width: parent.width height: Math.min(txtNote.height, parent.height*0.488) color: "transparent" visible: { - if ((note.text === "") && (note.text === "

") ) { + if ((note.text === "") || (note.text === "

") ) { false } else { true } } + SilicaListView { id: txtFlickable - anchors.fill: txtContainer + anchors.fill: parent clip: true quickScroll: false - VerticalScrollDecorator { flickable: txtNote } + VerticalScrollDecorator {} Text { id: txtNote @@ -228,6 +231,7 @@ Page { anchors.horizontalCenter: parent.horizontalCenter anchors.leftMargin: Theme.paddingLarge anchors.rightMargin: Theme.paddingLarge + Text { id: txtFollowers visible: followers_count ? true : false @@ -236,6 +240,7 @@ Page { color: Theme.highlightColor wrapMode: Text.Wrap } + Text { id: txtFollowing visible: following_count ? true : false @@ -244,6 +249,7 @@ Page { color: Theme.highlightColor wrapMode: Text.Wrap } + Text { id: txtStatuses visible: statuses_count ? true : false @@ -252,6 +258,7 @@ Page { color: Theme.highlightColor wrapMode: Text.Wrap } + /*Text { id: txtFavourites visible: favourites_count ? true : false @@ -304,11 +311,12 @@ Page { // to-do: create notification banner "Follow request sent!" } } + Button { id: btnMute preferredWidth: Theme.buttonWidthSmall text: (muting ? qsTr("Unmute") : qsTr("Mute")) - color: (muting ? highlightColor : palette.primaryColor) + color: (muting ? palette.errorColor : palette.primaryColor) onClicked: { var msg = { 'method' : 'POST', @@ -319,6 +327,7 @@ Page { worker.sendMessage(msg); } } + Button { id: btnBlock preferredWidth: Theme.buttonWidthSmall diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml index d844bff..cf13abd 100644 --- a/qml/pages/SettingsPage.qml +++ b/qml/pages/SettingsPage.qml @@ -5,81 +5,137 @@ import "../lib/API.js" as Logic Page { id: settingsPage + allowedOrientations: Orientation.All + SilicaFlickable { - anchors.fill: parent contentHeight: column.height + Theme.paddingLarge contentWidth: parent.width + anchors.fill: parent + RemorsePopup { id: remorsePopup } + VerticalScrollDecorator {} + Column { id: column - spacing: Theme.paddingSmall + spacing: Theme.paddingMedium width: parent.width + PageHeader { title: qsTr("Settings") } - Column { - // No spacing in this column + + SectionHeader { text: "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 - - IconTextSwitch { - id: removeAccount - text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account") - description: Logic.conf['login'] ? qsTr("Deauthorize this app and remove your account") : qsTr("Authorize this app to access your Mastodon account") - icon.source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add" - onCheckedChanged: { - remorsePopup.execute(removeAccount.text, function() { - busy = true; - checked = false; - timer1.start(); - if (Logic.conf['login']) { - Logic.conf['login'] = false - Logic.conf['instance'] = null; - Logic.conf['api_user_token'] = null; - } - pageStack.push(Qt.resolvedUrl("LoginPage.qml")) - }) - } - /* busy = true; - checked = false; - timer1.start() - }*/ - Timer { - id: timer1 - interval: 4700 - onTriggered: parent.busy = false - } + height: txtRemoveAccount.height + btnRemoveAccount.height + Theme.paddingLarge + anchors { + left: parent.left + leftMargin: Theme.paddingLarge + right: parent.right + rightMargin: Theme.paddingLarge } - IconTextSwitch { - //enabled: false - checked: typeof Logic.conf['loadImages'] !== "undefined" && Logic.conf['loadImages'] - text: qsTr("Load images in toots") - description: qsTr("Disable this option if you want to preserve your data connection") - icon.source: "image://theme/icon-m-image" - onClicked: { - Logic.conf['loadImages'] = checked - } + Icon { + id: icnRemoveAccount + color: Theme.secondaryColor + width: Theme.iconSizeMedium + fillMode: Image.PreserveAspectFit + source: Logic.conf['login'] ? "image://theme/icon-m-contact" : "image://theme/icon-m-add" + anchors.right: parent.right } - IconTextSwitch { - text: qsTr("Translate") - description: qsTr("Use Transifex to help with app translation to your language") - icon.source: "image://theme/icon-m-font-size" - onCheckedChanged: { - busy = true; - checked = false; - Qt.openUrlExternally("https://www.transifex.com/dysko/tooter/"); - timer2.start() + Column { + id: clnRemoveAccount + spacing: Theme.paddingMedium + anchors { + left: parent.left + right: icnRemoveAccount.left } - Timer { - id: timer2 - interval: 4700 - onTriggered: parent.busy = false + + Button { + id: btnRemoveAccount + text: Logic.conf['login'] ? qsTr("Remove Account") : qsTr("Add Account") + 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 { text: qsTr("Credits") } @@ -89,52 +145,61 @@ Page { anchors { left: parent.left right: parent.right - rightMargin: Theme.horizontalPageMargin + rightMargin: Theme.paddingLarge } + Repeater { model: ListModel { + ListElement { name: "Duško Angirević" desc: qsTr("UI/UX design and development") mastodon: "dysko@mastodon.social" mail: "" } + ListElement { name: "Miodrag Nikolić" desc: qsTr("Visual identity") mastodon: "" mail: "micotakis@gmail.com" } + ListElement { name: "Molan" desc: qsTr("Development and translations") mastodon: "molan@fosstodon.org" mail: "" } + ListElement { name: "Quentin PAGÈS / Quenti ♏" desc: qsTr("Occitan & French translation") mastodon: "Quenti@framapiaf.org" mail: "" } + ListElement { name: "Luchy Kon / dashinfantry" desc: qsTr("Chinese translation") mastodon: "" mail: "dashinfantry@gmail.com" } + ListElement { name: "André Koot" desc: qsTr("Dutch translation") mastodon: "meneer@mastodon.social" mail: "https://twitter.com/meneer" } + ListElement { name: "CarmenFdez" desc: qsTr("Spanish translation") mastodon: "" mail: "" } + ListElement { name: "Mohamed-Touhami MAHDI" desc: qsTr("Added README file") @@ -146,31 +211,29 @@ Page { Item { width: parent.width height: Theme.itemSizeMedium + IconButton { id: btn + icon.source: "image://theme/" + (model.mastodon !== "" ? "icon-m-outline-chat" : "icon-m-mail") + "?" + (pressed + ? Theme.highlightColor : Theme.primaryColor) anchors { verticalCenter: parent.verticalCenter right: parent.right } - icon.source: "image://theme/" + (model.mastodon !== "" ? "icon-m-contact" : "icon-m-mail") + "?" + (pressed - ? Theme.highlightColor - : Theme.primaryColor) onClicked: { if (model.mastodon !== ""){ var m = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); pageStack.push(Qt.resolvedUrl("ConversationPage.qml"), { - toot_id: 0, - title: model.name, + headerTitle: "Mention", description: '@'+model.mastodon, - avatar: "", - mdl: m, - type: "reply" + type: "new" }) } else { Qt.openUrlExternally("mailto:"+model.mail); } } } + Column { anchors { verticalCenter: parent.verticalCenter @@ -183,9 +246,10 @@ Page { Label { id: lblName text: model.name - color: Theme.secondaryColor + color: Theme.highlightColor font.pixelSize: Theme.fontSizeSmall } + Label { text: model.desc color: Theme.secondaryHighlightColor diff --git a/qml/pages/components/EmojiSelect.qml b/qml/pages/components/EmojiSelect.qml index ce8548e..3e4f8fa 100644 --- a/qml/pages/components/EmojiSelect.qml +++ b/qml/pages/components/EmojiSelect.qml @@ -4,6 +4,7 @@ import Sailfish.Silica 1.0 Component { id: emojiComponent + Dialog { id: emoticonsDialog canAccept: false //selector.currentIndex >= 0 @@ -13,20 +14,17 @@ Component { // acceptDestinationInstance.category = selector.value } } + SilicaGridView { id: gridView - anchors.fill: parent - //anchors.rightMargin: Theme.paddingLarge - //anchors.leftMargin: Theme.paddingLarge - cellWidth: gridView.width / 6 - cellHeight: cellWidth - VerticalScrollDecorator {flickable: listEmojis } header: PageHeader { title: qsTr("Emojis") description: qsTr("Tap to insert") } + cellWidth: gridView.width / 6 + cellHeight: cellWidth + anchors.fill: parent model: ListModel { - id: listEmojis ListElement { section: "smileys"; glyph: "😁" } ListElement { section: "smileys"; glyph: "😂" } ListElement { section: "smileys"; glyph: "😃" } @@ -142,11 +140,12 @@ Component { delegate: BackgroundItem { width: gridView.cellWidth height: gridView.cellHeight + Label { - anchors.centerIn: parent - color: (highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) - font.pixelSize: Theme.fontSizeLarge text: glyph + font.pixelSize: Theme.fontSizeLarge + color: (highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) + anchors.centerIn: parent } onClicked: { var cursorPosition = toot.cursorPosition @@ -158,6 +157,8 @@ Component { emoticonsDialog.accept() } } + + VerticalScrollDecorator {flickable: listEmojis } } } diff --git a/qml/pages/components/InfoBanner.qml b/qml/pages/components/InfoBanner.qml index 923face..a6a444e 100644 --- a/qml/pages/components/InfoBanner.qml +++ b/qml/pages/components/InfoBanner.qml @@ -4,28 +4,24 @@ import Sailfish.Silica 1.0 DockedPanel { id: root - z: 100 + dock: Dock.Top width: parent.width height: content.height - dock: Dock.Top Rectangle { id: content - width: root.width - height: infoLabel.height + 5*Theme.paddingMedium - //anchors.topMargin: 20 color: Theme.highlightBackgroundColor - opacity: 1.0 + width: root.width + height: infoLabel.height + 3*Theme.paddingMedium Label { id: infoLabel text : "" - color: Theme.primaryColor font.family: Theme.fontFamilyHeading font.pixelSize: Theme.fontSizeMedium - //font.weight: Font.Bold - width: parent.width + color: Theme.highlightColor wrapMode: Text.WrapAnywhere + width: parent.width anchors { left: parent.left leftMargin: Theme.horizontalPageMargin*2 @@ -34,6 +30,7 @@ DockedPanel { verticalCenter: parent.verticalCenter } } + MouseArea { anchors.fill: parent onClicked: { diff --git a/qml/pages/components/ItemUser.qml b/qml/pages/components/ItemUser.qml index 56e11b3..d1df686 100644 --- a/qml/pages/components/ItemUser.qml +++ b/qml/pages/components/ItemUser.qml @@ -4,9 +4,11 @@ import Sailfish.Silica 1.0 BackgroundItem { id: delegate + signal openUser (string notice) - height: Theme.itemSizeMedium + width: parent.width + height: Theme.itemSizeMedium Rectangle { id: avatar @@ -23,6 +25,7 @@ BackgroundItem { anchors.fill: parent source: model.account_avatar } + BusyIndicator { size: BusyIndicatorSize.Small opacity: img.status === Image.Ready ? 0.0 : 1.0 @@ -30,6 +33,7 @@ BackgroundItem { running: avatar.status !== Image.Ready; anchors.centerIn: parent } + MouseArea { anchors.fill: parent onClicked: pageStack.push(Qt.resolvedUrl("./../ProfilePage.qml"), { diff --git a/qml/pages/components/MediaBlock.qml b/qml/pages/components/MediaBlock.qml index 2a7717c..bf3c047 100644 --- a/qml/pages/components/MediaBlock.qml +++ b/qml/pages/components/MediaBlock.qml @@ -4,10 +4,12 @@ import QtMultimedia 5.0 Item { + id: holder + property ListModel model property double wRatio : 16/9 property double hRatio : 9/16 - id: holder + width: width height: height Component.onCompleted: { @@ -92,6 +94,7 @@ Item { } } } + MyImage { id: placeholder2 width: 2 @@ -110,6 +113,7 @@ Item { } } } + MyImage { id: placeholder3 width: 2 @@ -128,6 +132,7 @@ Item { } } } + MyImage { id: placeholder4 width: 2 diff --git a/qml/pages/components/ImageFullScreen.qml b/qml/pages/components/MediaFullScreen.qml similarity index 64% rename from qml/pages/components/ImageFullScreen.qml rename to qml/pages/components/MediaFullScreen.qml index f27da61..3378cac 100644 --- a/qml/pages/components/ImageFullScreen.qml +++ b/qml/pages/components/MediaFullScreen.qml @@ -4,12 +4,13 @@ import QtMultimedia 5.0 FullscreenContentPage { + id: mediaPage + allowedOrientations: Orientation.All + property string type: "" property string previewURL: "" property string mediaURL: "" - id: imagePage - allowedOrientations: Orientation.All Component.onCompleted: function(){ console.log(type) console.log(previewURL) @@ -29,8 +30,6 @@ FullscreenContentPage { id: videoFlickable visible: false anchors.fill: parent - contentWidth: imageContainer.width - contentHeight: imageContainer.height clip: true Image { @@ -57,7 +56,6 @@ FullscreenContentPage { return; } } - onPlaybackStateChanged: { console.log(playbackState) switch (playbackState){ @@ -72,7 +70,6 @@ FullscreenContentPage { return; } } - onPositionChanged: function(){ //console.log(duration) //console.log(bufferProgress) @@ -84,17 +81,18 @@ FullscreenContentPage { playerProgress.value = position } } - onStopped: function(){ stop() } IconButton { id: playerIcon - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.leftMargin: Theme.paddingLarge - anchors.bottomMargin: Theme.paddingLarge*1.5 + anchors { + left: parent.left + bottom: parent.bottom + leftMargin: Theme.horizontalPageMargin + bottomMargin: Theme.horizontalPageMargin + } icon.source: "image://theme/icon-m-play" onClicked: function() { if (video.playbackState === MediaPlayer.PlayingState) @@ -105,56 +103,47 @@ FullscreenContentPage { } ProgressBar { - indeterminate: true id: playerProgress - anchors.left: playerIcon.right - anchors.right: videoDlBtn.left - anchors.verticalCenter: playerIcon.verticalCenter - anchors.leftMargin: 0 - anchors.bottomMargin: Theme.paddingLarge*1.5 - } - - IconButton { - id: videoDlBtn - 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]); + indeterminate: true + width: 400 + anchors { + verticalCenter: playerIcon.verticalCenter + left: playerIcon.right + right: parent.right + rightMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium + bottomMargin: Theme.horizontalPageMargin } - } - Rectangle { - visible: videoError.text != "" - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - color: Theme.highlightDimmerColor - height: videoError.height + 2*Theme.paddingMedium - width: parent.width - Label { - anchors.centerIn: parent - id: videoError - width: parent.width - 2*Theme.paddingMedium - wrapMode: Text.Wrap - height: contentHeight - visible: false; - font.pixelSize: Theme.fontSizeSmall; - text: video.errorString - color: Theme.highlightColor + 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 + } } - } - MouseArea { - anchors.fill: parent - onClicked: function() { - if (video.playbackState === MediaPlayer.PlayingState) - video.pause() - else - video.play() + MouseArea { + anchors.fill: parent + onClicked: function() { + if (video.playbackState === MediaPlayer.PlayingState) + video.pause() + else + video.play() + } } } } @@ -163,11 +152,12 @@ FullscreenContentPage { Flickable { id: imageFlickable visible: false - anchors.fill: parent - contentWidth: imageContainer.width - contentHeight: imageContainer.height + contentWidth: imageContainer.width; contentHeight: imageContainer.height clip: true - onHeightChanged: if (imagePreview.status === Image.Ready) imagePreview.fitToScreen(); + anchors.fill: parent + onHeightChanged: if (imagePreview.status === Image.Ready) { + imagePreview.fitToScreen() + } Item { id: imageContainer @@ -176,18 +166,21 @@ FullscreenContentPage { Image { id: imagePreview + property real prevScale + function fitToScreen() { - scale = Math.min(imageFlickable.width / width, imageFlickable.height / height, 1) + scale = Math.min(imageFlickable.width / width, imageFlickable.height / height, imageFlickable.width, imageFlickable.height) pinchArea.minScale = scale prevScale = scale } - anchors.centerIn: parent + fillMode: Image.PreserveAspectFit cache: true asynchronous: true - sourceSize.height: 2000; - smooth: true // might slower performance + sourceSize.width: mediaPage.width + smooth: false + anchors.centerIn: parent onStatusChanged: { if (status == Image.Ready) { fitToScreen() @@ -195,15 +188,6 @@ FullscreenContentPage { } } - NumberAnimation { - id: loadedAnimation - target: imagePreview - property: "opacity" - duration: 250 - from: 0; to: 1 - easing.type: Easing.InOutQuad - } - onScaleChanged: { if ((width * scale) > imageFlickable.width) { var xoff = (imageFlickable.width / 2 + imageFlickable.contentX) * scale / prevScale; @@ -215,19 +199,30 @@ FullscreenContentPage { } prevScale = scale } + + NumberAnimation { + id: loadedAnimation + target: imagePreview + property: "opacity" + duration: 250 + from: 0; to: 1 + easing.type: Easing.InOutQuad + } } } PinchArea { id: pinchArea opacity: 0.3 + property real minScale: 1.0 property real maxScale: 3.0 + anchors.fill: parent enabled: imagePreview.status === Image.Ready pinch.target: imagePreview pinch.minimumScale: minScale * 0.5 // This is to create "bounce back effect" - pinch.maximumScale: maxScale * 1.5 // when over zoomed + pinch.maximumScale: maxScale * 1.5 // when over zoomed} onPinchFinished: { imageFlickable.returnToBounds() @@ -249,67 +244,74 @@ FullscreenContentPage { from: imagePreview.scale } } - } - Loader { - anchors.centerIn: parent - sourceComponent: { - switch (imagePreview.status) { - case Image.Loading: - return loadingIndicator - case Image.Error: - return failedLoading - default: - return undefined + Loader { + anchors.centerIn: parent + sourceComponent: { + switch (imagePreview.status) { + case Image.Loading: + return loadingIndicator + case Image.Error: + return failedLoading + default: + return undefined + } } - } - Component { - id: loadingIndicator + Component { + id: loadingIndicator + Item { + width: mediaPage.width + height: childrenRect.height - Item { - height: childrenRect.height - width: imagePage.width + ProgressCircle { + id: imageLoadingIndicator + progressValue: imagePreview.progress + progressColor: inAlternateCycle ? Theme.highlightColor : Theme.highlightDimmerColor + backgroundColor: inAlternateCycle ? Theme.highlightDimmerColor : Theme.highlightColor + anchors.horizontalCenter: parent.horizontalCenter + } + } + } - ProgressCircle { - id: imageLoadingIndicator - progressColor: inAlternateCycle ? Theme.highlightColor : Theme.highlightDimmerColor - backgroundColor: inAlternateCycle ? Theme.highlightDimmerColor : Theme.highlightColor - anchors.horizontalCenter: parent.horizontalCenter - progressValue: imagePreview.progress + Component { + id: failedLoading + Text { + text: qsTr("Error loading") + font.pixelSize: Theme.fontSizeSmall; + color: Theme.highlightColor } } } - } - Component { - id: failedLoading - Text { - font.pixelSize: Theme.fontSizeSmall; - text: qsTr("Error loading") - color: Theme.highlightColor - } + VerticalScrollDecorator { flickable: imageFlickable } } IconButton { - y: Theme.paddingLarge - anchors.right: parent.right - anchors.rightMargin: Theme.horizontalPageMargin + id: dismissBtn icon.source: "image://theme/icon-m-dismiss" + anchors { + top: parent.top + topMargin: Theme.horizontalPageMargin + right: parent.right + rightMargin: Theme.horizontalPageMargin + } onClicked: pageStack.pop() } IconButton { - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: Theme.paddingLarge - anchors.bottomMargin: Theme.paddingLarge*1.5 + id: mediaDlBtn + anchors { + right: parent.right + rightMargin: Theme.horizontalPageMargin + bottom: parent.bottom + bottomMargin: Theme.horizontalPageMargin + } icon.source: "image://theme/icon-m-cloud-download" onClicked: { var filename = mediaURL.split("/"); FileDownloader.downloadFile(mediaURL, filename[filename.length-1]); } } - - VerticalScrollDecorator { flickable: imageFlickable } } + diff --git a/qml/pages/components/MiniHeader.qml b/qml/pages/components/MiniHeader.qml index 6922f39..af5c608 100644 --- a/qml/pages/components/MiniHeader.qml +++ b/qml/pages/components/MiniHeader.qml @@ -37,26 +37,24 @@ Item { width: account_locked ? Theme.iconSizeExtraSmall*0.8 : 0 opacity: 0.8 height: width - source: "image://theme/icon-s-secure?" + (pressed - ? Theme.highlightColor - : Theme.primaryColor) + source: "image://theme/icon-s-secure?" + (pressed ? Theme.highlightColor : Theme.primaryColor) } Label { id: lblScreenName + truncationMode: TruncationMode.Fade + text: '@'+account_username + font.pixelSize: Theme.fontSizeExtraSmall + color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor) anchors { left: iconVerified.right right: lblDate.left leftMargin: Theme.paddingMedium baseline: lblName.baseline } - truncationMode: TruncationMode.Fade - text: '@'+account_username - font.pixelSize: Theme.fontSizeExtraSmall - color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor) } - Label { + Label { id: lblDate color: (pressed ? Theme.highlightColor : Theme.primaryColor) text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours) @@ -64,8 +62,8 @@ Item { horizontalAlignment: Text.AlignRight anchors { right: parent.right - baseline: lblName.baseline rightMargin: Theme.horizontalPageMargin + baseline: lblName.baseline } } diff --git a/qml/pages/components/MiniStatus.qml b/qml/pages/components/MiniStatus.qml index 4dd559b..a38dfca 100644 --- a/qml/pages/components/MiniStatus.qml +++ b/qml/pages/components/MiniStatus.qml @@ -9,6 +9,10 @@ Item { width: parent.width Image { id: icon + visible: type.length + width: Theme.iconSizeExtraSmall + height: width + source: typeof typeIcon !== "undefined" ? typeIcon : "" anchors { top: parent.top topMargin: Theme.paddingMedium @@ -16,12 +20,8 @@ Item { left: parent.left leftMargin: Theme.horizontalPageMargin + Theme.iconSizeMedium - width } - visible: type.length - width: Theme.iconSizeExtraSmall - height: width - source: typeof typeIcon !== "undefined" ? typeIcon : "" - } + Label { id: lblRtByName visible: type.length @@ -48,7 +48,6 @@ Item { } return typeof reblog_account_username !== "undefined" ? '@' + reblog_account_username + ' ' + action : '' } - font.pixelSize: Theme.fontSizeExtraSmall color: Theme.highlightColor } diff --git a/qml/pages/components/MyImage.qml b/qml/pages/components/MyImage.qml index 0e0775f..8e0be74 100644 --- a/qml/pages/components/MyImage.qml +++ b/qml/pages/components/MyImage.qml @@ -5,33 +5,38 @@ import QtMultimedia 5.0 Item { id: myImage + property string type : "" property string previewURL: "" property string mediaURL: "" + Rectangle { opacity: 0.2 - anchors.fill: parent color: Theme.highlightDimmerColor + anchors.fill: parent } + Image { - anchors.centerIn: parent source: "image://theme/icon-m-image" + anchors.centerIn: parent } + Rectangle { id: progressRec - anchors.bottom: parent.bottom width: 0 height: Theme.paddingSmall color: Theme.highlightBackgroundColor + anchors.bottom: parent.bottom } + Image { id: img - anchors.fill: parent - fillMode: Image.PreserveAspectCrop asynchronous: true opacity: status === Image.Ready ? 1.0 : 0.0 Behavior on opacity { FadeAnimator {} } source: previewURL + fillMode: Image.PreserveAspectCrop + anchors.fill: parent onProgressChanged: { if (progress != 1) progressRec.width = parent.width * progress @@ -39,35 +44,48 @@ Item { progressRec.width = 0; } } + MouseArea { anchors.fill: parent onClicked: { - pageStack.push(Qt.resolvedUrl("./ImageFullScreen.qml"), {"previewURL": previewURL, "mediaURL": mediaURL, "type": type}) + pageStack.push(Qt.resolvedUrl("./MediaFullScreen.qml"), { + "previewURL": previewURL, + "mediaURL": mediaURL, + "type": type + }) } } + Image { + id: videoIcon visible: type === "video" || type === "gifv" - anchors.centerIn: parent source: "image://theme/icon-l-play" + anchors.centerIn: parent } + BusyIndicator { + id: mediaLoader size: BusyIndicatorSize.Large running: img.status !== Image.Ready opacity: img.status === Image.Ready ? 0.0 : 1.0 anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter } + Rectangle { - anchors.fill: parent + id: mediaWarning color: Theme.highlightDimmerColor visible: typeof status_sensitive != 'undefined' && status_sensitive ? true : false + anchors.fill: parent + Image { source: "image://theme/icon-l-attention?"+Theme.highlightColor anchors.centerIn: parent } + MouseArea { anchors.fill: parent - onClicked: parent.visible = false; + onClicked: parent.visible = false } } } diff --git a/qml/pages/components/MyList.qml b/qml/pages/components/MyList.qml index 135df3c..d3dc318 100644 --- a/qml/pages/components/MyList.qml +++ b/qml/pages/components/MyList.qml @@ -61,13 +61,7 @@ SilicaListView { pageStack.push(Qt.resolvedUrl("../SettingsPage.qml"), {}) } } - /* MenuItem { - text: qsTr("Open in Browser") - visible: profile_url != "" - onClicked: { - Clipboard.text = profile_url - } - } */ + MenuItem { text: qsTr("Load more") onClicked: { diff --git a/qml/pages/components/Navigation.qml b/qml/pages/components/Navigation.qml index 1d721b1..c4af981 100644 --- a/qml/pages/components/Navigation.qml +++ b/qml/pages/components/Navigation.qml @@ -4,13 +4,16 @@ import QtGraphicalEffects 1.0 SilicaGridView { + id: gridView + + property bool isPortrait: false signal slideshowShow(int vIndex) signal slideshowIndexChanged(int vIndex) + onSlideshowIndexChanged: { navigateTo(vIndex) } - id: gridView - property bool isPortrait: false + ListModel { id: listModel ListElement { @@ -20,12 +23,14 @@ SilicaGridView { active: true unread: false } + ListElement { icon: "image://theme/icon-m-alarm" slug: "notifications" name: "Notifications" active: false } + ListElement { icon: "image://theme/icon-m-whereami" slug: "local" @@ -33,6 +38,7 @@ SilicaGridView { active: false unread: false } + ListElement { icon: "image://theme/icon-m-website" slug: "federated" @@ -40,6 +46,7 @@ SilicaGridView { active: false unread: false } + ListElement { icon: "image://theme/icon-m-search" slug: "search" @@ -49,15 +56,13 @@ SilicaGridView { } } model: listModel - anchors.fill: parent currentIndex: -1 - cellWidth: isPortrait ? gridView.width : gridView.width / model.count cellHeight: isPortrait ? gridView.height/model.count : gridView.height - + anchors.fill: parent delegate: BackgroundItem { - clip: true id: rectangle + clip: true width: gridView.cellWidth height: gridView.cellHeight GridView.onAdd: AddAnimation { @@ -66,88 +71,93 @@ SilicaGridView { GridView.onRemove: RemoveAnimation { target: rectangle } + GlassItem { id: effect visible: !isPortrait && unread + dimmed: true + color: Theme.highlightColor width: Theme.itemSizeMedium height: Theme.itemSizeMedium - dimmed: true - anchors.bottom: parent.bottom - anchors.bottomMargin: -height/2 - anchors.horizontalCenter: parent.horizontalCenter - color: Theme.highlightColor + anchors { + bottom: parent.bottom + bottomMargin: -height/2 + horizontalCenter: parent.horizontalCenter + } } + GlassItem { id: effect2 visible: isPortrait && unread + dimmed: false + color: Theme.highlightColor width: Theme.itemSizeMedium height: Theme.itemSizeMedium - dimmed: false - anchors.right: parent.right; - anchors.rightMargin: -height/2; - anchors.verticalCenter: parent.verticalCenter - color: Theme.highlightColor + anchors { + right: parent.right + rightMargin: -height/2 + verticalCenter: parent.verticalCenter + } } + OpacityRampEffect { sourceItem: label offset: 0.5 } + ColorOverlay { - anchors.fill: image - source: image - color: (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor)) - } + source: image + color: (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor)) + anchors.fill: image + } + Image { id: image + visible: false + source: model.icon // +'?'+ (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor)) sourceSize.width: Theme.iconSizeMedium sourceSize.height: Theme.iconSizeMedium - source: model.icon// +'?'+ (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor)) anchors.centerIn: parent - visible: false - // smooth: true } Text { - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.paddingSmall - anchors.left: parent.left - anchors.right: parent.right - horizontalAlignment: Text.AlignHCenter visible: false text: model.name font.pixelSize: Theme.fontSizeExtraSmall/2 color: (highlighted ? Theme.highlightColor : (model.active ? Theme.primaryColor : Theme.secondaryHighlightColor)) + horizontalAlignment: Text.AlignHCenter + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + bottomMargin: Theme.paddingSmall + } } Label { id: label visible: false - anchors { - bottom: parent.bottom - } - horizontalAlignment : Text.AlignHCente - width: parent.width color: (highlighted ? Theme.highlightColor : Theme.secondaryHighlightColor) - text: { return model.name.toUpperCase(); } - - font { - pixelSize: Theme.fontSizeExtraSmall - family: Theme.fontFamilyHeading - } + font.pixelSize: Theme.fontSizeExtraSmall + font.family: Theme.fontFamilyHeading + width: parent.width + horizontalAlignment : Text.AlignHCenter + anchors.bottom: parent.bottom } + onClicked: { slideshowShow(index) console.log(index) navigateTo(model.slug) effect.state = "right" } - } + function navigateTo(slug){ for(var i = 0; i < listModel.count; i++){ if (listModel.get(i).slug === slug || i===slug) @@ -156,9 +166,9 @@ SilicaGridView { listModel.setProperty(i, 'active', false); } console.log(slug) - } VerticalScrollDecorator {} + } diff --git a/qml/pages/components/ProfileHeader.qml b/qml/pages/components/ProfileHeader.qml index a4fd987..af2126d 100644 --- a/qml/pages/components/ProfileHeader.qml +++ b/qml/pages/components/ProfileHeader.qml @@ -4,48 +4,69 @@ import Sailfish.Silica 1.0 Item { id: profileHeader + property int value: 0 property string title: "" property string description: "" property string image: "" property string bg: "" + width: parent.width height: icon.height + Theme.paddingLarge*2 Rectangle { id: bgImage - anchors.fill: parent opacity: 0.2 gradient: Gradient { GradientStop { position: 0.0; color: Theme.highlightBackgroundColor } GradientStop { position: 1.0; color: Theme.highlightBackgroundColor } } + anchors.fill: parent + Image { - anchors.fill: bgImage asynchronous: true fillMode: Image.PreserveAspectCrop source: bg opacity: 0.8 + anchors.fill: parent } } + Image { 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 { left: parent.left leftMargin: Theme.paddingLarge top: parent.top topMargin: Theme.paddingLarge } - asynchronous: true - width: description === "" ? Theme.iconSizeMedium : Theme.iconSizeLarge - height: width - source: - if (icon.status === Image.Error) - source = "../../images/icon-l-profile.svg?" + (pressed - ? Theme.highlightColor - : Theme.primaryColor) - else image + + Button { + id: imageButton + opacity: 0 + width: Theme.iconSizeExtraLarge * 1.2 + anchors { + top: parent.top + left: parent.left + bottom: parent.bottom + } + onClicked: { + pageStack.push(Qt.resolvedUrl("ProfileImage.qml"), { + "image": image + }) + } + } } + Column { anchors { left: icon.right @@ -54,6 +75,7 @@ Item { rightMargin: Theme.paddingLarge verticalCenter: parent.verticalCenter } + Label { id: ttl text: @@ -61,23 +83,24 @@ Item { description.split('@')[0] } else title - height: contentHeight - color: Theme.highlightColor font.pixelSize: Theme.fontSizeLarge font.family: Theme.fontFamilyHeading - horizontalAlignment: Text.AlignRight + color: Theme.highlightColor truncationMode: TruncationMode.Fade width: parent.width + height: contentHeight + horizontalAlignment: Text.AlignRight } + Label { - height: description === "" ? 0 : contentHeight text: "@"+description - color: Theme.secondaryHighlightColor font.pixelSize: Theme.fontSizeSmall font.family: Theme.fontFamilyHeading - horizontalAlignment: Text.AlignRight + color: Theme.secondaryHighlightColor truncationMode: TruncationMode.Fade width: parent.width + height: description === "" ? 0 : contentHeight + horizontalAlignment: Text.AlignRight } } diff --git a/qml/pages/components/ProfileImage.qml b/qml/pages/components/ProfileImage.qml new file mode 100644 index 0000000..38fdde0 --- /dev/null +++ b/qml/pages/components/ProfileImage.qml @@ -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() + } + +} diff --git a/qml/pages/components/Toot.qml b/qml/pages/components/Toot.qml index fbd9190..43de76b 100644 --- a/qml/pages/components/Toot.qml +++ b/qml/pages/components/Toot.qml @@ -26,6 +26,8 @@ BackgroundItem { visible: type.length anchors.left: lblName.left anchors.bottom: iconRT.bottom + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.secondaryColor text: { var action; switch(type){ @@ -43,8 +45,6 @@ BackgroundItem { } return '@' + retweetScreenName + ' ' + action } - font.pixelSize: Theme.fontSizeExtraSmall - color: Theme.secondaryColor } Image { @@ -116,12 +116,12 @@ BackgroundItem { } Label { + id: lblDate function timestamp() { var txt = Format.formatDate(created_at, Formatter.Timepoint) var elapsed = Format.formatDate(created_at, Formatter.DurationElapsedShort) return (elapsed ? elapsed : txt ) } - id: lblDate color: (pressed ? Theme.highlightColor : Theme.primaryColor) text: Format.formatDate(created_at, new Date() - created_at < 60*60*1000 ? Formatter.DurationElapsedShort : Formatter.TimeValueTwentyFourHours) font.pixelSize: Theme.fontSizeExtraSmall diff --git a/src/notifications.h b/src/notifications.h index b22486a..524da9e 100644 --- a/src/notifications.h +++ b/src/notifications.h @@ -17,7 +17,7 @@ class Notifications : public QObject { Q_OBJECT public: - explicit Notifications(QObject *parent = 0); + explicit Notifications(QObject *parent = nullptr); Q_INVOKABLE void notify(QString appName, QString summary, QString body, bool preview, QString ts, QString issuekey); };