Supporting images in the TL

This commit is contained in:
Dusko Angirevic 2017-06-16 16:45:04 +02:00
parent a3bd2834b7
commit 6a20bc1657
14 changed files with 348 additions and 59 deletions

View file

@ -110,6 +110,7 @@ Qt.include("Mastodon.js")
var modelTLhome = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var modelTLhome = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
var modelTLpublic = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var modelTLpublic = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
var modelTLnotifications = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject'); var modelTLnotifications = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
var modelTLsearch = Qt.createQmlObject('import QtQuick 2.0; ListModel { }', Qt.application, 'InternalQmlObject');
var notificationsList = [] var notificationsList = []
var notificationGenerator = function(item){ var notificationGenerator = function(item){
var notification; var notification;

View file

@ -21,10 +21,20 @@ WorkerScript.onMessage = function(msg) {
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) {
for (var i in data) { if (msg.action === "statuses"){
if (data.hasOwnProperty(i)) { // status posted
console.log(JSON.stringify(data[i])) if(msg.model){
WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i]}) var item = parseToot(data);
msg.model.append(item)
msg.model.sync();
}
} else {
for (var i in data) {
if (data.hasOwnProperty(i)) {
console.log(JSON.stringify(data[i]))
WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i]})
}
} }
} }
}); });
@ -83,8 +93,8 @@ WorkerScript.onMessage = function(msg) {
} }
if(msg.model && items.length) if(msg.model && items.length)
addDataToModel(msg.model, msg.mode, items) addDataToModel(msg.model, msg.mode, items)
if(msg.action === "notifications") /*if(msg.action === "notifications")
orderNotifications(items) orderNotifications(items)*/
}); });
} }
@ -124,7 +134,8 @@ function parseNotification(data){
//console.log(JSON.stringify(data)) //console.log(JSON.stringify(data))
var item = { var item = {
id: data.id, id: data.id,
type: data.type type: data.type,
attachments: []
}; };
switch (item['type']){ switch (item['type']){
case "mention": case "mention":
@ -156,6 +167,7 @@ function parseNotification(data){
item = parseAccounts(item, "reblog_", data["account"]) item = parseAccounts(item, "reblog_", data["account"])
item['content'] = data['account']['note'] item['content'] = data['account']['note']
item['typeIcon'] = "image://theme/icon-s-installed" item['typeIcon'] = "image://theme/icon-s-installed"
item['attachments'] = []
break; break;
default: default:
@ -164,7 +176,7 @@ function parseNotification(data){
item['id'] = data.id item['id'] = data.id
item['created_at'] = new Date(data.created_at) item['created_at'] = new Date(data.created_at)
item['section'] = new Date(data["created_at"]).toLocaleDateString() item['section'] = getDate(data["created_at"])
return item; return item;
} }
@ -180,6 +192,10 @@ function collect() {
} }
return ret; return ret;
} }
function getDate(dateStr){
var ts = new Date(dateStr);
return new Date(ts.getFullYear(), ts.getMonth(), ts.getDate(), 0, 0, 0)
}
function parseToot (data){ function parseToot (data){
//console.log(JSON.stringify(data)) //console.log(JSON.stringify(data))
var item = {}; var item = {};
@ -191,7 +207,7 @@ function parseToot (data){
item['status_reblog'] = data["reblog"] ? true : false item['status_reblog'] = data["reblog"] ? true : false
item['status_content'] = data["content"] item['status_content'] = data["content"]
item['status_created_at'] = item['created_at'] = new Date(data["created_at"]); item['status_created_at'] = item['created_at'] = new Date(data["created_at"]);
item['section'] = new Date(data["created_at"]).toLocaleDateString() item['section'] = getDate(data["created_at"]);
item['status_reblogs_count'] = data["reblogs_count"] item['status_reblogs_count'] = data["reblogs_count"]
item['status_favourites_count'] = data["favourites_count"] item['status_favourites_count'] = data["favourites_count"]
item['status_reblogged'] = data["reblogged"] item['status_reblogged'] = data["reblogged"]
@ -212,13 +228,13 @@ function parseToot (data){
} else { } else {
item = parseAccounts(item, "", data["account"]) item = parseAccounts(item, "", data["account"])
} }
item['content'] = data['content'].replaceAll('</span><span class="invisible">', '').replaceAll('<span class="invisible">', '').replaceAll('</span><span class="ellipsis">', '');
//item['application_name'] = data["application"]["name"] //item['application_name'] = data["application"]["name"]
//item['application_website'] = data["application"]["website"] //item['application_website'] = data["application"]["website"]
// account // account
item['content'] = data['content'].replace(/(<([^>]+)>)/ig,""); //item['content'] = data['content'].replace(/(<([^>]+)>)/ig,"");
/*for(var i = 0; i < data['tags'].length ; i++){ /*for(var i = 0; i < data['tags'].length ; i++){
var tag = data['tags'][i]['name']; var tag = data['tags'][i]['name'];
console.log(tag) console.log(tag)
@ -227,7 +243,6 @@ function parseToot (data){
item['attachments'] = []; item['attachments'] = [];
for(var i = 0; i < data['media_attachments'].length ; i++){ for(var i = 0; i < data['media_attachments'].length ; i++){
var attachments = data['media_attachments'][i]; var attachments = data['media_attachments'][i];
console.log(JSON.stringify(attachments))
item['content'] = item['content'].replaceAll(attachments['text_url'], '') item['content'] = item['content'].replaceAll(attachments['text_url'], '')
item['attachments'].push({ item['attachments'].push({
id: attachments['id'], id: attachments['id'],
@ -237,8 +252,7 @@ function parseToot (data){
preview_url: attachments['preview_url'] preview_url: attachments['preview_url']
}) })
} }
console.log(JSON.stringify(item['attachments'])) /*item['content'] = item['content'].split(" ")
item['content'] = item['content'].split(" ")
for(var i = 0; i < item['content'].length ; i++){ for(var i = 0; i < item['content'].length ; i++){
if(item['content'][i][0] === "#"){ if(item['content'][i][0] === "#"){
item['content'][i] = '<a href="'+item['content'][i]+'">'+item['content'][i]+'</a>'; item['content'][i] = '<a href="'+item['content'][i]+'">'+item['content'][i]+'</a>';
@ -247,9 +261,8 @@ function parseToot (data){
item['content'][i] = '<a href="'+item['content'][i]+'">'+item['content'][i]+'</a>'; item['content'][i] = '<a href="'+item['content'][i]+'">'+item['content'][i]+'</a>';
} }
} }
item['content'] = item['content'].join(" ").autoLink() item['content'] = item['content'].join(" ").autoLink()*/
//console.log(JSON.stringify(item)) //console.log(JSON.stringify(item))
return item; return item;
} }

