diff --git a/harbour-tooterb.pro b/harbour-tooterb.pro index 1b3c051..cf3b679 100644 --- a/harbour-tooterb.pro +++ b/harbour-tooterb.pro @@ -14,9 +14,9 @@ TARGET = harbour-tooterb CONFIG += sailfishapp QT += network dbus sql +QT += multimedia CONFIG += link_pkgconfig -PKGCONFIG += sailfishapp -PKGCONFIG += \ +PKGCONFIG += sailfishapp \ nemonotifications-qt5 DEFINES += "APPVERSION=\\\"$${SPECVERSION}\\\"" @@ -58,16 +58,16 @@ DISTFILES += qml/harbour-tooterb.qml \ qml/pages/SettingsPage.qml \ qml/pages/components/InfoBanner.qml \ qml/pages/components/MediaFullScreen.qml \ + qml/pages/components/MyMedia.qml \ + qml/pages/components/NavigationPanel.qml \ qml/pages/components/ProfileImage.qml \ qml/pages/components/VisualContainer.qml \ qml/pages/components/MiniStatus.qml \ qml/pages/components/MiniHeader.qml \ qml/pages/components/ItemUser.qml \ qml/pages/components/MyList.qml \ - qml/pages/components/Navigation.qml \ qml/pages/components/ProfileHeader.qml \ qml/pages/components/MediaBlock.qml \ - qml/pages/components/MyImage.qml \ qml/cover/CoverPage.qml \ qml/pages/MainPage.qml \ qml/pages/LoginPage.qml \ diff --git a/qml/harbour-tooterb.qml b/qml/harbour-tooterb.qml index b50b096..60e8399 100644 --- a/qml/harbour-tooterb.qml +++ b/qml/harbour-tooterb.qml @@ -87,5 +87,4 @@ ApplicationWindow { activate() } } - } diff --git a/qml/images/icon-s-bookmark.svg b/qml/images/icon-s-bookmark.svg index 6a7cba2..f05bf8a 100644 --- a/qml/images/icon-s-bookmark.svg +++ b/qml/images/icon-s-bookmark.svg @@ -2,8 +2,6 @@ icon-s-bookmark - - - + diff --git a/qml/lib/API.js b/qml/lib/API.js index ba90d18..cfc6fa8 100644 --- a/qml/lib/API.js +++ b/qml/lib/API.js @@ -9,6 +9,7 @@ var mediator = (function(){ mediator.channels[channel].push({ context : this, callback : fn }); return this; }; + var publish = function(channel){ if(!mediator.channels[channel]) return false; var args = Array.prototype.slice.call(arguments, 1); @@ -18,6 +19,7 @@ var mediator = (function(){ }; return this; }; + return { channels : {}, publish : publish, @@ -28,6 +30,7 @@ var mediator = (function(){ } }; }()); + var init = function(){ console.log("db.version: "+db.version); if(db.version === '') { @@ -35,7 +38,7 @@ var init = function(){ tx.executeSql('CREATE TABLE IF NOT EXISTS settings (' + ' key TEXT UNIQUE, ' + ' value TEXT ' - +');'); + + ');'); //tx.executeSql('INSERT INTO settings (key, value) VALUES (?, ?)', ["conf", "{}"]); }); db.changeVersion('', '0.1', function(tx) { @@ -103,6 +106,7 @@ var tootParser = function(data){ console.log(ret) } + var test = 1; Qt.include("Mastodon.js") @@ -161,6 +165,7 @@ var notifier = function(item){ key: item.id } break; + case "follow": msg = { urgency: "critical", @@ -182,6 +187,7 @@ var notifier = function(item){ key: item.id } break; + case "mention": msg = { urgency: "critical", @@ -193,6 +199,7 @@ var notifier = function(item){ key: item.id } break; + default: //console.log(JSON.stringify(messageObject.data)) return; diff --git a/qml/lib/Mastodon.js b/qml/lib/Mastodon.js index 55265be..97b5bcc 100644 --- a/qml/lib/Mastodon.js +++ b/qml/lib/Mastodon.js @@ -10,10 +10,12 @@ var mastodonAPI = function(config) { // modify initial config afterwards config[key] = value; }, + getConfig: function(key) { //get config key return config[key]; }, + get: function (endpoint) { // for GET API calls // can be called with two or three parameters @@ -67,6 +69,7 @@ var mastodonAPI = function(config) { } http.send(); }, + post: function (endpoint) { // for POST API calls var postData, callback; @@ -113,6 +116,7 @@ var mastodonAPI = function(config) { } });*/ }, + delete: function (endpoint, callback) { // for DELETE API calls. $.ajax({ @@ -125,6 +129,7 @@ var mastodonAPI = function(config) { } }); }, + stream: function (streamType, onData) { // Event Stream Support // websocket streaming is undocumented. i had to reverse engineer the fucking web client. @@ -132,7 +137,7 @@ var mastodonAPI = function(config) { // user for your local home TL and notifications // public for your federated TL // public:local for your home TL - // hashtag&tag=fuckdonaldtrump for the stream of #fuckdonaldtrump + // hashtag&tag=mastodonrocks for the stream of #mastodonrocks // callback gets called whenever new data ist recieved // callback { event: (eventtype), payload: {mastodon object as described in the api docs} } // eventtype could be notification (=notification) or update (= new toot in TL) @@ -147,12 +152,10 @@ var mastodonAPI = function(config) { onData(event); }; es.onmessage = listener; - - }, + registerApplication: function (client_name, redirect_uri, scopes, website, callback) { //register a new application - // OAuth Auth flow: // First register the application // 2) get a access code from a user (using the link, generation function below!) @@ -191,10 +194,12 @@ var mastodonAPI = function(config) { } 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({ url: config.instance + "/oauth/token", diff --git a/qml/lib/Worker.js b/qml/lib/Worker.js index 268c024..1373fb0 100644 --- a/qml/lib/Worker.js +++ b/qml/lib/Worker.js @@ -10,7 +10,7 @@ WorkerScript.onMessage = function(msg) { console.log("Conf > " + JSON.stringify(msg.conf)) console.log("Params > " + JSON.stringify(msg.params)) - // order notifications in ASC order + /** order notifications in ASC order */ function orderNotifications(items){ for (var i = items.length-1; i > 0; i--) { if (items[i].id > 0 ) //msg.conf.notificationLastID) @@ -18,14 +18,17 @@ WorkerScript.onMessage = function(msg) { } } + /** Logged-in status */ if (!msg.conf || !msg.conf.login) { console.log("Not loggedin") return; } + /** Load images */ if (typeof msg.conf['loadImages'] !== "undefined") loadImages = msg.conf['loadImages'] + /** POST statuses */ 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) { @@ -63,7 +66,7 @@ WorkerScript.onMessage = function(msg) { } else if(msg.action === "notifications") { // notification - // console.log("Is notification... parsing...") + console.log("Get notification list") console.log(JSON.stringify(data[i])) item = parseNotification(data[i]); items.push(item) @@ -73,7 +76,9 @@ WorkerScript.onMessage = function(msg) { console.log("ancestors") for (var j = 0; j < data[i].length; j ++) { item = parseToot(data[i][j]); - item['id'] = item['status_id'] + item['id'] = item['status_id']; + if (typeof item['attachments'] === "undefined") + item['attachments'] = []; items.push(item) console.log(JSON.stringify(data[i][j])) } @@ -82,7 +87,7 @@ WorkerScript.onMessage = function(msg) { //console.log(JSON.stringify(i)) } else if(msg.action.indexOf("statuses") >-1 && msg.action.indexOf("context") >-1 && i === "descendants") { - // status ancestors toots - conversation + // status descendants toots - conversation console.log("descendants") for (var j = 0; j < data[i].length; j ++) { item = parseToot(data[i][j]); @@ -94,16 +99,19 @@ WorkerScript.onMessage = function(msg) { } addDataToModel (msg.model, "append", items); items = []; + } else if (data[i].hasOwnProperty("content")){ - // console.log("Is toot... parsing...") + //console.log("Get Toot") item = parseToot(data[i]); item['id'] = item['status_id'] items.push(item) + } else { WorkerScript.sendMessage({ 'action': msg.action, 'success': true, key: i, "data": data[i] }) } } } + if(msg.model && items.length) addDataToModel(msg.model, msg.mode, items) /*if(msg.action === "notifications") @@ -123,11 +131,10 @@ function addDataToModel (model, mode, items) { model.insert(0,items[i]) } } - model.sync() } -// Get Account Data: Represents a user of Mastodon and their associated profile. +/** Function: Get Account Data */ function parseAccounts(collection, prefix, data) { var res = collection; @@ -153,13 +160,12 @@ function parseAccounts(collection, prefix, data) { //res[prefix + 'account_fields'] = data["fields"] res[prefix + 'account_bot'] = data["bot"] res[prefix + 'account_group'] = data["group"] - res[prefix + 'account_source'] = data["source"] //console.log(JSON.stringify(res)) return (res); } -// Get Notification Data +/** Function: Get Notification Data */ function parseNotification(data){ //console.log(JSON.stringify(data)) var item = { @@ -168,12 +174,12 @@ function parseNotification(data){ attachments: [] }; switch (item['type']){ + case "mention": if (!data.status) { break; } item = parseToot(data.status) - item['typeIcon'] = "image://theme/icon-s-retweet" item['typeIcon'] = "image://theme/icon-s-alarm" item['type'] = "mention" break; @@ -197,19 +203,18 @@ function parseNotification(data){ item = parseToot(data.status) item = parseAccounts(item, "reblog_", data["account"]) item = parseAccounts(item, "", data["status"]["account"]) - item['status_reblog'] = true; + item['status_reblog'] = true + item['type'] = "favourite" item['typeIcon'] = "image://theme/icon-s-favorite" - item['type'] = "favourite"; - //item['retweetScreenName'] = item['reblog_account_username']; break; case "follow": item['type'] = "follow"; item = parseAccounts(item, "", data["account"]) item = parseAccounts(item, "reblog_", data["account"]) - item['content'] = data['account']['note'] + //item['content'] = data['account']['note'] item['typeIcon'] = "../../images/icon-s-follow.svg" - item['attachments'] = [] + //item['attachments'] = [] break; default: @@ -222,6 +227,7 @@ function parseNotification(data){ return item; } +/** Function: */ function collect() { var ret = {}; var len = arguments.length; @@ -235,12 +241,13 @@ function collect() { return ret; } +/** Function: Get Status date */ function getDate(dateStr) { var ts = new Date(dateStr); return new Date(ts.getFullYear(), ts.getMonth(), ts.getDate(), 0, 0, 0) } -// Get Status / Toot Data +/** Function: Get Status data */ function parseToot (data) { var i = 0; var item = {}; @@ -253,7 +260,6 @@ function parseToot (data) { item['status_spoiler_text'] = data["spoiler_text"] item['status_visibility'] = data["visibility"] item['status_language'] = data["language"] - item['status_uri'] = data["uri"] item['status_url'] = data["url"] item['status_replies_count'] = data["replies_count"] @@ -262,34 +268,39 @@ function parseToot (data) { item['status_favourited'] = data["favourited"] item['status_reblogged'] = data["reblogged"] item['status_bookmarked'] = data["bookmarked"] - item['status_content'] = data["content"] + item['attachments'] = data['media_attachments'] item['status_in_reply_to_id'] = data["in_reply_to_id"] item['status_in_reply_to_account_id'] = data["in_reply_to_account_id"] item['status_reblog'] = data["reblog"] ? true : false item['section'] = getDate(data["created_at"]) - // If Toot is a Reblog + /** If Toot is a Reblog */ if(item['status_reblog']) { item['type'] = "reblog"; item['typeIcon'] = "image://theme/icon-s-retweet" - item['status_id'] = data["reblog"]["id"]; - item['status_spoiler_text'] = data["reblog"]["spoiler_text"] + item['status_id'] = data["reblog"]["id"] item['status_sensitive'] = data["reblog"]["sensitive"] + item['status_spoiler_text'] = data["reblog"]["spoiler_text"] + item['status_replies_count'] = data["reblog"]["replies_count"] + item['status_reblogs_count'] = data["reblog"]["reblogs_count"] + item['status_favourites_count'] = data["reblog"]["favourites_count"] item = parseAccounts(item, "", data['reblog']["account"]) item = parseAccounts(item, "reblog_", data["account"]) } else { item = parseAccounts(item, "", data["account"]) } + + /** Replace HTML content in Toots */ item['content'] = data['content'] .replaceAll('