diff --git a/backend/ForumBackend.qml b/backend/ForumBackend.qml
index 54cc132..e3b2958 100644
--- a/backend/ForumBackend.qml
+++ b/backend/ForumBackend.qml
@@ -150,10 +150,10 @@ Object {
loginFinished = false //do not set loggedIn to false => ability to change login data
- if (configModel.get(0).support_md5) {
+ if (configModel.supportMd5) {
console.log("md5")
password = Md5Utils.md5(password)
- } else if (configModel.get(0).support_sha1) { //Untested yet
+ } else if (configModel.supportSHA1) { //Untested yet
console.log("sha1")
password = Sha1Utils.sha1(password)
} else {
diff --git a/backend/ForumConfigModel.qml b/backend/ForumConfigModel.qml
index 3b7cf5a..0ac1301 100644
--- a/backend/ForumConfigModel.qml
+++ b/backend/ForumConfigModel.qml
@@ -38,18 +38,28 @@ XmlListModel {
query: "/methodResponse/params/param/value/struct"
property bool hasLoaded: false
+
+ property string version
property bool isVBulletin: false
+ property bool supportMd5: false
+ property bool supportSHA1: false
+ property bool subscribeForum: true
- XmlRole { name: "support_md5"; query: "member[name='support_md5']/value/string()" }
- XmlRole { name: "support_sha1"; query: "member[name='support_sha1']/value/string()" }
+ XmlRole { name: "support_md5"; query: "member[name='support_md5']/value/number()" }
+ XmlRole { name: "support_sha1"; query: "member[name='support_sha1']/value/number()" }
XmlRole { name: "version"; query: "member[name='version']/value/string()" }
+ XmlRole { name: "subscribe_forum"; query: "member[name='subscribe_forum']/value/number()" }
onStatusChanged: {
if (status === XmlListModel.Ready) {
var element = get(0)
- if (element.version.trim().indexOf("vb") === 0) {
- isVBulletin = true
- }
+
+ version = element.version.trim()
+ isVBulletin = version.indexOf("vb") === 0
+ supportMd5 = (typeof(element.support_md5) === "number") ? element.support_md5 : false
+ supportSHA1 = (typeof(element.support_sha1) === "number") ? element.support_sha1 : false
+ subscribeForum = (typeof(element.subscribe_forum) === "number") ? element.subscribe_forum : true
+
console.log("version: " + element.version.trim())
console.log("configModel has loaded")
diff --git a/ui/components/Notification.qml b/ui/components/Notification.qml
index 711a8f1..f8a7144 100644
--- a/ui/components/Notification.qml
+++ b/ui/components/Notification.qml
@@ -37,14 +37,14 @@ Rectangle {
function show(text) {
queue.push(text)
- if (!showing) {
+ if (!showing && !timer.running) { //!timer.running for the time between two notifications (when timer.interval === 800)
update()
}
}
function update() {
notification.text = ""
- notification.text = queue.pop()
+ notification.text = queue.shift()
notification.showing = true
}
diff --git a/ui/viewing/SubForumList.qml b/ui/viewing/SubForumList.qml
index 5d93fdd..a45cec7 100644
--- a/ui/viewing/SubForumList.qml
+++ b/ui/viewing/SubForumList.qml
@@ -37,13 +37,10 @@ ListView {
id: forumsList
property alias current_forum: categoryModel.parentForumId
- property int current_topic: -1
- property int selected_forum: -1
- property string selected_title: ""
- property bool canPost: false
- property bool hasTopics: false
property string mode: ""
property bool moreLoading: false
+ property bool hasTopics: false
+ property bool canPost: false
property bool viewSubscriptions: false
@@ -56,19 +53,16 @@ ListView {
delegate: SubForumListItem {
text: StringUtils.base64_decode(model.name)
subText: StringUtils.base64_decode(model.description)
- replies: model.topic ? (parseInt(model.posts) + 1) : 0 //+1 to include OP
+ replies: model.topic ? (model.posts + 1) : 0 //+1 to include OP
author: model.topic ? StringUtils.base64_decode(model.author) : ""
- has_new: model.has_new === '1' ? true : false
+ has_new: model.has_new
progression: true
onTriggered: {
- selected_title = text
if (model.topic) {
- current_topic = -1
- current_topic = model.id
+ forumsPage.pushThreadPage(model.id, text)
} else {
- selected_forum = -1
- selected_forum = model.id
+ forumsPage.pushSubForumPage(model.id, text, model.can_subscribe, model.is_subscribed)
}
}
@@ -161,10 +155,12 @@ ListView {
property bool viewSubscriptions: forumsList.viewSubscriptions
query: viewSubscriptions ? "/methodResponse/params/param/value/struct/member[name='forums']/value/array/data/value/struct" : "/methodResponse/params/param/value/array/data/value/struct"
- XmlRole { name: "id"; query: "member[name='forum_id']/value/string()" }
+ XmlRole { name: "id"; query: "member[name='forum_id']/value/number()" }
XmlRole { name: "name"; query: "member[name='forum_name']/value/base64/string()" }
XmlRole { name: "description"; query: "member[name='description']/value/base64/string()" }
XmlRole { name: "logo"; query: "member[name='logo_url']/value/string()" }
+ XmlRole { name: "can_subscribe"; query: "member[name='can_subscribe']/value/number()" }
+ XmlRole { name: "is_subscribed"; query: "member[name='is_subscribed']/value/number()" }
property bool checkingForChildren: false
@@ -178,7 +174,7 @@ ListView {
if (!checkingForChildren) {
console.debug("categoryModel has: " + count + " items");
- if (count !== 1 || parentForumId !== parseInt(get(0).id)) {
+ if (count !== 1 || parentForumId !== get(0).id) {
insertResults()
} else { //Header with a child attribute
if (!topicModel.hasLoadedCompletely) {
@@ -218,7 +214,7 @@ ListView {
var element = get(i)
//We need to declare even unused properties here
//Needed when there are both topics and categories in a subforum
- var pushObject = {"topic": false, "id": element.id.trim(), "name": element.name.trim(), "description": viewSubscriptions ? "" : element.description.trim(), "logo": element.logo.trim(), "author": "", "posts": "-1", "has_new": "0"}
+ var pushObject = {"topic": false, "id": element.id, "name": element.name.trim(), "description": viewSubscriptions ? "" : element.description.trim(), "logo": element.logo.trim(), "author": "", "posts": -1, "has_new": 0, "can_subscribe": viewSubscriptions ? 1 : element.can_subscribe, "is_subscribed": viewSubscriptions ? 1 : element.is_subscribed}
if (!isForumOverview) {
forumListModel.insert(i, pushObject)
} else {
@@ -356,12 +352,12 @@ ListView {
property bool viewSubscriptions: forumsList.viewSubscriptions
query: "/methodResponse/params/param/value/struct/member/value/array/data/value/struct"
- XmlRole { name: "id"; query: "member[name='topic_id']/value/string()" }
+ XmlRole { name: "id"; query: "member[name='topic_id']/value/number()" }
XmlRole { name: "title"; query: "member[name='topic_title']/value/base64/string()" }
// XmlRole { name: "description"; query: "member[name='short_content']/value/base64/string()" }
XmlRole { name: "author"; query: "member[name='topic_author_name']/value/base64/string()" }
- XmlRole { name: "posts"; query: "member[name='reply_number']/value/int/string()" }
- XmlRole { name: "has_new"; query: "member[name='new_post']/value/boolean/string()" }
+ XmlRole { name: "posts"; query: "member[name='reply_number']/value/int/number()" }
+ XmlRole { name: "has_new"; query: "member[name='new_post']/value/boolean/number()" }
onStatusChanged: {
if (status === 1) {
@@ -369,7 +365,7 @@ ListView {
hasTopics = true //no else needed (and it may interfere with moreLoading)
//TODO: Check if if is needed or if it won't be added twice even without the if
- if (count === 1 && forumListModel.count > 0 && get(0).id.trim() === forumListModel.get(forumListModel.count - 1).id && forumListModel.get(forumListModel.count - 1).topic === true) {
+ if (count === 1 && forumListModel.count > 0 && get(0).id === forumListModel.get(forumListModel.count - 1).id && forumListModel.get(forumListModel.count - 1).topic === true) {
//Do not add the element as it is a duplicate of the last one which was added
//Happens if a forum contains n * backend.topicsLoadCount topics (with n = 2, 3, 4, ...) and loadMore() is called (sadly, that's how the API handles the request)
@@ -385,7 +381,7 @@ ListView {
var element = get(i);
//We need to declare even unused properties here
//Needed when there are both topics and categories in a subforum
- forumListModel.append({"topic": true, "id": element.id.trim(), "name": element.title.trim(), "description": "" /*element.description.trim()*/, "logo": "", "author": element.author.trim(), "posts": element.posts.trim(), "has_new": element.has_new.trim()});
+ forumListModel.append({"topic": true, "id": element.id, "name": element.title.trim(), "description": "", "logo": "", "author": element.author.trim(), "posts": element.posts, "has_new": element.has_new, "can_subscribe": 1, "is_subscribed": 0});
}
}
}
diff --git a/ui/viewing/SubForumPage.qml b/ui/viewing/SubForumPage.qml
index 3501146..c636c98 100644
--- a/ui/viewing/SubForumPage.qml
+++ b/ui/viewing/SubForumPage.qml
@@ -28,7 +28,8 @@
import QtQuick 2.2
import Ubuntu.Components 1.1
import Ubuntu.Components.Popups 1.0
-import '../components'
+import "../components"
+import "../../backend"
PageWithBottomEdge {
id: forumsPage
@@ -41,11 +42,17 @@ PageWithBottomEdge {
property alias current_forum: forumsList.current_forum
property bool isForumOverview: current_forum === 0
- property alias selectedTitle: forumsList.selected_title
+ property int selectedId: -1
+ property string selectedTitle: ""
+ property bool selectedCanSubscribe: false
+ property bool selectedIsSubscribed: false
property alias loadingSpinnerRunning: loadingSpinner.running
property bool showSections: false
+ property bool isSubscribed: false
+ property bool canSubscribe: false
+
bottomEdgeTitle: i18n.tr("Subscriptions")
bottomEdgeEnabled: !disableBottomEdge && current_forum >= 0 && backend.currentSession.loggedIn
bottomEdgePageSource: (!disableBottomEdge && current_forum >= 0) ? Qt.resolvedUrl("SubForumPage.qml") : ""
@@ -117,10 +124,47 @@ PageWithBottomEdge {
}
}
+ Action {
+ id: subscribeAction
+ text: isSubscribed ? i18n.tr("Unsubscribe") : i18n.tr("Subscribe")
+ iconName: isSubscribed ? "starred" : "non-starred"
+ visible: backend.currentSession.loggedIn && !viewSubscriptions && backend.currentSession.configModel.subscribeForum && canSubscribe
+
+ onTriggered: subscriptionChange()
+
+ function subscriptionChange() {
+ if (isSubscribed) {
+ subscribeRequest.query = 'unsubscribe_forum' + current_forum + ''
+ } else {
+ subscribeRequest.query = 'subscribe_forum' + current_forum + ''
+ }
+
+ if (subscribeRequest.start()) {
+ isSubscribed = !isSubscribed //If the api request fails, it will be changed back later
+ subscribeRequest.notificationQueue.push(isSubscribed ? i18n.tr("Subscribed to this subforum") : i18n.tr("Unsubscribed from this subforum"))
+ }
+ }
+ }
+
+ ApiRequest {
+ id: subscribeRequest
+ checkSuccess: true
+ allowMultipleRequests: true
+ property var notificationQueue: [] //Needed when subscribeRequest.queryQueue.length > 1
+
+ onQuerySuccessResult: {
+ if (success) {
+ notification.show(notificationQueue.shift())
+ } else {
+ isSubscribed = !isSubscribed
+ notificationQueue.shift()
+ }
+ }
+ }
+
function onNewTopicCreated(subject, topicId) {
selectedTitle = subject
- forumsList.current_topic = -1
- forumsList.current_topic = topicId //Show topic
+ pushThreadPage(topicId) //Show thread
forumsList.reload()
}
@@ -128,6 +172,7 @@ PageWithBottomEdge {
readonly property var headerActions: [
reloadAction,
newTopicAction,
+ subscribeAction,
loginAction
]
@@ -177,43 +222,54 @@ PageWithBottomEdge {
mode: (forumsPage.head.sections.selectedIndex === 1) ? "TOP" : ((forumsPage.head.sections.selectedIndex === 2) ? "ANN" : "")
- onSelected_forumChanged: {
- if (selected_forum > 0) {
- component = Qt.createComponent("SubForumPage.qml");
-
- if (component.status === Component.Ready) {
- finishSubForumPageCreation();
- } else {
- component.statusChanged.connect(finishSubForumPageCreation);
- }
- }
- }
+ }
- function finishSubForumPageCreation() {
- var page = component.createObject(mainView, {"title": selectedTitle, "current_forum": selected_forum, "loadingSpinnerRunning": true, "disableBottomEdge": disableBottomEdge})
- pageStack.push(page)
+ function pushSubForumPage(forumId, title, canSubscribe, isSubscribed) {
+ selectedId = forumId
+ selectedTitle = title
+ selectedCanSubscribe = (typeof(canSubscribe) === "bool" || typeof(canSubscribe) === "number") ? canSubscribe : true
+ selectedIsSubscribed = (typeof(isSubscribed) === "bool" || typeof(isSubscribed) === "number") ? isSubscribed : false
+ component = Qt.createComponent("SubForumPage.qml")
+
+ if (component.status === Component.Ready) {
+ finishSubForumPageCreation()
+ } else {
+ component.statusChanged.connect(finishSubForumPageCreation)
}
+ }
- onCurrent_topicChanged: {
- if (current_topic > 0) {
- component = Qt.createComponent("ThreadPage.qml")
-
- if (component.status === Component.Ready) {
- finishThreadPageCreation();
- } else {
- component.statusChanged.connect(finishThreadPageCreation);
+ function finishSubForumPageCreation() {
+ var page = component.createObject(mainView, {"title": selectedTitle, "current_forum": selectedId, "loadingSpinnerRunning": true, "disableBottomEdge": disableBottomEdge, "canSubscribe": selectedCanSubscribe, "isSubscribed": selectedIsSubscribed})
+ page.onIsSubscribedChanged.connect(function() { //Change is_subscribed attribute when the subscription state is changed
+ for (var i = 0; i < forumsList.model.count; i++) {
+ if (forumsList.model.get(i).id === selectedId) {
+ forumsList.model.setProperty(i, "is_subscribed", page.isSubscribed ? 1 : 0) //is_subscribed requires a number
+ break
}
}
- }
+ })
+ pageStack.push(page)
+ }
- function finishThreadPageCreation() {
- var vBulletinAnnouncement = backend.currentSession.configModel.isVBulletin && forumsList.mode === "ANN"
- var page = component.createObject(mainView, {"title": selectedTitle, "loadingSpinnerRunning": true, "forum_id": current_forum, "vBulletinAnnouncement": vBulletinAnnouncement})
- page.current_topic = current_topic //Need to set vBulletinAnnouncement before current_topic!!! Therefore, this is executed after the creation of the Page.
- pageStack.push(page)
+ function pushThreadPage(topicId, title) {
+ selectedId = topicId
+ selectedTitle = title
+ component = Qt.createComponent("ThreadPage.qml")
+
+ if (component.status === Component.Ready) {
+ finishThreadPageCreation()
+ } else {
+ component.statusChanged.connect(finishThreadPageCreation)
}
}
+ function finishThreadPageCreation() {
+ var vBulletinAnnouncement = backend.currentSession.configModel.isVBulletin && forumsList.mode === "ANN"
+ var page = component.createObject(mainView, {"title": selectedTitle, "loadingSpinnerRunning": true, "forum_id": current_forum, "vBulletinAnnouncement": vBulletinAnnouncement})
+ page.current_topic = selectedId //Need to set vBulletinAnnouncement before current_topic!!! Therefore, this is executed after the creation of the Page.
+ pageStack.push(page)
+ }
+
Label {
id: emptyView
text: viewSubscriptions ? i18n.tr("You are not subscribed to any topics or forums") : ((forumsList.mode === "") ? i18n.tr("No topics available here") : ((forumsList.mode === "TOP") ? i18n.tr("No stickies available here") : i18n.tr("No announcements available here")))
diff --git a/ui/viewing/ThreadList.qml b/ui/viewing/ThreadList.qml
index a9445d5..fa958ae 100644
--- a/ui/viewing/ThreadList.qml
+++ b/ui/viewing/ThreadList.qml
@@ -41,6 +41,8 @@ ListView {
property int totalPostCount: -1
property bool canReply: false
property bool isClosed: false
+ property bool canSubscribe: false
+ property bool isSubscribed: false
property bool vBulletinAnnouncement: false
@@ -132,6 +134,32 @@ ListView {
isClosed = isClosedSubstring.trim() === "1"
}
+
+ //Check if can subscribe
+
+ var canSubscribeStringPosition = xml.indexOf("can_subscribe");
+ if (canSubscribeStringPosition < 0) {
+ canSubscribe = true
+ } else {
+ var openBoolTagPosition = xml.indexOf("", canSubscribeStringPosition);
+ var closeBoolTagPosition = xml.indexOf("", openBoolTagPosition);
+ var canSubscribeSubstring = xml.substring(openBoolTagPosition + 9, closeBoolTagPosition); //equals + "".length
+
+ canSubscribe = canSubscribeSubstring.trim() === "1"
+ }
+
+ //Check if is subscribed
+
+ var isSubscribedStringPosition = xml.indexOf("is_subscribed");
+ if (isSubscribedStringPosition < 0) {
+ isSubscribed = false
+ } else {
+ var openBoolTagPosition = xml.indexOf("", isSubscribedStringPosition);
+ var closeBoolTagPosition = xml.indexOf("", openBoolTagPosition);
+ var isSubscribedSubstring = xml.substring(openBoolTagPosition + 9, closeBoolTagPosition); //equals + "".length
+
+ isSubscribed = isSubscribedSubstring.trim() === "1"
+ }
}
}
diff --git a/ui/viewing/ThreadPage.qml b/ui/viewing/ThreadPage.qml
index ebbc143..8d0dce2 100644
--- a/ui/viewing/ThreadPage.qml
+++ b/ui/viewing/ThreadPage.qml
@@ -30,6 +30,7 @@ import Ubuntu.Components 1.1
import Ubuntu.Components.ListItems 1.0
import Ubuntu.Components.Popups 1.0
import "../components"
+import "../../backend"
PageWithBottomEdge {
id: threadPage
@@ -75,6 +76,14 @@ PageWithBottomEdge {
}
head.actions: [
+ Action {
+ id: reloadAction
+ text: i18n.tr("Reload")
+ iconName: "reload"
+ onTriggered: {
+ threadList.reload()
+ }
+ },
Action {
id: loginAction
text: i18n.tr("Login")
@@ -84,6 +93,27 @@ PageWithBottomEdge {
pageStack.push(loginPage)
}
},
+ Action {
+ id: subscribeAction
+ text: threadList.isSubscribed ? i18n.tr("Unsubscribe") : i18n.tr("Subscribe")
+ iconName: threadList.isSubscribed ? "starred" : "non-starred"
+ visible: backend.currentSession.loggedIn && threadList.canSubscribe
+
+ onTriggered: subscriptionChange()
+
+ function subscriptionChange() {
+ if (threadList.isSubscribed) {
+ subscribeRequest.query = 'unsubscribe_topic' + current_topic + ''
+ } else {
+ subscribeRequest.query = 'subscribe_topic' + current_topic + ''
+ }
+
+ if (subscribeRequest.start()) {
+ threadList.isSubscribed = !threadList.isSubscribed //If the api request fails, it will be changed back later
+ subscribeRequest.notificationQueue.push(threadList.isSubscribed ? i18n.tr("Subscribed to this topic") : i18n.tr("Unsubscribed from this topic"))
+ }
+ }
+ },
Action {
id: gotoAction
text: i18n.tr("Go To Page")
@@ -95,17 +125,25 @@ PageWithBottomEdge {
popup.itemSelector.selectedIndex = selected
// popup.itemSelector.positionViewAtIndex(selected, ListView.Center) //TODO: Add to UI Toolkit?
}
- },
- Action {
- id: reloadAction
- text: i18n.tr("Reload")
- iconName: "reload"
- onTriggered: {
- threadList.reload()
- }
}
]
+ ApiRequest {
+ id: subscribeRequest
+ checkSuccess: true
+ allowMultipleRequests: true
+ property var notificationQueue: [] //Needed when subscribeRequest.queryQueue.length > 1
+
+ onQuerySuccessResult: {
+ if (success) {
+ notification.show(notificationQueue.shift())
+ } else {
+ threadList.isSubscribed = !threadList.isSubscribed
+ notificationQueue.shift()
+ }
+ }
+ }
+
head.contents: Label {
width: parent.width
anchors.verticalCenter: parent.verticalCenter