View file

@ -137,6 +137,8 @@ Page {
var msg = { var msg = {
'action' : 'statuses', 'action' : 'statuses',
'method' : 'POST', 'method' : 'POST',
'model' : mdl,
'mode' : "append",
'params' : { 'params' : {
"status": toot.text, "status": toot.text,
"visibility": visibility[privacy.currentIndex] "visibility": visibility[privacy.currentIndex]

View file

@ -145,7 +145,7 @@ Page {
} }
clip: true clip: true
model: ListModel {} mdl: ListModel {}
type: "accounts/"+user_id+"/statuses" type: "accounts/"+user_id+"/statuses"
vars: {} vars: {}
conf: Logic.conf conf: Logic.conf

View file

@ -0,0 +1,66 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import QtMultimedia 5.0
Page {
id: page
property string type: ""
property string previewURL: ""
property string mediaURL: ""
allowedOrientations: Orientation.All
Item {
anchors.fill: parent
clip: true
Image {
id: image
anchors.centerIn: parent
//fillMode: Image.PreserveAspectCrop
asynchronous: true
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
source: mediaURL
onStatusChanged: {
if (status === Image.Ready) {
console.log('Loaded')
width = sourceSize.width
height = sourceSize.height
if (width > height)
pinch.scale = page.width / width
else
pinch.scale = page.height / height
}
}
}
Video {
id: video
anchors.fill: parent
autoLoad: true
source: videoURL
onErrorStringChanged: {
console.log(errorString)
}
MouseArea {
anchors.fill: parent
onClicked: {
video.playbackState == MediaPlayer.PlayingState ? video.pause() : video.play()
}
}
focus: true
}
PinchArea {
id: pinch
visible: videoURL === ""
anchors.fill: parent
pinch.target: image
pinch.minimumScale: 0.1
pinch.maximumScale: 10
pinch.dragAxis: Pinch.XAndYAxis
}
}
}

View file

@ -0,0 +1,154 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import QtMultimedia 5.0
Item {
property ListModel model
property double wRatio : 16/9
property double hRatio : 9/16
id: holder
width: width
height: height
Component.onCompleted: {
if (model && model.count && model.get(0).type === "video") {
while (model.count>1){
model.remove(model.count-1)
}
//console.log(JSON.stringify(model.get(0)))
}
switch(model.count){
case 1:
placeholder1.width = holder.width
placeholder1.height = placeholder1.width*hRatio
placeholder1.visible = true;
holder.height = placeholder1.height
break;
case 2:
placeholder1.visible = true;
placeholder2.visible = true;
placeholder1.width = (holder.width-Theme.paddingSmall)/2
placeholder1.height = placeholder1.width
placeholder2.width = placeholder1.width
placeholder2.height = placeholder1.width
placeholder2.x = placeholder1.width + placeholder2.x + Theme.paddingSmall
holder.height = placeholder1.height
break;
case 3:
placeholder1.visible = true;
placeholder2.visible = true;
placeholder3.visible = true;
placeholder4.visible = false;
placeholder1.width = holder.width - Theme.paddingSmall - Theme.itemSizeLarge;
placeholder1.height = Theme.itemSizeLarge*2+Theme.paddingSmall
placeholder2.width = Theme.itemSizeLarge;
placeholder2.height = placeholder2.width
placeholder2.x = placeholder1.x + placeholder1.width + Theme.paddingSmall;
break;
case 4:
placeholder1.visible = true;
placeholder2.visible = true;
placeholder3.visible = true;
placeholder4.visible = true;
placeholder1.width = placeholder2.width = placeholder3.width = placeholder4.width = (holder.width - 3*Theme.paddingSmall)/4
placeholder1.height = placeholder2.height = placeholder3.height = placeholder4.height = Theme.itemSizeLarge*2+Theme.paddingSmall
placeholder2.x = 1*(placeholder1.width)+ 1*Theme.paddingSmall;
placeholder3.x = 2*(placeholder1.width)+ 2*Theme.paddingSmall;
placeholder4.x = 3*(placeholder1.width)+ 3*Theme.paddingSmall;
holder.height = placeholder1.height
break;
default:
holder.height = 0
}
}
MyImage {
id: placeholder1
width: 2
height: 1
opacity: pressed ? 0.6 : 1
visible: {
if (model && model.count){
type = model.get(0).type
previewURL = model.get(0).preview_url
mediaURL = model.get(0).url
height = 200
return true
} else {
height = 0
return false
}
}
Image {
visible: model.count && (model.get(0).type === "video" || model.get(0).type === "gifv")
anchors.centerIn: parent
source: "image://theme/icon-l-play"
}
}
MyImage {
id: placeholder2
width: 2
height: 1
opacity: pressed ? 0.6 : 1
visible: {
if (model && model.count && model.get(1)){
type = model.get(1).type
previewURL = model.get(1).preview_url
mediaURL = model.get(1).url
height = 200
return true
} else {
height = 0
return false
}
}
}
MyImage {
id: placeholder3
width: 2
height: 1
opacity: pressed ? 0.6 : 1
visible: {
if (model && model.count && model.get(2)){
type = model.get(2).type
previewURL = model.get(2).preview_url
mediaURL = model.get(2).url
height = 200
return true
} else {
height = 0
return false
}
}
}
MyImage {
id: placeholder4
width: 2
height: 1
opacity: pressed ? 0.6 : 1
visible: {
if (model && model.count && model.get(3)){
type = model.get(3).type
previewURL = model.get(3).preview_url
mediaURL = model.get(3).url
height = 200
return true
} else {
height = 0
return false
}
}
}
}

View file

@ -18,7 +18,7 @@ Item {
visible: type.length visible: type.length
width: Theme.iconSizeExtraSmall width: Theme.iconSizeExtraSmall
height: width height: width
source: typeIcon source: typeof typeIcon !== "undefined" ? typeIcon : ""
} }
Label { Label {
@ -45,7 +45,7 @@ Item {
ministatus.visible = false ministatus.visible = false
action = type; action = type;
} }
return '@' + reblog_account_username + ' ' + action return typeof reblog_account_username !== "undefined" ? '@' + reblog_account_username + ' ' + action : ''
} }
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall

View file

@ -0,0 +1,23 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import QtMultimedia 5.0
Item {
property string type : ""
property string previewURL: ""
property string mediaURL: ""
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
asynchronous: true
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
source: previewURL
MouseArea {
anchors.fill: parent
onClicked: {
pageStack.push(Qt.resolvedUrl("./ImageFullScreen.qml"), {"previewURL": previewURL, "mediaURL": mediaURL, "type": type})
}
}
}
}

View file

@ -2,20 +2,9 @@ import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import "../../lib/API.js" as Logic import "../../lib/API.js" as Logic
import "." import "."
import org.nemomobile.notifications 1.0
SilicaListView { SilicaListView {
Notification {
id: notification
category: "x-nemo.example"
urgency: Notification.Normal
onClicked: console.log("Clicked")
}
id: myList id: myList
property string type; property string type;
property string title property string title
@ -86,19 +75,20 @@ SilicaListView {
} }
} }
} }
PushUpMenu { /*PushUpMenu {
MenuItem { MenuItem {
text: qsTr("Load more") text: qsTr("Load more")
onClicked: { onClicked: {
loadData("append") loadData("append")
} }
} }
} }*/
clip: true clip: true
section { section {
property: 'section' property: 'section'
delegate: SectionHeader { delegate: SectionHeader {
text: section height: Theme.itemSizeExtraSmall
text: Format.formatDate(section, Formatter.DateMedium)
} }
} }
@ -114,22 +104,43 @@ SilicaListView {
} }
onCountChanged: { onCountChanged: {
contentY = scrollOffset loadStarted = false;
console.log("CountChanged!") /*contentY = scrollOffset
console.log("CountChanged!")*/
//last_id_MN
} }
footer: Item{
width: parent.width
height: Theme.itemSizeLarge
Button {
anchors.horizontalCenter: parent.horizontalCenter
anchors.margins: Theme.paddingSmall
anchors.bottomMargin: Theme.paddingLarge
visible: false
onClicked: {
loadData("append")
}
}
BusyIndicator {
size: BusyIndicatorSize.Small
running: loadStarted;
//anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
}
onContentYChanged: { onContentYChanged: {
if (contentY > scrollOffset) { if (contentY > scrollOffset) {
openDrawer(false) openDrawer(false)
} else { } else {
if (contentY < 100 && !loadStarted){
}
openDrawer(true) openDrawer(true)
} }
if(contentY+height > footerItem.y && !loadStarted){
loadData("append")
loadStarted = true;
}
scrollOffset = contentY scrollOffset = contentY
} }
VerticalScrollDecorator {} VerticalScrollDecorator {}

View file

@ -6,7 +6,7 @@ BackgroundItem {
signal send (string notice) signal send (string notice)
signal navigateTo(string link) signal navigateTo(string link)
width: parent.width width: parent.width
height: miniHeader.height + media.height + lblContent.height + Theme.paddingLarge + (ministatus.visible ? ministatus.height : 0) +Theme.paddingLarge height: miniHeader.height + (attachments && attachments.count ? media.height + Theme.paddingLarge + Theme.paddingMedium: Theme.paddingLarge) + lblContent.height + Theme.paddingLarge + (ministatus.visible ? ministatus.height : 0)
MiniStatus { MiniStatus {
id: ministatus id: ministatus
anchors { anchors {
@ -24,6 +24,8 @@ BackgroundItem {
left: parent.left left: parent.left
leftMargin: Theme.horizontalPageMargin leftMargin: Theme.horizontalPageMargin
} }
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
asynchronous: true asynchronous: true
width: Theme.iconSizeMedium width: Theme.iconSizeMedium
height: width height: width
@ -58,6 +60,8 @@ BackgroundItem {
width: Theme.iconSizeSmall width: Theme.iconSizeSmall
height: width height: width
smooth: true smooth: true
opacity: status === Image.Ready ? 1.0 : 0.0
Behavior on opacity { FadeAnimator {} }
source: typeof reblog_account_avatar !== "undefined" ? reblog_account_avatar : '' source: typeof reblog_account_avatar !== "undefined" ? reblog_account_avatar : ''
visible: typeof status_reblog !== "undefined" && status_reblog visible: typeof status_reblog !== "undefined" && status_reblog
} }
@ -107,25 +111,37 @@ BackgroundItem {
} }
text: content text: content.replace(new RegExp("<a ", 'g'), '<a style="text-decoration: none; color:'+Theme.highlightColor+'" ')
textFormat: Text.StyledText textFormat: Text.RichText
linkColor : Theme.highlightColor linkColor : Theme.highlightColor
wrapMode: Text.Wrap wrapMode: Text.Wrap
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: (pressed ? Theme.highlightColor : (highlight ? Theme.primaryColor : Theme.secondaryColor)) color: (pressed ? Theme.highlightColor : (!highlight ? Theme.primaryColor : Theme.secondaryColor))
} }
Label { MediaBlock {
id: media id: media
anchors { anchors {
left: parent.left left: lblContent.left
leftMargin: Theme.paddingMedium right: lblContent.right
right: parent.right
rightMargin: Theme.horizontalPageMargin
top: lblContent.bottom top: lblContent.bottom
topMargin: Theme.paddingSmall topMargin: Theme.paddingSmall
bottomMargin: Theme.paddingLarge bottomMargin: Theme.paddingLarge
} }
text: attachments.count + "Aaa" model: typeof attachments !== "undefined" ? attachments : []
height: 100
Rectangle {
anchors.fill: parent
color: Theme.highlightDimmerColor
visible: status_sensitive
Image {
source: "image://theme/icon-l-attention?"+Theme.highlightColor
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: parent.visible = false;
}
}
} }
@ -143,4 +159,7 @@ BackgroundItem {
type: "reply" type: "reply"
}) })
} }
onPressAndHold: {
console.log(lblContent.text)
}
} }

