From e0b81bf291075622fdb6af337e39667f1f3b1e5f Mon Sep 17 00:00:00 2001 From: Dusko Angirevic Date: Thu, 1 Jun 2017 16:13:51 +0200 Subject: [PATCH] Init --- harbour-tooter.desktop | 12 + harbour-tooter.pro | 44 ++ harbour-tooter.pro.user | 801 ++++++++++++++++++++++++++++++ icons/108x108/harbour-tooter.png | Bin 0 -> 7433 bytes icons/128x128/harbour-tooter.png | Bin 0 -> 9004 bytes icons/256x256/harbour-tooter.png | Bin 0 -> 18837 bytes icons/86x86/harbour-tooter.png | Bin 0 -> 5835 bytes qml/cover/CoverPage.qml | 57 +++ qml/harbour-tooter.qml | 62 +++ qml/lib/API.js | 318 ++++++++++++ qml/pages/FirstPage.qml | 127 +++++ qml/pages/MyList.qml | 177 +++++++ qml/pages/SecondPage.qml | 67 +++ qml/pages/Tweet.qml | 192 +++++++ rpm/harbour-tooter.changes.in | 14 + rpm/harbour-tooter.spec | 71 +++ rpm/harbour-tooter.yaml | 45 ++ src/harbour-tooter.cpp | 50 ++ translations/harbour-tooter-de.ts | 40 ++ translations/harbour-tooter.ts | 40 ++ 20 files changed, 2117 insertions(+) create mode 100644 harbour-tooter.desktop create mode 100644 harbour-tooter.pro create mode 100644 harbour-tooter.pro.user create mode 100644 icons/108x108/harbour-tooter.png create mode 100644 icons/128x128/harbour-tooter.png create mode 100644 icons/256x256/harbour-tooter.png create mode 100644 icons/86x86/harbour-tooter.png create mode 100644 qml/cover/CoverPage.qml create mode 100644 qml/harbour-tooter.qml create mode 100644 qml/lib/API.js create mode 100644 qml/pages/FirstPage.qml create mode 100644 qml/pages/MyList.qml create mode 100644 qml/pages/SecondPage.qml create mode 100644 qml/pages/Tweet.qml create mode 100644 rpm/harbour-tooter.changes.in create mode 100644 rpm/harbour-tooter.spec create mode 100644 rpm/harbour-tooter.yaml create mode 100644 src/harbour-tooter.cpp create mode 100644 translations/harbour-tooter-de.ts create mode 100644 translations/harbour-tooter.ts 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 0000000000000000000000000000000000000000..ab10628d3741e1893912e2a304931b55c8c43cf7 GIT binary patch literal 7433 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 Hu0mjfp95I$ literal 0 HcmV?d00001 diff --git a/icons/128x128/harbour-tooter.png b/icons/128x128/harbour-tooter.png new file mode 100644 index 0000000000000000000000000000000000000000..54375c53cbe19c8ff70ed0c2b435707a7f8a5db5 GIT binary patch literal 9004 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 A4gdfE literal 0 HcmV?d00001 diff --git a/icons/256x256/harbour-tooter.png b/icons/256x256/harbour-tooter.png new file mode 100644 index 0000000000000000000000000000000000000000..de79583e552264a35469db949e39a9339178399a GIT binary patch literal 18837 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 + 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 + + + +