aboutsummaryrefslogtreecommitdiff
path: root/tabs
diff options
context:
space:
mode:
Diffstat (limited to 'tabs')
-rw-r--r--tabs/TweetsModel.qml88
-rw-r--r--tabs/Twitter.qml124
-rw-r--r--tabs/tweetSearch.js83
3 files changed, 295 insertions, 0 deletions
diff --git a/tabs/TweetsModel.qml b/tabs/TweetsModel.qml
new file mode 100644
index 00000000..19b77ab1
--- /dev/null
+++ b/tabs/TweetsModel.qml
@@ -0,0 +1,88 @@
+import QtQuick 2.2
+import "tweetSearch.js" as Helper
+
+Item {
+ id: wrapper
+
+ // Insert valid consumer key and secret tokens below
+ // See https://dev.twitter.com/apps
+//! [auth tokens]
+ property string tweetsMaxCount: "20"
+ property string consumerKey : ""
+ property string consumerSecret : ""
+//! [auth tokens]
+ property string bearerToken : ""
+
+ property variant model: tweets
+ property string from : ""
+ property string phrase : ""
+
+ property int status: XMLHttpRequest.UNSENT
+ property bool isLoading: status === XMLHttpRequest.LOADING
+ property bool wasLoading: false
+ signal isLoaded
+
+ ListModel { id: tweets }
+
+ function encodePhrase(x) { return encodeURIComponent(x); }
+
+ function reload() {
+ tweets.clear()
+
+ if (from == "" && phrase == "")
+ return;
+
+//! [requesting]
+ var req = new XMLHttpRequest;
+ req.open("GET", "https://api.twitter.com/1.1/search/tweets.json?from=" + from +
+ "&count=" + tweetsMaxCount + "&q=" + encodePhrase(phrase));
+ req.setRequestHeader("Authorization", "Bearer " + bearerToken);
+ req.onreadystatechange = function() {
+ status = req.readyState;
+ if (status === XMLHttpRequest.DONE) {
+ var objectArray = JSON.parse(req.responseText);
+ if (objectArray.errors !== undefined)
+ console.log("Error fetching tweets: " + objectArray.errors[0].message)
+ else {
+ for (var key in objectArray.statuses) {
+ var jsonObject = objectArray.statuses[key];
+ tweets.append(jsonObject);
+ }
+ }
+ if (wasLoading == true)
+ wrapper.isLoaded()
+ }
+ wasLoading = (status === XMLHttpRequest.LOADING);
+ }
+ req.send();
+//! [requesting]
+ }
+
+
+ Component.onCompleted: {
+ if (consumerKey === "" || consumerSecret == "") {
+ console.log("setting demo token")
+ bearerToken = encodeURIComponent(Helper.demoToken())
+ tweetsModel.phrase = ""
+ tweetsModel.from = "@monerocurrency"
+ reload()
+ return;
+ }
+
+ var authReq = new XMLHttpRequest;
+ authReq.open("POST", "https://api.twitter.com/oauth2/token");
+ authReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
+ authReq.setRequestHeader("Authorization", "Basic " + Qt.btoa(consumerKey + ":" + consumerSecret));
+ authReq.onreadystatechange = function() {
+ if (authReq.readyState === XMLHttpRequest.DONE) {
+ var jsonResponse = JSON.parse(authReq.responseText);
+ if (jsonResponse.errors !== undefined)
+ console.log("Authentication error: " + jsonResponse.errors[0].message)
+ else
+ bearerToken = jsonResponse.access_token;
+ }
+ }
+ authReq.send("grant_type=client_credentials");
+ }
+
+}
diff --git a/tabs/Twitter.qml b/tabs/Twitter.qml
new file mode 100644
index 00000000..03c9be81
--- /dev/null
+++ b/tabs/Twitter.qml
@@ -0,0 +1,124 @@
+import QtQuick 2.2
+import QtQuick.Controls 1.2
+import "tweetSearch.js" as Helper
+
+Item {
+ id: tab
+ ListModel {
+ id: testModel
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ ListElement { head: "Monero || #xmr"; foot: "<b>@btcplanet</b> Duis turpis arcu, varius nec rutrum in, adipiscing at enim. Donec quis consequat ipsum," }
+ }
+
+ property int inAnimDur: 250
+ property int counter: 0
+ property alias isLoading: tweetsModel.isLoading
+ property var idx
+ property var ids
+
+ Component.onCompleted: {
+ ids = new Array()
+ }
+
+ function idInModel(id) {
+ for (var j = 0; j < ids.length; j++)
+ if (ids[j] === id)
+ return 1
+ return 0
+ }
+
+ TweetsModel {
+ id: tweetsModel
+ onIsLoaded: {
+ console.debug("Reload")
+ idx = new Array()
+ for (var i = 0; i < tweetsModel.model.count; i++) {
+ var id = tweetsModel.model.get(i).id
+ if (!idInModel(id))
+ idx.push(i)
+ }
+ console.debug(idx.length + " new tweets")
+ tab.counter = idx.length
+ }
+ }
+
+ Timer {
+ id: timer
+ interval: 1; running: tab.counter; repeat: true
+ onTriggered: {
+ tab.counter--;
+ var id = tweetsModel.model.get(idx[tab.counter]).id
+ var item = tweetsModel.model.get(tab.counter)
+ listView.add({ "statusText": item.text,
+ "twitterName": item.user.screen_name,
+ "name" : item.user.name,
+ "userImage": item.user.profile_image_url,
+ "source": item.source,
+ "id": id,
+ "uri": Helper.insertLinks(item.user.url, item.user.entities),
+ "published": item.created_at });
+ console.log(item.created_at)
+ ids.push(id)
+ }
+ }
+
+ ListView {
+ id: listView
+ model: ListModel { id: finalModel }
+ anchors.fill: parent
+ clip: true
+ boundsBehavior: ListView.StopAtBounds
+
+ function add(obj) { model.insert(0, obj) }
+ delegate: Rectangle {
+ height: 98
+ width: listView.width
+
+ Text {
+ id: headerText
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.topMargin: 16
+ elide: Text.ElideRight
+ font.family: "Arial"
+ font.pixelSize: 18
+ color: "#000000"
+ text: model.name
+ }
+
+ Text {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: headerText.bottom
+ anchors.bottom: parent.bottom
+ anchors.topMargin: 10
+ anchors.bottomMargin: 10
+ wrapMode: Text.Wrap
+ elide: Text.ElideRight
+ font.family: "Arial"
+ font.pixelSize: 12
+ color: "#535353"
+ text: model.statusText
+ }
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: 1
+ color: "#DBDBDB"
+ }
+ }
+ }
+}
diff --git a/tabs/tweetSearch.js b/tabs/tweetSearch.js
new file mode 100644
index 00000000..2d1c083f
--- /dev/null
+++ b/tabs/tweetSearch.js
@@ -0,0 +1,83 @@
+.pragma library
+
+function formatDate(date) {
+ var da = new Date(date)
+ return da.toDateString()
+}
+
+function demoToken() {
+ var a = new Array(22).join('A')
+ return a + String.fromCharCode(0x44, 0x69, 0x4a, 0x52, 0x51, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x74, 0x2b, 0x72, 0x6a, 0x6c, 0x2b, 0x71,
+ 0x6d, 0x7a, 0x30, 0x72, 0x63, 0x79, 0x2b, 0x42, 0x62,
+ 0x75, 0x58, 0x42, 0x42, 0x73, 0x72, 0x55, 0x48, 0x47,
+ 0x45, 0x67, 0x3d, 0x71, 0x30, 0x45, 0x4b, 0x32, 0x61,
+ 0x57, 0x71, 0x51, 0x4d, 0x62, 0x31, 0x35, 0x67, 0x43,
+ 0x5a, 0x4e, 0x77, 0x5a, 0x6f, 0x39, 0x79, 0x71, 0x61,
+ 0x65, 0x30, 0x68, 0x70, 0x65, 0x32, 0x46, 0x44, 0x73,
+ 0x53, 0x39, 0x32, 0x57, 0x41, 0x75, 0x30, 0x67)
+}
+
+function linkForEntity(entity) {
+ return (entity.url ? entity.url :
+ (entity.screen_name ? 'https://twitter.com/' + entity.screen_name :
+ 'https://twitter.com/search?q=%23' + entity.text))
+}
+
+function textForEntity(entity) {
+ return (entity.display_url ? entity.display_url :
+ (entity.screen_name ? entity.screen_name : entity.text))
+}
+
+function insertLinks(text, entities) {
+ if (typeof text !== 'string')
+ return "";
+
+ if (!entities)
+ return text;
+
+ // Add all links (urls, usernames and hashtags) to an array and sort them in
+ // descending order of appearance in text
+ var links = []
+ if (entities.urls)
+ links = entities.urls.concat(entities.hashtags, entities.user_mentions)
+ else if (entities.url)
+ links = entities.url.urls
+
+ links.sort(function(a, b) { return b.indices[0] - a.indices[0] })
+
+ for (var i = 0; i < links.length; i++) {
+ var offset = links[i].url ? 0 : 1
+ text = text.substring(0, links[i].indices[0] + offset) +
+ '<a href=\"' + linkForEntity(links[i]) + '\">' +
+ textForEntity(links[i]) + '</a>' +
+ text.substring(links[i].indices[1])
+ }
+ return text.replace(/\n/g, '<br>');
+}
+
+function boldLinks(text, entities) {
+ if (typeof text !== 'string')
+ return "";
+
+ if (!entities)
+ return text;
+
+ // Add all links (urls, usernames and hashtags) to an array and sort them in
+ // descending order of appearance in text
+ var links = []
+ if (entities.urls)
+ links = entities.urls.concat(entities.hashtags, entities.user_mentions)
+ else if (entities.url)
+ links = entities.url.urls
+
+ links.sort(function(a, b) { return b.indices[0] - a.indices[0] })
+
+ for (var i = 0; i < links.length; i++) {
+ var offset = links[i].url ? 0 : 1
+ text = text.substring(0, links[i].indices[0] + offset) +
+ '<b>' + textForEntity(links[i]) + '</b>' +
+ text.substring(links[i].indices[1])
+ }
+ return text.replace(/\n/g, '<br>');
+}