commit e0b81bf291075622fdb6af337e39667f1f3b1e5f Author: Dusko Angirevic Date: Thu Jun 1 16:13:51 2017 +0200 Init diff --git a/harbour-tooter.desktop b/harbour-tooter.desktop new file mode 100644 index 0000000..f3bdd0e --- /dev/null +++ b/harbour-tooter.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Application +X-Nemo-Application-Type=silica-qt5 +Icon=harbour-tooter +Exec=harbour-tooter +Name=harbour-tooter +# translation example: +# your app name in German locale (de) +# +# Remember to comment out the following line, if you do not want to use +# a different app name in German locale (de). +Name[de]=harbour-tooter diff --git a/harbour-tooter.pro b/harbour-tooter.pro new file mode 100644 index 0000000..af09050 --- /dev/null +++ b/harbour-tooter.pro @@ -0,0 +1,44 @@ +# NOTICE: +# +# Application name defined in TARGET has a corresponding QML filename. +# If name defined in TARGET is changed, the following needs to be done +# to match new name: +# - corresponding QML filename must be changed +# - desktop icon filename must be changed +# - desktop filename must be changed +# - icon definition filename in desktop file must be changed +# - translation filenames have to be changed + +# The name of your application +TARGET = harbour-tooter + +CONFIG += sailfishapp + +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 \ + rpm/harbour-tooter.yaml \ + translations/*.ts \ + harbour-tooter.desktop + +SAILFISHAPP_ICONS = 86x86 108x108 128x128 256x256 + +# to disable building translations every time, comment out the +# following CONFIG line +CONFIG += sailfishapp_i18n + +# German translation is enabled as an example. If you aren't +# planning to localize your app, remember to comment out the +# following TRANSLATIONS line. And also do not forget to +# modify the localized app name in the the .desktop file. +TRANSLATIONS += translations/harbour-tooter-de.ts + +DISTFILES += \ + qml/lib/API.js \ + qml/pages/MyList.qml \ + qml/pages/Tweet.qml diff --git a/harbour-tooter.pro.user b/harbour-tooter.pro.user new file mode 100644 index 0000000..3c95b5c --- /dev/null +++ b/harbour-tooter.pro.user @@ -0,0 +1,801 @@ + + + + + + EnvironmentId + {25497605-1bff-4134-a878-76c1475dd8e3} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + MerSDK-SailfishOS-i486 + MerSDK-SailfishOS-i486 + {f49c1b5a-d715-401a-9a10-0e5fe9e5b72a} + 0 + 2 + 0 + + C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_i486-Debug + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 3 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 2 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_i486-Release + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 3 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 2 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_i486-Profile + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 3 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 2 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + + true + RPM + + QmakeProjectManager.MerRpmBuildStep + + + true + RPM Validation + + QmakeProjectManager.MerRpmValidationStep + + 2 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy By Building An RPM Package + + QmakeProjectManager.MerMb2RpmBuildConfiguration + + + + + true + Prepare Target + + QmakeProjectManager.MerPrepareTargetStep + + + true + Rsync + + QmakeProjectManager.MerRsyncDeployStep + + 2 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy By Copying Binaries + + QmakeProjectManager.MerRSyncDeployConfiguration + + + + + true + Prepare Target + + QmakeProjectManager.MerPrepareTargetStep + + + true + RPM + + QmakeProjectManager.MerRpmDeployStep + + 2 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy As RPM Package + + QmakeProjectManager.MerRpmDeployConfiguration + + 3 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + C:/Users/dysko/SF/harbour-tooter + false + 10234 + 3 + + 1 + + harbour-tooter (on Remote Device) + + QmakeProjectManager.MerRunConfiguration:harbour-tooter + + harbour-tooter + + false + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.Target.1 + + MerSDK-SailfishOS-armv7hl + MerSDK-SailfishOS-armv7hl + {588087e2-ecc1-41aa-b652-86f16cba9351} + 0 + 2 + 0 + + C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Debug + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 3 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 2 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Release + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 3 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 2 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Profile + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 3 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Start SDK + + Mer.MerSdkStartStep + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 2 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + + true + RPM + + QmakeProjectManager.MerRpmBuildStep + + + true + RPM Validation + + QmakeProjectManager.MerRpmValidationStep + + 2 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy By Building An RPM Package + + QmakeProjectManager.MerMb2RpmBuildConfiguration + + + + + true + Prepare Target + + QmakeProjectManager.MerPrepareTargetStep + + + true + Rsync + + QmakeProjectManager.MerRsyncDeployStep + + 2 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy By Copying Binaries + + QmakeProjectManager.MerRSyncDeployConfiguration + + + + + true + Prepare Target + + QmakeProjectManager.MerPrepareTargetStep + + + true + RPM + + QmakeProjectManager.MerRpmDeployStep + + 2 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy As RPM Package + + QmakeProjectManager.MerRpmDeployConfiguration + + 3 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + C:/Users/dysko/SF/harbour-tooter + false + 10234 + 3 + + 1 + + harbour-tooter (on Mer Device) + + QmakeProjectManager.MerRunConfiguration:harbour-tooter + + harbour-tooter + + false + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/icons/108x108/harbour-tooter.png b/icons/108x108/harbour-tooter.png new file mode 100644 index 0000000..ab10628 Binary files /dev/null and b/icons/108x108/harbour-tooter.png differ diff --git a/icons/128x128/harbour-tooter.png b/icons/128x128/harbour-tooter.png new file mode 100644 index 0000000..54375c5 Binary files /dev/null and b/icons/128x128/harbour-tooter.png differ diff --git a/icons/256x256/harbour-tooter.png b/icons/256x256/harbour-tooter.png new file mode 100644 index 0000000..de79583 Binary files /dev/null and b/icons/256x256/harbour-tooter.png differ diff --git a/icons/86x86/harbour-tooter.png b/icons/86x86/harbour-tooter.png new file mode 100644 index 0000000..ad316d6 Binary files /dev/null and b/icons/86x86/harbour-tooter.png differ diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml new file mode 100644 index 0000000..0d08923 --- /dev/null +++ b/qml/cover/CoverPage.qml @@ -0,0 +1,57 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + 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 Sailfish.Silica 1.0 +import "../lib/API.js" as Logic + +CoverBackground { + Label { + id: label + anchors.centerIn: parent + text: Logic.test //qsTr("My Cover") + } + + CoverActionList { + id: coverAction + + CoverAction { + iconSource: "image://theme/icon-cover-next" + onTriggered: { + label.text = Logic.test + } + } + + CoverAction { + iconSource: "image://theme/icon-cover-pause" + } + } +} + diff --git a/qml/harbour-tooter.qml b/qml/harbour-tooter.qml new file mode 100644 index 0000000..9e4ef65 --- /dev/null +++ b/qml/harbour-tooter.qml @@ -0,0 +1,62 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + 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 Sailfish.Silica 1.0 +import "pages" +import "./lib/API.js" as Logic + +ApplicationWindow +{ + //initialPage: Component { FirstPage { } } + cover: Qt.resolvedUrl("cover/CoverPage.qml") + allowedOrientations: defaultAllowedOrientations + Component.onCompleted: { + var obj = {}; + Logic.mediator.installTo(obj); + obj.subscribe('confLoaded', function(){ + console.log('confLoaded'); + console.log(JSON.stringify(Logic.conf)) + if (Logic.conf['instance']) { + Logic.api = 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/FirstPage.qml"), {}) + }); + Logic.init() + } + + Component.onDestruction: { + Logic.saveData() + } +} + diff --git a/qml/lib/API.js b/qml/lib/API.js new file mode 100644 index 0000000..d00dc44 --- /dev/null +++ b/qml/lib/API.js @@ -0,0 +1,318 @@ +.pragma library +.import QtQuick.LocalStorage 2.0 as LS + +var db = LS.LocalStorage.openDatabaseSync("tooter", "", "harbour-tooter", 100000); +var conf = {}; +var mediator = (function(){ + var subscribe = function(channel, fn){ + if(!mediator.channels[channel]) mediator.channels[channel] = []; + 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); + for(var i = 0, l = mediator.channels[channel].length; i < l; i++){ + var subscription = mediator.channels[channel][i]; + subscription.callback.apply(subscription.context.args); + }; + return this; + }; + return { + channels : {}, + publish : publish, + subscribe : subscribe, + installTo : function(obj){ + obj.subscribe = subscribe; + obj.publish = publish; + } + }; +}()); +var init = function(){ + console.log("db.version: "+db.version); + if(db.version === '') { + db.transaction(function(tx) { + 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) { + + }); + } + db.transaction(function(tx) { + var rs = tx.executeSql('SELECT * FROM settings;'); + console.log("READING CONF FROM DB") + for (var i = 0; i < rs.rows.length; i++) { + //var json = JSON.parse(rs.rows.item(i).value); + console.log(rs.rows.item(i).key+" \t > \t "+rs.rows.item(i).value) + conf[rs.rows.item(i).key] = JSON.parse(rs.rows.item(i).value) + } + console.log("END OF READING") + console.log(JSON.stringify(conf)); + mediator.publish('confLoaded', { loaded: true}); + }); +}; + +function saveData() { + 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])]) + } + } + }); +} + +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 + + + console.log(ret) +} + +// by @kirschn@pleasehug.me 2017 +// no fucking copyright +// do whatever you want with it +// but please don't hurt it (and keep this header) +var test = 1; +var MastodonAPI = function(config) { + var apiBase = config.instance + "/api/v1/"; + return { + setConfig: function (key, value) { + // 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 + // endpoint, callback + // or + // endpoint, queryData, callback + // where querydata is an object {["paramname1", "paramvalue1], ["paramname2","paramvalue2"]} + + // variables + var queryData, callback, + queryStringAppend = "?"; + + // check with which arguments we're supplied + if (typeof arguments[1] === "function") { + queryData = {}; + callback = arguments[1]; + } else { + queryData = arguments[1]; + callback = arguments[2]; + } + // build queryData Object into a URL Query String + for (var i in queryData) { + if (queryData.hasOwnProperty(i)) { + if (typeof queryData[i] === "string") { + queryStringAppend += queryData[i] + "&"; + } else if (typeof queryData[i] === "object") { + queryStringAppend += queryData[i].name + "="+ queryData[i].data + "&"; + } + } + } + // ajax function + var http = new XMLHttpRequest() + var url = apiBase + endpoint; + http.open("GET", apiBase + endpoint + queryStringAppend, true); + + // Send the proper header information along with the request + http.setRequestHeader("Authorization", "Bearer " + config.api_user_token); + http.setRequestHeader("Content-Type", "application/json"); + http.setRequestHeader("Connection", "close"); + + http.onreadystatechange = function() { // Call a function when the state changes. + if (http.readyState == 4) { + if (http.status == 200) { + console.log("Successful GET API request to " +apiBase+endpoint); + callback(JSON.parse(http.response),http.status) + } else { + console.log("error: " + http.status) + } + } + } + http.send(); + }, + post: function (endpoint) { + // for POST API calls + var postData, callback; + // check with which arguments we're supplied + if (typeof arguments[1] === "function") { + postData = {}; + callback = arguments[1]; + } else { + postData = arguments[1]; + callback = arguments[2]; + } + + var http = new XMLHttpRequest() + var url = apiBase + endpoint; + var params = JSON.stringify(postData); + http.open("POST", url, true); + + // Send the proper header information along with the request + http.setRequestHeader("Authorization", "Bearer " + config.api_user_token); + http.setRequestHeader("Content-Type", "application/json"); + http.setRequestHeader("Content-length", params.length); + http.setRequestHeader("Connection", "close"); + + http.onreadystatechange = function() { // Call a function when the state changes. + if (http.readyState == 4) { + if (http.status == 200) { + console.log("Successful POST API request to " +apiBase+endpoint); + callback(http.response,http.status) + } else { + console.log("error: " + http.status) + } + } + } + http.send(params); + + /*$.ajax({ + url: apiBase + endpoint, + type: "POST", + data: postData, + headers: {"Authorization": "Bearer " + config.api_user_token}, + success: function(data, textStatus) { + console.log("Successful POST API request to " +apiBase+endpoint); + callback(data,textStatus) + } + });*/ + }, + delete: function (endpoint, callback) { + // for DELETE API calls. + $.ajax({ + url: apiBase + endpoint, + type: "DELETE", + headers: {"Authorization": "Bearer " + config.api_user_token}, + success: function(data, textStatus) { + console.log("Successful DELETE API request to " +apiBase+endpoint); + callback(data,textStatus) + } + }); + }, + stream: function (streamType, onData) { + // Event Stream Support + // websocket streaming is undocumented. i had to reverse engineer the fucking web client. + // streamType is either + // 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 + // 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) + //return "wss://" + apiBase.substr(8) +"streaming?access_token=" + config.api_user_token + "&stream=" + streamType + + var es = new WebSocket("wss://" + apiBase.substr(8) + +"streaming?access_token=" + config.api_user_token + "&stream=" + streamType); + var listener = function (event) { + console.log("Got Data from Stream " + streamType); + event = JSON.parse(event.data); + event.payload = JSON.parse(event.payload); + 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!) + // 3) insert the data you got from the application and the code from the user into + // getAccessTokenFromAuthCode. Note: scopes has to be an array, every time! + // For example ["read", "write"] + + //determine which parameters we got + if (website === null) { + website = ""; + } + // build scope array to string for the api request + var scopeBuild = ""; + 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); + } + }); + }, + 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", + type: "POST", + data: { + client_id: client_id, + client_secret: client_secret, + redirect_uri: redirect_uri, + grant_type: "authorization_code", + code: code + }, + success: function (data, textStatus) { + console.log("Got Token: " + data); + callback(data); + } + }); + } + }; +}; + +// node.js +if (typeof module !== 'undefined') { module.exports = MastodonAPI; }; + + +var api; + +function func() { + console.log(api) +} diff --git a/qml/pages/FirstPage.qml b/qml/pages/FirstPage.qml new file mode 100644 index 0000000..fdfa269 --- /dev/null +++ b/qml/pages/FirstPage.qml @@ -0,0 +1,127 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + 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 Sailfish.Silica 1.0 +import "../lib/API.js" as Logic + + +Page { + id: page + + // The effective value will be restricted by ApplicationWindow.allowedOrientations + allowedOrientations: Orientation.All + + // To enable PullDownMenu, place our content in a SilicaFlickable + SilicaFlickable { + anchors.fill: parent + + // PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView + PullDownMenu { + MenuItem { + text: qsTrId("Set demo conf") + onClicked: { + 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")) + } + } + + + MyList { + id: myList + anchors.fill: parent + model: ListModel { + id: model + } + } + } + + Component.onCompleted: { + /*Mastodon.api.post("statuses", {status:"First toot by Tooter - Mastodon client for #SailfishOS"}, function (data) { + console.log(JSON.stringify(data)) + // will be called if the toot was successful + // 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", [ + //["since_id", 420], + //["max_id", 1337] + ], function(data) { + // returns all users account id 1 is following in the id range from 420 to 1337 + // you don't have to supply the parameters, you can also just go with .get(endpoint, callback) + //model.append(data) + for (var i in data) { + if (data.hasOwnProperty(i)) { + var toot = tootParser(data[i]) + model.append(toot) + } + } + console.log(model.count) + }); + console.log(Logic.test) + } +} + diff --git a/qml/pages/MyList.qml b/qml/pages/MyList.qml new file mode 100644 index 0000000..63650e1 --- /dev/null +++ b/qml/pages/MyList.qml @@ -0,0 +1,177 @@ +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 {} + +} diff --git a/qml/pages/SecondPage.qml b/qml/pages/SecondPage.qml new file mode 100644 index 0000000..99ea9b6 --- /dev/null +++ b/qml/pages/SecondPage.qml @@ -0,0 +1,67 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + 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 Sailfish.Silica 1.0 +import "../lib/API.js" as Logic + + +Page { + id: page + + // The effective value will be restricted by ApplicationWindow.allowedOrientations + allowedOrientations: Orientation.All + + SilicaListView { + id: listView + model: 20 + anchors.fill: parent + header: PageHeader { + title: qsTr("Nested Page") + } + delegate: BackgroundItem { + id: delegate + + Label { + x: Theme.horizontalPageMargin + text: qsTr("Item") + " " + index + anchors.verticalCenter: parent.verticalCenter + color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor + } + onClicked: console.log("Clicked " + index) + } + VerticalScrollDecorator {} + } + Component.onCompleted: { + Logic.test++; + Logic.conf['test'] = "aaaa"; + console.log(Logic.test) + } +} diff --git a/qml/pages/Tweet.qml b/qml/pages/Tweet.qml new file mode 100644 index 0000000..a6830e1 --- /dev/null +++ b/qml/pages/Tweet.qml @@ -0,0 +1,192 @@ +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 + }) + }*/ + +} diff --git a/rpm/harbour-tooter.changes.in b/rpm/harbour-tooter.changes.in new file mode 100644 index 0000000..6a47ba0 --- /dev/null +++ b/rpm/harbour-tooter.changes.in @@ -0,0 +1,14 @@ +# Rename this file as harbour-tooter.changes to include changelog +# entries in your RPM file. +# +# Add new changelog entries following the format below. +# Add newest entries to the top of the list. +# Separate entries from eachother with a blank line. + +# * date Author's Name version-release +# - Summary of changes + +* Sun Apr 13 2014 Jack Tar 0.0.1-1 +- Scrubbed the deck +- Hoisted the sails + diff --git a/rpm/harbour-tooter.spec b/rpm/harbour-tooter.spec new file mode 100644 index 0000000..0cc3d8c --- /dev/null +++ b/rpm/harbour-tooter.spec @@ -0,0 +1,71 @@ +# +# Do NOT Edit the Auto-generated Part! +# Generated by: spectacle version 0.27 +# + +Name: harbour-tooter + +# >> macros +# << macros + +%{!?qtc_qmake:%define qtc_qmake %qmake} +%{!?qtc_qmake5:%define qtc_qmake5 %qmake5} +%{!?qtc_make:%define qtc_make make} +%{?qtc_builddir:%define _builddir %qtc_builddir} +Summary: Tooter +Version: 0.1.0 +Release: 1 +Group: Qt/Qt +License: LICENSE +URL: http://example.org/ +Source0: %{name}-%{version}.tar.bz2 +Source100: harbour-tooter.yaml +Requires: sailfishsilica-qt5 >= 0.10.9 +BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt5Qml) +BuildRequires: pkgconfig(Qt5Quick) +BuildRequires: desktop-file-utils + +%description +Short description of my Sailfish OS Application + + +%prep +%setup -q -n %{name}-%{version} + +# >> setup +# << setup + +%build +# >> build pre +# << build pre + +%qtc_qmake5 + +%qtc_make %{?_smp_mflags} + +# >> build post +# << build post + +%install +rm -rf %{buildroot} +# >> install pre +# << install pre +%qmake5_install + +# >> install post +# << install post + +desktop-file-install --delete-original \ + --dir %{buildroot}%{_datadir}/applications \ + %{buildroot}%{_datadir}/applications/*.desktop + +%files +%defattr(-,root,root,-) +%{_bindir} +%{_datadir}/%{name} +%{_datadir}/applications/%{name}.desktop +%{_datadir}/icons/hicolor/*/apps/%{name}.png +# >> files +# << files diff --git a/rpm/harbour-tooter.yaml b/rpm/harbour-tooter.yaml new file mode 100644 index 0000000..156248d --- /dev/null +++ b/rpm/harbour-tooter.yaml @@ -0,0 +1,45 @@ +Name: harbour-tooter +Summary: Tooter +Version: 0.1.0 +Release: 1 +# The contents of the Group field should be one of the groups listed here: +# http://gitorious.org/meego-developer-tools/spectacle/blobs/master/data/GROUPS +Group: Qt/Qt +URL: http://example.org/ +License: LICENSE +# This must be generated before uploading a package to a remote build service. +# Usually this line does not need to be modified. +Sources: +- '%{name}-%{version}.tar.bz2' +Description: | + Short description of my Sailfish OS Application +Configure: none +# The qtc5 builder inserts macros to allow QtCreator to have fine +# control over qmake/make execution +Builder: qtc5 + +# This section specifies build dependencies that are resolved using pkgconfig. +# This is the preferred way of specifying build dependencies for your package. +PkgConfigBR: + - sailfishapp >= 1.0.2 + - Qt5Core + - Qt5Qml + - Qt5Quick + +# Build dependencies without a pkgconfig setup can be listed here +# PkgBR: +# - package-needed-to-build + +# Runtime dependencies which are not automatically detected +Requires: + - sailfishsilica-qt5 >= 0.10.9 + +# All installed files +Files: + - '%{_bindir}' + - '%{_datadir}/%{name}' + - '%{_datadir}/applications/%{name}.desktop' + - '%{_datadir}/icons/hicolor/*/apps/%{name}.png' + +# For more information about yaml and what's supported in Sailfish OS +# build system, please see https://wiki.merproject.org/wiki/Spectacle diff --git a/src/harbour-tooter.cpp b/src/harbour-tooter.cpp new file mode 100644 index 0000000..0e24cbb --- /dev/null +++ b/src/harbour-tooter.cpp @@ -0,0 +1,50 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + 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. +*/ + +#ifdef QT_QML_DEBUG +#include +#endif + +#include + + +int main(int argc, char *argv[]) +{ + // SailfishApp::main() will display "qml/template.qml", if you need more + // control over initialization, you can use: + // + // - SailfishApp::application(int, char *[]) to get the QGuiApplication * + // - SailfishApp::createView() to get a new QQuickView * instance + // - SailfishApp::pathTo(QString) to get a QUrl to a resource file + // + // To display the view, call "show()" (will show fullscreen on device). + + return SailfishApp::main(argc, argv); +} diff --git a/translations/harbour-tooter-de.ts b/translations/harbour-tooter-de.ts new file mode 100644 index 0000000..a84d4fe --- /dev/null +++ b/translations/harbour-tooter-de.ts @@ -0,0 +1,40 @@ + + + + + + + + + + + + FirstPage + + Show Page 2 + Zur Seite 2 + + + + MyList + + Settings + + + + Load more + + + + + SecondPage + + Nested Page + Unterseite + + + Item + Element + + + diff --git a/translations/harbour-tooter.ts b/translations/harbour-tooter.ts new file mode 100644 index 0000000..e1fbe0d --- /dev/null +++ b/translations/harbour-tooter.ts @@ -0,0 +1,40 @@ + + + + + + + + Tooter + + + + FirstPage + + Show Page 2 + + + + + MyList + + Settings + + + + Load more + + + + + SecondPage + + Nested Page + + + + Item + + + +