Conf saving and Mastodon instance login
Worst login implementation in the history of worst logins implementation
This commit is contained in:
parent
e0b81bf291
commit
01ac966b35
12 changed files with 425 additions and 467 deletions
|
@ -18,7 +18,6 @@ SOURCES += src/harbour-tooter.cpp
|
|||
|
||||
OTHER_FILES += qml/harbour-tooter.qml \
|
||||
qml/cover/CoverPage.qml \
|
||||
qml/pages/FirstPage.qml \
|
||||
qml/pages/SecondPage.qml \
|
||||
rpm/harbour-tooter.changes.in \
|
||||
rpm/harbour-tooter.spec \
|
||||
|
@ -40,5 +39,7 @@ TRANSLATIONS += translations/harbour-tooter-de.ts
|
|||
|
||||
DISTFILES += \
|
||||
qml/lib/API.js \
|
||||
qml/pages/MyList.qml \
|
||||
qml/pages/Tweet.qml
|
||||
qml/pages/MainPage.qml \
|
||||
qml/pages/LoginPage.qml \
|
||||
qml/pages/JSONListModel.qml \
|
||||
qml/lib/jsonpath.js
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.0.1, 2017-06-01T15:42:11. -->
|
||||
<!-- Written by QtCreator 4.0.1, 2017-06-02T15:45:28. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
@ -8,7 +8,7 @@
|
|||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
|
@ -768,7 +768,7 @@
|
|||
<value type="QString" key="MerRunConfiguration.QmlLiveTargetWorkspace"></value>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">1</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">harbour-tooter (on Mer Device)</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">harbour-tooter (on Remote Device)</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmakeProjectManager.MerRunConfiguration:harbour-tooter</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.Arguments"></value>
|
||||
|
|
|
@ -45,12 +45,16 @@ ApplicationWindow
|
|||
console.log('confLoaded');
|
||||
console.log(JSON.stringify(Logic.conf))
|
||||
if (Logic.conf['instance']) {
|
||||
Logic.api = Logic.MastodonAPI({ instance: Logic.conf['instance'], api_user_token: "" });
|
||||
Logic.api = new Logic.MastodonAPI({ instance: Logic.conf['instance'], api_user_token: "" });
|
||||
}
|
||||
if (Logic.conf['login']) {
|
||||
Logic.api.setConfig("api_user_token", Logic.conf['api_user_token'])
|
||||
pageStack.push(Qt.resolvedUrl("./pages/MainPage.qml"), {})
|
||||
} else {
|
||||
pageStack.push(Qt.resolvedUrl("./pages/LoginPage.qml"), {})
|
||||
}
|
||||
pageStack.push(Qt.resolvedUrl("./pages/FirstPage.qml"), {})
|
||||
|
||||
|
||||
});
|
||||
Logic.init()
|
||||
}
|
||||
|
|
|
@ -57,13 +57,19 @@ var init = function(){
|
|||
};
|
||||
|
||||
function saveData() {
|
||||
console.log("SAVING CONF TO DB")
|
||||
db.transaction(function(tx) {
|
||||
for (var key in conf) {
|
||||
if (conf.hasOwnProperty(key)){
|
||||
console.log(key + "\t>\t"+conf[key]);
|
||||
tx.executeSql('INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?) ', [key, JSON.stringify(conf[key])])
|
||||
if (typeof conf[key] === "object" && conf[key] === null) {
|
||||
tx.executeSql('DELETE FROM settings WHERE key=? ', [key])
|
||||
} else {
|
||||
tx.executeSql('INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?) ', [key, JSON.stringify(conf[key])])
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log("ENF OF SAVING")
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -268,27 +274,34 @@ var MastodonAPI = function(config) {
|
|||
if (typeof scopes !== "string") {
|
||||
scopes = scopes.join(" ");
|
||||
}
|
||||
$.ajax({
|
||||
url: apiBase + "apps",
|
||||
type: "POST",
|
||||
data: {
|
||||
client_name: client_name,
|
||||
redirect_uris: redirect_uri,
|
||||
scopes: scopes,
|
||||
website: website
|
||||
},
|
||||
success: function (data, textStatus) {
|
||||
console.log("Registered Application: " + data);
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
|
||||
var http = new XMLHttpRequest()
|
||||
var url = apiBase + "apps";
|
||||
var params = 'client_name=' + client_name + '&redirect_uris=' + redirect_uri + '&scopes=' + scopes + '&website=' + website;
|
||||
console.log(params)
|
||||
http.open("POST", url, true);
|
||||
|
||||
// Send the proper header information along with the request
|
||||
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
|
||||
http.onreadystatechange = function() { // Call a function when the state changes.
|
||||
if (http.readyState == 4) {
|
||||
if (http.status == 200) {
|
||||
console.log("Registered Application: " + http.response);
|
||||
callback(http.response)
|
||||
} else {
|
||||
console.log("error: " + http.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
http.send(params);
|
||||
},
|
||||
generateAuthLink: function (client_id, redirect_uri, responseType, scopes) {
|
||||
return config.instance + "/oauth/authorize?client_id=" + client_id + "&redirect_uri=" + redirect_uri +
|
||||
"&response_type=" + responseType + "&scope=" + scopes.join("+");
|
||||
},
|
||||
getAccessTokenFromAuthCode: function (client_id, client_secret, redirect_uri, code, callback) {
|
||||
$.ajax({
|
||||
/*$.ajax({
|
||||
url: config.instance + "/oauth/token",
|
||||
type: "POST",
|
||||
data: {
|
||||
|
@ -302,7 +315,27 @@ var MastodonAPI = function(config) {
|
|||
console.log("Got Token: " + data);
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
});*/
|
||||
var http = new XMLHttpRequest()
|
||||
var url = config.instance + "/oauth/token";
|
||||
var params = 'client_id=' + client_id + '&client_secret=' + client_secret + '&redirect_uri=' + redirect_uri + '&grant_type=authorization_code&code=' + code;
|
||||
console.log(params)
|
||||
http.open("POST", url, true);
|
||||
|
||||
// Send the proper header information along with the request
|
||||
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
|
||||
http.onreadystatechange = function() { // Call a function when the state changes.
|
||||
if (http.readyState == 4) {
|
||||
if (http.status == 200) {
|
||||
console.log("Got Token: " + http.response);
|
||||
callback(http.response)
|
||||
} else {
|
||||
console.log("error: " + http.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
http.send(params);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
88
qml/lib/jsonpath.js
Normal file
88
qml/lib/jsonpath.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* JSONPath 0.8.5 - XPath for JSON
|
||||
*
|
||||
* Copyright (c) 2007 Stefan Goessner (goessner.net)
|
||||
* Licensed under the MIT (MIT-LICENSE.txt) licence.
|
||||
*
|
||||
*/
|
||||
function jsonPath(obj, expr, arg) {
|
||||
var P = {
|
||||
resultType: arg && arg.resultType || "VALUE",
|
||||
result: [],
|
||||
normalize: function(expr) {
|
||||
var subx = [];
|
||||
return expr.replace(/[\['](\??\(.*?\))[\]']|\['(.*?)'\]/g, function($0,$1,$2){return "[#"+(subx.push($1||$2)-1)+"]";}) /* http://code.google.com/p/jsonpath/issues/detail?id=4 */
|
||||
.replace(/'?\.'?|\['?/g, ";")
|
||||
.replace(/;;;|;;/g, ";..;")
|
||||
.replace(/;$|'?\]|'$/g, "")
|
||||
.replace(/#([0-9]+)/g, function($0,$1){return subx[$1];});
|
||||
},
|
||||
asPath: function(path) {
|
||||
var x = path.split(";"), p = "$";
|
||||
for (var i=1,n=x.length; i<n; i++)
|
||||
p += /^[0-9*]+$/.test(x[i]) ? ("["+x[i]+"]") : ("['"+x[i]+"']");
|
||||
return p;
|
||||
},
|
||||
store: function(p, v) {
|
||||
if (p) P.result[P.result.length] = P.resultType == "PATH" ? P.asPath(p) : v;
|
||||
return !!p;
|
||||
},
|
||||
trace: function(expr, val, path) {
|
||||
if (expr !== "") {
|
||||
var x = expr.split(";"), loc = x.shift();
|
||||
x = x.join(";");
|
||||
if (val && val.hasOwnProperty(loc))
|
||||
P.trace(x, val[loc], path + ";" + loc);
|
||||
else if (loc === "*")
|
||||
P.walk(loc, x, val, path, function(m,l,x,v,p) { P.trace(m+";"+x,v,p); });
|
||||
else if (loc === "..") {
|
||||
P.trace(x, val, path);
|
||||
P.walk(loc, x, val, path, function(m,l,x,v,p) { typeof v[m] === "object" && P.trace("..;"+x,v[m],p+";"+m); });
|
||||
}
|
||||
else if (/^\(.*?\)$/.test(loc)) // [(expr)]
|
||||
P.trace(P.eval(loc, val, path.substr(path.lastIndexOf(";")+1))+";"+x, val, path);
|
||||
else if (/^\?\(.*?\)$/.test(loc)) // [?(expr)]
|
||||
P.walk(loc, x, val, path, function(m,l,x,v,p) { if (P.eval(l.replace(/^\?\((.*?)\)$/,"$1"), v instanceof Array ? v[m] : v, m)) P.trace(m+";"+x,v,p); }); // issue 5 resolved
|
||||
else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) // [start:end:step] phyton slice syntax
|
||||
P.slice(loc, x, val, path);
|
||||
else if (/,/.test(loc)) { // [name1,name2,...]
|
||||
for (var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++)
|
||||
P.trace(s[i]+";"+x, val, path);
|
||||
}
|
||||
}
|
||||
else
|
||||
P.store(path, val);
|
||||
},
|
||||
walk: function(loc, expr, val, path, f) {
|
||||
if (val instanceof Array) {
|
||||
for (var i=0,n=val.length; i<n; i++)
|
||||
if (i in val)
|
||||
f(i,loc,expr,val,path);
|
||||
}
|
||||
else if (typeof val === "object") {
|
||||
for (var m in val)
|
||||
if (val.hasOwnProperty(m))
|
||||
f(m,loc,expr,val,path);
|
||||
}
|
||||
},
|
||||
slice: function(loc, expr, val, path) {
|
||||
if (val instanceof Array) {
|
||||
var len=val.length, start=0, end=len, step=1;
|
||||
loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, function($0,$1,$2,$3){start=parseInt($1||start);end=parseInt($2||end);step=parseInt($3||step);});
|
||||
start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start);
|
||||
end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end);
|
||||
for (var i=start; i<end; i+=step)
|
||||
P.trace(i+";"+expr, val, path);
|
||||
}
|
||||
},
|
||||
eval: function(x, _v, _vname) {
|
||||
try { return $ && _v && eval(x.replace(/(^|[^\\])@/g, "$1_v").replace(/\\@/g, "@")); } // issue 7 : resolved ..
|
||||
catch(e) { throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/(^|[^\\])@/g, "$1_v").replace(/\\@/g, "@")); } // issue 7 : resolved ..
|
||||
}
|
||||
};
|
||||
|
||||
var $ = obj;
|
||||
if (expr && obj && (P.resultType == "VALUE" || P.resultType == "PATH")) {
|
||||
P.trace(P.normalize(expr).replace(/^\$;?/,""), obj, "$"); // issue 6 resolved
|
||||
return P.result.length ? P.result : false;
|
||||
}
|
||||
}
|
51
qml/pages/JSONListModel.qml
Normal file
51
qml/pages/JSONListModel.qml
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* JSONListModel - a QML ListModel with JSON and JSONPath support
|
||||
*
|
||||
* Copyright (c) 2012 Romain Pokrzywka (KDAB) (romain@kdab.com)
|
||||
* Licensed under the MIT licence (http://opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import "../lib/jsonpath.js" as JSONPath
|
||||
|
||||
Item {
|
||||
property string source: ""
|
||||
property string json: ""
|
||||
property string query: ""
|
||||
|
||||
property ListModel model : ListModel { id: jsonModel }
|
||||
property alias count: jsonModel.count
|
||||
|
||||
onSourceChanged: {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open("GET", source);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE)
|
||||
json = xhr.responseText;
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
onJsonChanged: updateJSONModel()
|
||||
onQueryChanged: updateJSONModel()
|
||||
|
||||
function updateJSONModel() {
|
||||
jsonModel.clear();
|
||||
|
||||
if ( json === "" )
|
||||
return;
|
||||
|
||||
var objectArray = parseJSONString(json, query);
|
||||
for ( var key in objectArray ) {
|
||||
var jo = objectArray[key];
|
||||
jsonModel.append( jo );
|
||||
}
|
||||
}
|
||||
|
||||
function parseJSONString(jsonString, jsonPathQuery) {
|
||||
var objectArray = JSON.parse(jsonString);
|
||||
if ( jsonPathQuery !== "" )
|
||||
objectArray = JSONPath.jsonPath(objectArray, jsonPathQuery);
|
||||
|
||||
return objectArray;
|
||||
}
|
||||
}
|
188
qml/pages/LoginPage.qml
Normal file
188
qml/pages/LoginPage.qml
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
Copyright (C) 2013 Jolla Ltd.
|
||||
Contact: Thomas Perl <thomas.perl@jollamobile.com>
|
||||
All rights reserved.
|
||||
|
||||
You may use this file under the terms of BSD license as follows:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Jolla Ltd nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtWebKit 3.0
|
||||
import Sailfish.Silica 1.0
|
||||
import "../lib/API.js" as Logic
|
||||
|
||||
|
||||
|
||||
Page {
|
||||
id: loginPage
|
||||
|
||||
// The effective value will be restricted by ApplicationWindow.allowedOrientations
|
||||
allowedOrientations: Orientation.All
|
||||
|
||||
|
||||
|
||||
SilicaFlickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: column.height + Theme.paddingLarge
|
||||
|
||||
VerticalScrollDecorator {}
|
||||
|
||||
Column {
|
||||
id: column
|
||||
width: parent.width
|
||||
|
||||
PageHeader { title: "Login" }
|
||||
|
||||
SectionHeader {
|
||||
text: "Instance"
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: instance
|
||||
focus: true
|
||||
label: "Enter the name mastodon instance"
|
||||
placeholderText: label
|
||||
text: "https://mastodon.social"
|
||||
width: parent.width
|
||||
EnterKey.iconSource: "image://theme/icon-m-enter-next"
|
||||
EnterKey.onClicked: {
|
||||
Logic.api = new Logic.MastodonAPI({ instance: instance.text, api_user_token: "" });
|
||||
Logic.api.registerApplication("Tooter",
|
||||
'http://localhost/harbour-tooter', // redirect uri, we will need this later on
|
||||
["read", "write", "follow"], //scopes
|
||||
"http://grave-design.com/harbour-tooter", //website on the login screen
|
||||
function(data) {
|
||||
|
||||
console.log(data)
|
||||
var conf = JSON.parse(data)
|
||||
conf.instance = instance.text;
|
||||
conf.login = false;
|
||||
|
||||
|
||||
/*conf['login'] = false;
|
||||
conf['mastodon_client_id'] = data['mastodon_client_id'];
|
||||
conf['mastodon_client_secret'] = data['mastodon_client_secret'];
|
||||
conf['mastodon_client_redirect_uri'] = data['mastodon_client_redirect_uri'];
|
||||
delete Logic.conf;*/
|
||||
Logic.conf = conf;
|
||||
console.log(JSON.stringify(conf))
|
||||
console.log(JSON.stringify(Logic.conf))
|
||||
// we got our application
|
||||
|
||||
// our user to it!
|
||||
var url = Logic.api.generateAuthLink(Logic.conf["client_id"],
|
||||
Logic.conf["redirect_uri"],
|
||||
"code", // oauth method
|
||||
["read", "write", "follow"] //scopes
|
||||
);
|
||||
console.log(url)
|
||||
webView.url = url
|
||||
webView.visible = true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Label {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: Theme.paddingLarge
|
||||
rightMargin: Theme.paddingLarge
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
color: Theme.secondaryHighlightColor
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
text: "Mastodon is a free, open-source social network. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Pick a server that you trust — whichever you choose, you can interact with everyone else. Anyone can run their own Mastodon instance and participate in the social network seamlessly."
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SilicaWebView {
|
||||
id: webView
|
||||
visible: false
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
opacity: 0
|
||||
onLoadingChanged: {
|
||||
console.log(url)
|
||||
if ((url+"").substr(0, 37) === 'http://localhost/harbour-tooter?code=') {
|
||||
visible = false;
|
||||
var authCode = (url+"").substr(37)
|
||||
console.log(authCode)
|
||||
|
||||
Logic.api.getAccessTokenFromAuthCode(
|
||||
Logic.conf["client_id"],
|
||||
Logic.conf["client_secret"],
|
||||
Logic.conf["redirect_uri"],
|
||||
authCode,
|
||||
function(data) {
|
||||
// AAAND DATA CONTAINS OUR TOKEN!
|
||||
console.log(data)
|
||||
data = JSON.parse(data)
|
||||
console.log(JSON.stringify(data))
|
||||
console.log(JSON.stringify(data.access_token))
|
||||
Logic.conf["api_user_token"] = data.access_token
|
||||
Logic.conf["login"] = true;
|
||||
Logic.api.setConfig("api_user_token", Logic.conf["api_user_token"])
|
||||
pageStack.replace(Qt.resolvedUrl("MainPage.qml"), {})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
switch (loadRequest.status)
|
||||
{
|
||||
case WebView.LoadSucceededStatus:
|
||||
opacity = 1
|
||||
break
|
||||
case WebView.LoadFailedStatus:
|
||||
//opacity = 0
|
||||
break
|
||||
default:
|
||||
//opacity = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
FadeAnimation on opacity {}
|
||||
PullDownMenu {
|
||||
MenuItem {
|
||||
text: "Reload"
|
||||
onClicked: webView.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ import "../lib/API.js" as Logic
|
|||
|
||||
|
||||
Page {
|
||||
id: page
|
||||
id: mainPage
|
||||
|
||||
// The effective value will be restricted by ApplicationWindow.allowedOrientations
|
||||
allowedOrientations: Orientation.All
|
||||
|
@ -43,16 +43,28 @@ Page {
|
|||
SilicaFlickable {
|
||||
anchors.fill: parent
|
||||
|
||||
PageHeader {
|
||||
title: "Tooter"
|
||||
}
|
||||
|
||||
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
|
||||
PullDownMenu {
|
||||
MenuItem {
|
||||
text: qsTrId("Set demo conf")
|
||||
text: Logic.conf['login'] ? qsTrId("Logout"): qsTrId("Login")
|
||||
onClicked: {
|
||||
Logic.conf['login'] = true
|
||||
Logic.conf['instance'] = "https://mastodon.social";
|
||||
Logic.conf['api_user_token'] = '6d8cb23e3ebf3c7a97dd9adf204e47ad159f1a3d07dbbd0325e98981368d8c51';
|
||||
if (Logic.conf['login']) {
|
||||
Logic.conf['login'] = false
|
||||
Logic.conf['instance'] = null;
|
||||
Logic.conf['api_user_token'] = null;
|
||||
Logic.conf['dysko'] = null;
|
||||
} else {
|
||||
Logic.conf['login'] = true
|
||||
Logic.conf['instance'] = "https://mastodon.social";
|
||||
Logic.conf['api_user_token'] = '6d8cb23e3ebf3c7a97dd9adf204e47ad159f1a3d07dbbd0325e98981368d8c51';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Show Page 2")
|
||||
onClicked: pageStack.push(Qt.resolvedUrl("SecondPage.qml"))
|
||||
|
@ -60,13 +72,7 @@ Page {
|
|||
}
|
||||
|
||||
|
||||
MyList {
|
||||
id: myList
|
||||
anchors.fill: parent
|
||||
model: ListModel {
|
||||
id: model
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
@ -76,37 +82,8 @@ Page {
|
|||
// data is the http response object
|
||||
//sidenote: please do not actually execute this request, you could be bullied by your friends
|
||||
});*/
|
||||
var tootParser = function(data){
|
||||
console.log(data)
|
||||
var ret = {};
|
||||
ret.id = data.id
|
||||
ret.content = data.content
|
||||
ret.created_at = data.created_at
|
||||
ret.in_reply_to_account_id = data.in_reply_to_account_id
|
||||
ret.in_reply_to_id = data.in_reply_to_id
|
||||
|
||||
ret.user_id = data.account.id
|
||||
ret.user_locked = data.account.locked
|
||||
ret.username = data.account.username
|
||||
ret.display_name = data.account.display_name
|
||||
ret.avatar_static = data.account.avatar_static
|
||||
|
||||
|
||||
ret.favourited = data.favourited ? true : false
|
||||
ret.favourites_count = data.favourites_count ? data.favourites_count : 0
|
||||
|
||||
ret.reblog = data.reblog ? true : false
|
||||
ret.reblogged = data.reblogged ? true : false
|
||||
ret.reblogs_count = data.reblogs_count ? data.reblogs_count : false
|
||||
|
||||
ret.muted = data.muted ? true : false
|
||||
ret.sensitive = data.sensitive ? true : false
|
||||
ret.visibility = data.visibility ? data.visibility : false
|
||||
ret.section = (new Date(ret.created_at)).toLocaleDateString()
|
||||
console.log(ret)
|
||||
return ret;
|
||||
}
|
||||
Logic.api.get("timelines/home", [
|
||||
/*Logic.api.get("timelines/home", [
|
||||
//["since_id", 420],
|
||||
//["max_id", 1337]
|
||||
], function(data) {
|
||||
|
@ -115,12 +92,11 @@ Page {
|
|||
//model.append(data)
|
||||
for (var i in data) {
|
||||
if (data.hasOwnProperty(i)) {
|
||||
var toot = tootParser(data[i])
|
||||
model.append(toot)
|
||||
console.log(JSON.stringify(data[i]))
|
||||
}
|
||||
}
|
||||
console.log(model.count)
|
||||
});
|
||||
|
||||
});*/
|
||||
console.log(Logic.test)
|
||||
}
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
|
||||
|
||||
SilicaListView {
|
||||
id: myList
|
||||
property var locale: Qt.locale()
|
||||
property bool loadStarted : false;
|
||||
property int scrollOffset;
|
||||
property string action: ""
|
||||
property variant vars
|
||||
property variant conf
|
||||
|
||||
signal notify (string what, int num)
|
||||
onNotify: {
|
||||
console.log(what + " - " + num)
|
||||
}
|
||||
|
||||
signal openDrawer (bool setDrawer)
|
||||
onOpenDrawer: {
|
||||
//console.log("Open drawer: " + setDrawer)
|
||||
}
|
||||
signal send (string notice)
|
||||
onSend: {
|
||||
console.log("LIST send signal emitted with notice: " + notice)
|
||||
}
|
||||
BusyIndicator {
|
||||
size: BusyIndicatorSize.Large
|
||||
running: myList.model.count === 0 && !viewPlaceHolder.visible
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
WorkerScript {
|
||||
id: worker
|
||||
source: "../../lib/Worker.js"
|
||||
onMessage: {
|
||||
if (messageObject.error){
|
||||
viewPlaceHolder.visible = true;
|
||||
viewPlaceHolder.text = "Error"
|
||||
viewPlaceHolder.hintText = messageObject.message
|
||||
console.log(JSON.stringify(messageObject))
|
||||
}
|
||||
if (messageObject.notifyNewItems){
|
||||
console.log(JSON.stringify(messageObject.notifyNewItems))
|
||||
notify(action, messageObject.notifyNewItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
interval: 5*60*1000;
|
||||
running: true;
|
||||
repeat: true
|
||||
onTriggered: loadData("prepend")
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var msg = {
|
||||
'bgAction' : action,
|
||||
'params' : vars,
|
||||
'model' : model,
|
||||
'conf' : conf
|
||||
};
|
||||
worker.sendMessage(msg);
|
||||
}
|
||||
|
||||
function loadData(mode){
|
||||
var msg = {
|
||||
'bgAction' : action,
|
||||
'params' : vars,
|
||||
'model' : model,
|
||||
'mode' : mode,
|
||||
'conf' : conf
|
||||
};
|
||||
worker.sendMessage(msg);
|
||||
}
|
||||
|
||||
ViewPlaceholder {
|
||||
id: viewPlaceHolder
|
||||
enabled: model.count === 0
|
||||
text: ""
|
||||
hintText: ""
|
||||
}
|
||||
|
||||
PullDownMenu {
|
||||
MenuItem {
|
||||
text: qsTr("Settings")
|
||||
onClicked: pageStack.push(Qt.resolvedUrl("../Settings.qml"))
|
||||
}
|
||||
MenuItem {
|
||||
visible: action === 'statuses_userTimeline'
|
||||
text: (following ? "Unfollow" : "Follow")
|
||||
onClicked: {
|
||||
var msg = { 'action': following ? "friendships_destroy" : "friendships_create", 'screen_name': username, 'conf' : conf
|
||||
};
|
||||
worker.sendMessage(msg);
|
||||
following = !following
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("Load more")
|
||||
onClicked: {
|
||||
loadData("prepend")
|
||||
}
|
||||
}
|
||||
}
|
||||
PushUpMenu {
|
||||
MenuItem {
|
||||
text: qsTr("Load more")
|
||||
onClicked: {
|
||||
loadData("append")
|
||||
}
|
||||
}
|
||||
}
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
clip: true
|
||||
section {
|
||||
property: 'section'
|
||||
criteria: ViewSection.FullString
|
||||
delegate: SectionHeader {
|
||||
text: {
|
||||
var dat = Date.fromLocaleDateString(locale, section);
|
||||
dat = Format.formatDate(dat, Formatter.TimepointRelativeCurrentDay)
|
||||
if (dat === "00:00:00" || dat === "00:00") {
|
||||
visible = false;
|
||||
height = 0;
|
||||
return " ";
|
||||
}else {
|
||||
return dat;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Tweet {
|
||||
onSend: {
|
||||
myList.send(notice)
|
||||
}
|
||||
}
|
||||
add: Transition {
|
||||
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 800 }
|
||||
NumberAnimation { property: "x"; duration: 800; easing.type: Easing.InOutBack }
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; duration: 800; easing.type: Easing.InOutBack }
|
||||
}
|
||||
|
||||
onCountChanged: {
|
||||
contentY = scrollOffset
|
||||
console.log("CountChanged!")
|
||||
|
||||
//last_id_MN
|
||||
|
||||
}
|
||||
onContentYChanged: {
|
||||
|
||||
if (contentY > scrollOffset) {
|
||||
openDrawer(false)
|
||||
|
||||
} else {
|
||||
if (contentY < 100 && !loadStarted){
|
||||
}
|
||||
openDrawer(true)
|
||||
}
|
||||
scrollOffset = contentY
|
||||
}
|
||||
VerticalScrollDecorator {}
|
||||
|
||||
}
|
|
@ -1,192 +0,0 @@
|
|||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
BackgroundItem {
|
||||
signal send (string notice)
|
||||
|
||||
id: delegate
|
||||
//property string text: "0"
|
||||
width: parent.width
|
||||
signal navigateTo(string link)
|
||||
height: lblText.paintedHeight + (lblText.text.length > 0 ? Theme.paddingLarge : 0 )+ lblName.paintedHeight + lblScreenName.paintedHeight + (reblog ? Theme.paddingLarge + iconRT.height : 0)
|
||||
Image {
|
||||
id: iconRT
|
||||
y: Theme.paddingLarge
|
||||
anchors {
|
||||
right: avatar.right
|
||||
}
|
||||
visible: reblog
|
||||
width: Theme.iconSizeExtraSmall
|
||||
height: width
|
||||
source: "image://theme/icon-s-retweet?" + (pressed ? Theme.primaryColor : Theme.secondaryColor)
|
||||
}
|
||||
Label {
|
||||
id: lblRtByName
|
||||
visible: reblog
|
||||
anchors {
|
||||
left: lblName.left
|
||||
bottom: iconRT.bottom
|
||||
}
|
||||
text: 'retweeted by @' + retweetScreenName
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
color: Theme.secondaryColor
|
||||
}
|
||||
|
||||
Image {
|
||||
id: avatar
|
||||
x: Theme.horizontalPageMargin
|
||||
y: Theme.paddingLarge + (isRetweet ? iconRT.height+Theme.paddingMedium : 0)
|
||||
asynchronous: true
|
||||
width: Theme.iconSizeMedium
|
||||
height: width
|
||||
smooth: true
|
||||
source: avatar_static
|
||||
visible: true
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
|
||||
"name": name,
|
||||
"username": screenName,
|
||||
"profileImage": profileImageUrl
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Label {
|
||||
id: lblName
|
||||
anchors {
|
||||
top: avatar.top
|
||||
topMargin: 0
|
||||
left: avatar.right
|
||||
leftMargin: Theme.paddingMedium
|
||||
}
|
||||
text: username
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
|
||||
}
|
||||
|
||||
Image {
|
||||
id: iconVerified
|
||||
y: Theme.paddingLarge
|
||||
anchors {
|
||||
left: lblName.right
|
||||
leftMargin: Theme.paddingSmall
|
||||
verticalCenter: lblName.verticalCenter
|
||||
}
|
||||
visible: isVerified
|
||||
width: isVerified ? Theme.iconSizeExtraSmall*0.8 : 0
|
||||
opacity: 0.8
|
||||
height: width
|
||||
source: "../../verified.svg"
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: iconVerified
|
||||
source: iconVerified
|
||||
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
|
||||
}
|
||||
|
||||
Label {
|
||||
id: lblScreenName
|
||||
anchors {
|
||||
left: iconVerified.right
|
||||
right: lblDate.left
|
||||
leftMargin: Theme.paddingMedium
|
||||
baseline: lblName.baseline
|
||||
}
|
||||
truncationMode: TruncationMode.Fade
|
||||
text: '@'+display_name
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
color: (pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor)
|
||||
}
|
||||
Label {
|
||||
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
|
||||
horizontalAlignment: Text.AlignRight
|
||||
anchors {
|
||||
right: parent.right
|
||||
baseline: lblName.baseline
|
||||
rightMargin: Theme.paddingLarge
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: lblText
|
||||
anchors {
|
||||
left: lblName.left
|
||||
right: parent.right
|
||||
top: lblScreenName.bottom
|
||||
topMargin: Theme.paddingSmall
|
||||
rightMargin: Theme.paddingLarge
|
||||
}
|
||||
height: content.length ? paintedHeight : 0
|
||||
//text: (highlights.length > 0 ? Theme.highlightText(plainText, new RegExp(highlights, "igm"), Theme.highlightColor) : plainText)
|
||||
//textFormat:Text.RichText
|
||||
onLinkActivated: {
|
||||
console.log(link)
|
||||
if (link[0] === "@") {
|
||||
pageStack.push(Qt.resolvedUrl("../Profile.qml"), {
|
||||
"name": "",
|
||||
"username": link.substring(1),
|
||||
"profileImage": ""
|
||||
})
|
||||
} else if (link[0] === "#") {
|
||||
|
||||
pageStack.pop(pageStack.find(function(page) {
|
||||
var check = page.isFirstPage === true;
|
||||
if (check)
|
||||
page.onLinkActivated(link)
|
||||
return check;
|
||||
}));
|
||||
|
||||
send(link)
|
||||
} else {
|
||||
pageStack.push(Qt.resolvedUrl("../Browser.qml"), {"href" : link})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
text: content
|
||||
textFormat:Text.RichText
|
||||
linkColor : Theme.highlightColor
|
||||
wrapMode: Text.Wrap
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: (pressed ? Theme.highlightColor : Theme.primaryColor)
|
||||
}
|
||||
|
||||
/*MediaBlock {
|
||||
id: mediaImg
|
||||
anchors {
|
||||
left: lblName.left
|
||||
right: parent.right
|
||||
top: lblText.bottom
|
||||
topMargin: Theme.paddingSmall
|
||||
rightMargin: Theme.paddingLarge
|
||||
}
|
||||
model: (media ? media : '')
|
||||
width: lblDate.x - lblName.x- Theme.paddingLarge
|
||||
height: 100
|
||||
}
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("../TweetDetails.qml"), {
|
||||
"tweets": myList.model,
|
||||
"screenName": screenName,
|
||||
"selected": index
|
||||
})
|
||||
}*/
|
||||
|
||||
}
|
|
@ -3,27 +3,20 @@
|
|||
<TS version="2.1">
|
||||
<context>
|
||||
<name></name>
|
||||
<message id="Set demo conf">
|
||||
<message id="Logout">
|
||||
<source></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message id="Login">
|
||||
<source></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FirstPage</name>
|
||||
<name>MainPage</name>
|
||||
<message>
|
||||
<source>Show Page 2</source>
|
||||
<translation>Zur Seite 2</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MyList</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Load more</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation type="unfinished">Zur Seite 2</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
|
@ -3,29 +3,22 @@
|
|||
<TS version="2.1">
|
||||
<context>
|
||||
<name></name>
|
||||
<message id="Set demo conf">
|
||||
<message id="Logout">
|
||||
<source></source>
|
||||
<translation type="unfinished">Tooter</translation>
|
||||
</message>
|
||||
<message id="Login">
|
||||
<source></source>
|
||||
<translation type="unfinished">Tooter</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FirstPage</name>
|
||||
<name>MainPage</name>
|
||||
<message>
|
||||
<source>Show Page 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MyList</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Load more</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SecondPage</name>
|
||||
<message>
|
||||
|
|
Loading…
Reference in a new issue