View file

@ -5,11 +5,11 @@
<name></name> <name></name>
<message id="Logout"> <message id="Logout">
<source></source> <source></source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
<message id="Login"> <message id="Login">
<source></source> <source></source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -122,7 +122,7 @@
<name>MyList</name> <name>MyList</name>
<message> <message>
<source>Load more</source> <source>Load more</source>
<translation>Charger davantage</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

@ -5,11 +5,11 @@
<name></name> <name></name>
<message id="Logout"> <message id="Logout">
<source></source> <source></source>
<translation>Uitloggen</translation> <translation type="unfinished"></translation>
</message> </message>
<message id="Login"> <message id="Login">
<source></source> <source></source>
<translation>Inloggen</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -122,7 +122,7 @@
<name>MyList</name> <name>MyList</name>
<message> <message>
<source>Load more</source> <source>Load more</source>
<translation>Meer laden</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

@ -5,11 +5,11 @@
<name></name> <name></name>
<message id="Logout"> <message id="Logout">
<source></source> <source></source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
<message id="Login"> <message id="Login">
<source></source> <source></source>
<translation></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
@ -122,7 +122,7 @@
<name>MyList</name> <name>MyList</name>
<message> <message>
<source>Load more</source> <source>Load more</source>
<translation>Cargar mai</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>

View file

@ -122,7 +122,7 @@
<name>MyList</name> <name>MyList</name>
<message> <message>
<source>Load more</source> <source>Load more</source>
<translation>Load more</translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>