diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6e5f5bf --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +## v0.004# + + +# News # + +* Conversation opens as child of news item +* Pull-to-refresh news +* Delete Icon +* Animated Gif attachments shown below news item +* Improved image selector for new message +* Gif attachments for new message +* Timeline reloaded after new message + +# Contacts # +* Contact details window mechanism completely reworked +* New calendar icon for Friendica contacts +* "Connect" opens connect request page for Friendica contacs + +# Calendar # +* new calendar tab +* shows own public events and public events of Friendica contacts +* list view of events of selected date +* click on event to show details + +# Config # +* the icon of the server is shown if url is correct +* Click on icon for server details + +# Translations # +* German \ No newline at end of file diff --git a/android-build-release-signed.apk b/Friendiqa.apk similarity index 86% rename from android-build-release-signed.apk rename to Friendiqa.apk index 84fb623..1d2bf9f 100644 Binary files a/android-build-release-signed.apk and b/Friendiqa.apk differ diff --git a/README.md b/README.md index 3eeeacf..1e9cb33 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ ## Friendiqa# QML based client for the Friendica Social Network. - Tabs for news (incl. Direct Messages), friends and photos. - Delete old version first when upgrading (due to database changes) -OS: currently Linux and Android(4.3). -Source code is a QtCreator project. - + Tabs for news (incl. Direct Messages), friends, photos and events. + OS: currently Linux and Android(4.3). + Source code is a QtCreator project. + ## Screenshots ## ![Newstab](Screenshots/NewsTab.jpg) ![Friendstab](Screenshots/FriendsTab.jpg) ![Photostab](Screenshots/PhotoTab.jpg) +![Eventstab](Screenshots/EventTab.jpg) ![Configtab](Screenshots/ConfigTab.jpg) @@ -18,34 +18,36 @@ Source code is a QtCreator project. # News # Currently supported: -* Shows Posts from friends, favorited messages, Direct Messages and Notifications -* Show news as timeline or tree (conversation opens in same window) -* Open links in external browser -* Click on contact phot for additional information -* Deletion, Reposting, Answering of Posts -* Liking, disliking, favoriting +* Shows Posts from friends, favorited messages, Direct Messages and Notifications +* Open links in external browser +* Click on contact photo for contact details * Click on like text for additional contact info -* Attending events -* Update fetches new posts since last in local DB +* Deletion, Reposting, Answering of Posts +* Liking, disliking, favoriting +* Attending for event posts +* Update fetches new posts (up to last 50) since last in local DB * More shows older posts from local DB -* Create new Message with images or direct messages, Contact/Group access rights(can be stored), smileys +* Create new Message with images or direct messages, Contact/Group access rights(can be stored), smileys * New image dialog ToDo: -* Videos and other binary data as attachment (sending and receiving) -* Rich text editing in Send Dialog + +* Videos and other binary data as attachment (sending and receiving) +* More than one attachment +* Rich text editing in Send Dialog * Attachments for Direct messages (currently not supported in API) - + # Friends # Currently supported: + * Tabs for friends, other contacts and groups -* Grid of all known contacts with locally downloaded pictures -* Large friend item for addional information and functionality -* Show news of contact from local database -* Send direct message, if contact is following -* Show public pictures of contact (screenscraping of contact's website, works only with certain theme) -* Open website of contact or connect page (for other contacts) +* Grid of all known contacts with locally downloaded pictures +* Large friend item for addional information and functionality +* Show news of contact from local database +* Send direct message, if contact is following +* Show public pictures of contact (screenscraping of contact's website, works only with certain theme) +* Open website of contact or connect page (for other contacts) ToDo: * More information for contact from description page, possibly private information for friends @@ -58,12 +60,21 @@ Currently supported: * Show albums in grid, show images in album in grid and fullscreen * Show albums and images of contacts * Pinch to zoom, swipe to scroll - + ToDo: * Private images of friends * Support for all themes of friends * Delete downloaded own images + +# Events # +* download own public events and public events of Friendica contacts +* list view of events of selected date +* click on event to show details + +ToDo +* private events + # Config # Currently supported: @@ -73,27 +84,20 @@ Currently supported: ToDo * OAuth? - + # Other # ToDo -* Calendar tab, video tab +* Video tab * Photo upload to album (needs API change) * Translation * Blingbling + +# Translations # +* German + -# New in version 0.003 -* improved BackButton behaviour -* click on contact everywhere to get to contact details -* Image dialog automatically opens in Android camera directory -* Smiley Dialog in Message Dialog -* Extensive use of FontAwesome for icons -* Bugfixes - - ## License ## -* v0.001 for Friendica < 3.5 -* v0.002 for Friendica >= 3.5 -* Published under the [GPL v3](http://gplv3.fsf.org). +Pubished under the [GPL v3](http://gplv3.fsf.org). diff --git a/Screenshots/ConfigTab.jpg b/Screenshots/ConfigTab.jpg index c63a34d..ed2b9da 100644 Binary files a/Screenshots/ConfigTab.jpg and b/Screenshots/ConfigTab.jpg differ diff --git a/Screenshots/EventsTab.jpg b/Screenshots/EventsTab.jpg new file mode 100644 index 0000000..3439b05 Binary files /dev/null and b/Screenshots/EventsTab.jpg differ diff --git a/Screenshots/FriendsTab.jpg b/Screenshots/FriendsTab.jpg index 94d3fe4..6258f55 100644 Binary files a/Screenshots/FriendsTab.jpg and b/Screenshots/FriendsTab.jpg differ diff --git a/Screenshots/NewsTab.jpg b/Screenshots/NewsTab.jpg index ac283c4..047f7f4 100644 Binary files a/Screenshots/NewsTab.jpg and b/Screenshots/NewsTab.jpg differ diff --git a/Screenshots/PhotoTab.jpg b/Screenshots/PhotoTab.jpg index bb51e5f..6655493 100644 Binary files a/Screenshots/PhotoTab.jpg and b/Screenshots/PhotoTab.jpg differ diff --git a/source-android/android/AndroidManifest.xml b/source-android/android/AndroidManifest.xml index c2da86e..e64dbfa 100644 --- a/source-android/android/AndroidManifest.xml +++ b/source-android/android/AndroidManifest.xml @@ -1,6 +1,6 @@ - - + + diff --git a/source-android/android/res/drawable-hdpi/friendiqa.png b/source-android/android/res/drawable-hdpi/friendiqa.png new file mode 100644 index 0000000..7618b3a Binary files /dev/null and b/source-android/android/res/drawable-hdpi/friendiqa.png differ diff --git a/source-android/android/res/drawable-ldpi/friendiqa.png b/source-android/android/res/drawable-ldpi/friendiqa.png new file mode 100644 index 0000000..8e269d7 Binary files /dev/null and b/source-android/android/res/drawable-ldpi/friendiqa.png differ diff --git a/source-android/android/res/drawable-mdpi/friendiqa.png b/source-android/android/res/drawable-mdpi/friendiqa.png new file mode 100644 index 0000000..6643513 Binary files /dev/null and b/source-android/android/res/drawable-mdpi/friendiqa.png differ diff --git a/source-android/android/res/drawable-xhdpi/friendiqa.png b/source-android/android/res/drawable-xhdpi/friendiqa.png new file mode 100644 index 0000000..e6e47bb Binary files /dev/null and b/source-android/android/res/drawable-xhdpi/friendiqa.png differ diff --git a/source-android/android/res/drawable-xxhdpi/friendiqa.png b/source-android/android/res/drawable-xxhdpi/friendiqa.png new file mode 100644 index 0000000..05a1f15 Binary files /dev/null and b/source-android/android/res/drawable-xxhdpi/friendiqa.png differ diff --git a/source-android/android/res/drawable-xxxhdpi/friendiqa.png b/source-android/android/res/drawable-xxxhdpi/friendiqa.png new file mode 100644 index 0000000..2ae19ef Binary files /dev/null and b/source-android/android/res/drawable-xxxhdpi/friendiqa.png differ diff --git a/source-android/application.qrc b/source-android/application.qrc index ca84b0e..e7aba98 100644 --- a/source-android/application.qrc +++ b/source-android/application.qrc @@ -196,5 +196,17 @@ images/smileys/adult/finger.gif images/smileys/adult/sperm.gif images/smileys/adult/tits.gif + common/filesystem.cpp + common/filesystem.h + common/friendiqa.cpp + common/uploadableimage.cpp + common/uploadableimage.h + common/xhr.cpp + common/xhr.h + qml/calendarqml/CalendarTab.qml + qml/calendarqml/CalendarDay.qml + qml/calendarqml/EventList.qml + translations/friendiqa-de.qm + translations/friendiqa-de.ts diff --git a/source-android/common/friendiqa.cpp b/source-android/common/friendiqa.cpp index de055f0..51659e4 100644 --- a/source-android/common/friendiqa.cpp +++ b/source-android/common/friendiqa.cpp @@ -7,7 +7,9 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); QQuickView view; - + QTranslator qtTranslator; + qtTranslator.load("friendiqa-" + QLocale::system().name(),":/translations"); + app.installTranslator(&qtTranslator); XHR* xhr = XHR::instance(); view.rootContext()->setContextProperty("xhr", xhr); diff --git a/source-android/js/helper.js b/source-android/js/helper.js index 7935585..4deece4 100644 --- a/source-android/js/helper.js +++ b/source-android/js/helper.js @@ -9,12 +9,12 @@ function friendicaRequest(login,api,rootwindow,callback) { try{ if (xhrequest.status=200){ //if (xhrequest.responseText!=""){ callback(xhrequest.responseText) }else{ - showMessage("Error","API:" +api+"\n NO RESPONSE"+xhrequest.statusText,rootwindow); - callback(xhrequest.responseText) + showMessage("Error","API:" +login.server+api+"\n NO RESPONSE"+xhrequest.statusText,rootwindow); + //callback(xhrequest.responseText) } } - catch (e){ - showMessage("Error", api+" "+e+" "+xhrequest.statusText,rootwindow) + catch (e){print(e); + showMessage("Error", xhrequest.responseText,rootwindow) } } } @@ -60,7 +60,7 @@ function friendicaWebRequest(url,rootwindow,callback) { } else if(xhrequest.readyState === XMLHttpRequest.DONE) { try{ callback(xhrequest.responseText); } - catch (e){ + catch (e){print(e); showMessage("Error",url+" "+e, rootwindow) } } @@ -130,3 +130,8 @@ var arraystring=JSON.stringify(array); arraystring=arraystring.replace(/[\[\]]/g , ''); return arraystring; } + +function cleanDate(date){ +var cleanedDate= date.slice(0,3)+", "+date.slice(8,11)+date.slice(4,7)+date.slice(25,30)+date.slice(10,25); +return cleanedDate +} diff --git a/source-android/js/news.js b/source-android/js/news.js index 61082c3..98798ae 100644 --- a/source-android/js/news.js +++ b/source-android/js/news.js @@ -32,13 +32,12 @@ function requestGroups(login,database,rootwindow,callback){ function getFriendsTimeline(login,database,contacts,onlynew,rootwindow,callback){ // retrieve and return timeline since last news, return contacts which are not friends and older than 2 days for update (friends can be updated in Contactstab) var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]); - var parameter = ""; + var parameter = "?count=50"; if(onlynew){db.transaction( function(tx) { var result = tx.executeSql('SELECT status_id from news WHERE username="'+login.username+'" AND messagetype=0 ORDER BY status_id DESC LIMIT 1'); // check for last news id - try{parameter="&since_id="+result.rows.item(0).status_id;}catch(e){};})} + try{parameter=parameter+"&since_id="+result.rows.item(0).status_id;}catch(e){};})} var newContacts=[]; - //print("/api/statuses/friends_timeline"+parameter); - Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){ + Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){print(obj); var news=JSON.parse(obj); var newContacts=findNewContacts(news,contacts); callback(news,newContacts) @@ -53,7 +52,7 @@ function getCurrentContacts(login,database,callback){ contactlist.push(result.rows.item(i).url ) //print(result.rows.item(i).url) } - var lastDate=Date.now()-172800000;// 2 days old + var lastDate=Date.now()-604800000;// 7 days old //print('SELECT url from contacts WHERE username="'+login.username+'" AND isFriend=0 AND imageAge>'+lastDate); var result2 = tx.executeSql('SELECT url from contacts WHERE username="'+login.username+'" AND isFriend=0 AND imageAge > '+lastDate); for (var j=0;j0){ for (var j=0;j0){ for (var k=0;j0){ - if (newsitemobject.dislike.length==1){dislikeText= QT.atob(newsitemobject.dislike[0].name)+" "+ qsTr("doesn't like this.")} + if (newsitemobject.dislike.length==1){dislikeText= Qt.atob(newsitemobject.dislike[0].name)+" "+ qsTr("doesn't like this.")} else {dislikeText= newsitemobject.dislike.length+" "+ qsTr("don't like this.")} } if (newsitemobject.attendyes.length>0){ @@ -42,7 +42,15 @@ WorkerScript.onMessage = function(msg) { if (newsitemobject.friendica_activities_self.indexOf(2)!=-1){self.disliked=1} } var friendica_activities={likeText:likeText,dislikeText:dislikeText,attendyesText:attendyesText,attendnoText:attendnoText,attendmaybeText:attendmaybeText,self:self} - //print(JSON.stringify(friendica_activities) ) ; + + var attachmentList=[];if(newsitemobject.attachments){ + var attachArray=JSON.parse(Qt.atob(newsitemobject.attachments)); + for (var image in attachArray){if(attachArray[image].mimetype=="image/gif"){ + attachmentList.push(attachArray[image]) + } + } + } + newsitemobject.attachmentList=attachmentList; var seconds=(msg.currentTime-newsitemobject.created_at)/1000; var timestring=""; if (seconds<60) {timestring=seconds+" "+qsTr("seconds") +" "+qsTr("ago");} @@ -54,7 +62,7 @@ WorkerScript.onMessage = function(msg) { else if (seconds<3888000){timestring=Math.round(seconds/86400)+" "+qsTr("days") +" "+qsTr("ago");} else if (seconds<5832000){timestring=Math.round(seconds/3888000)+" "+qsTr("month") +" "+qsTr("ago");} else if (seconds<69984000){timestring=Math.round(seconds/3888000)+" "+qsTr("months") +" "+qsTr("ago");} - else {timestring=Math.round(seconds/69984000)+" "+qsTr("years") +" "+qsTr("ago");} + else {timestring=Math.round(seconds/46656000)+" "+qsTr("years") +" "+qsTr("ago");} var data=({"newsitemobject": newsitemobject,"dateDiff":timestring,"friendica_activities":friendica_activities})} //print("News:"+j+msg.news.length+JSON.stringify(data)); msg.model.append(data);} diff --git a/source-android/js/service.js b/source-android/js/service.js index e2f62d3..8ea1252 100644 --- a/source-android/js/service.js +++ b/source-android/js/service.js @@ -121,8 +121,93 @@ function initDatabase(database) { // initialize the database object tx.executeSql('CREATE TABLE IF NOT EXISTS news(username TEXT, messagetype INT, text TEXT, created_at INT, in_reply_to_status_id INT, source TEXT, status_id INT, in_reply_to_user_id INT, geo TEXT,favorited TEXT, uid INT, statusnet_html TEXT, statusnet_conversation_id TEXT,friendica_activities TEXT, friendica_activities_self TEXT, attachments TEXT, friendica_owner INT)'); tx.executeSql('CREATE TABLE IF NOT EXISTS contacts(username TEXT, id INT, name TEXT, screen_name TEXT, location TEXT,imageAge INT, profile_image_url TEXT, description TEXT, profile_image BLOB, url TEXT, protected TEXT, followers_count INT, friends_count INT, created_at INT, favourites_count TEXT, utc_offset TEXT, time_zone TEXT, statuses_count INT, following TEXT, verified TEXT, statusnet_blocking TEXT, notifications TEXT, statusnet_profile_url TEXT, cid INT, network TEXT, isFriend INT)'); tx.executeSql('CREATE TABLE IF NOT EXISTS groups(username TEXT, groupname TEXT, gid INT, members TEXT)'); +tx.executeSql('CREATE TABLE IF NOT EXISTS events(username TEXT, id INT, start INT, end INT, allday INT, title TEXT, j INT, d TEXT, isFirst INT, uid INT, cid INT, uri TEXT, created INT, edited INT, desc TEXT, location TEXT, type TEXT, nofinish TEXT, adjust INT, ignore INT, permissions TEXT, guid INT, itemid INT, plink TEXT, authorName TEXT, authorAvatar TEXT, authorLink TEXT, html TEXT)'); })} +function cleanPermissions(oldperms){ + var newperms=oldperms.replace("<","");newperms=newperms.replace(">","");newperms="["+newperms+"]"; + var newpermArray=JSON.parse(newperms); +return (newpermArray) +} + +function getEvents(database,login,rootwindow,callback){ +var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]); + Helperjs.friendicaWebRequest(login.server+"/cal/"+login.username+"/json",rootwindow,function(obj){ + var events = JSON.parse(obj); + db.transaction( function(tx) { + for (var i=0;imaxnews){var lastvalidtimers= tx.executeSql('select created_at from news ORDER BY created_at DESC LIMIT ' +(newscount-maxnews)); - var lastvalidtime=lastvalidtimers.rows.item(maxnews).created_at; + if (newscount>maxnews){ + var lastvalidtimers= tx.executeSql('SELECT DISTINCT created_at FROM news ORDER BY created_at ASC LIMIT ' +(newscount-maxnews)); + var lastvalidtime=lastvalidtimers.rows.item(newscount-maxnews-1).created_at; var deleters = tx.executeSql('DELETE from news WHERE created_at<='+lastvalidtime)} callback() }) @@ -260,13 +358,17 @@ function processNews(callback){ function updateContactInDB(login,database,isFriend,contact){// for newstab and friendstab // var suffix=contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("."), contact.profile_image_url.length); // var imagename=login.imagestore+"contacts/"+contact.screen_name.trim()+suffix; - var imagename=login.imagestore+"contacts/"+contact.screen_name+"-"+contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("/")+1, contact.profile_image_url.length); - contacttimer.restart(); + +var imagename=""; +contacttimer.restart(); var currentTime=Date.now(); + if(contact.profile_image_url==""){root.currentContact=root.currentContact+1 } else{//print(JSON.stringify(contact)) + imagename=login.imagestore+"contacts/"+contact.screen_name+"-"+contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("/")+1, contact.profile_image_url.length); + xhr.setUrl(Qt.resolvedUrl(contact.profile_image_url)); xhr.setFilename(imagename); xhr.setDownloadtype("contact"); - xhr.download(); + xhr.download();} var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]); var result; db.transaction( function(tx) { diff --git a/source-android/qml/calendarqml/CalendarDay.qml b/source-android/qml/calendarqml/CalendarDay.qml new file mode 100644 index 0000000..55ecffe --- /dev/null +++ b/source-android/qml/calendarqml/CalendarDay.qml @@ -0,0 +1,47 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.4 + +Item { + id: calendarDay + width:7*mm + height: 7*mm + property int dateInt:Math.floor((Date.parse(model.date)-(new Date().getTimezoneOffset() * 60 * 1000))/86400000) + Rectangle { + id: placeHolder + color: 'lightblue'; antialiasing: true + anchors.fill:parent + } + Text { + id:daytext + anchors.right: parent.right + anchors.margins: 0.5*mm + color:(model.month==monthgrid.month)?"black":"grey" + wrapMode: Text.WrapAnywhere + text: model.day + font.bold: model.today + font.pixelSize: 4*mm + } + Rectangle { + id:eventRect + color:"black" + anchors.margins: 0.5*mm + anchors.bottom: calendarDay.bottom + width: parent.width-mm + height: mm + visible: eventdays.indexOf(dateInt)>-1 + } + MouseArea { + anchors.fill: calendarDay + onClicked: { + var eventDate=[]; + var idx = eventdays.indexOf(dateInt); + while (idx != -1) { + eventDate.push(idx); + idx = eventdays.indexOf(dateInt,idx + 1) + } + var component = Qt.createComponent("qrc:/qml/calendarqml/EventList.qml"); + if (component.status== Component.Ready){ + var eventlist = component.createObject(calendartab,{"daylist": eventDate})} + } + } +} diff --git a/source-android/qml/calendarqml/CalendarTab.qml b/source-android/qml/calendarqml/CalendarTab.qml new file mode 100644 index 0000000..7127a31 --- /dev/null +++ b/source-android/qml/calendarqml/CalendarTab.qml @@ -0,0 +1,134 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.1 +import QtQml 2.2 +import Qt.labs.calendar 1.0 +import QtQuick.Layouts 1.3 +import "qrc:/js/service.js" as Service +import "qrc:/js/helper.js" as Helperjs +import "qrc:/qml/calendarqml" +import "qrc:/qml/genericqml" + +Rectangle { + id:calendarrectangle + y:1 + width:root.width-mm + height:root.height-5*mm + color: '#fff' + property date currentTime: new Date() + property int offsetTime: currentTime.getTimezoneOffset() * 60 * 1000 + property var events:[] + property var eventdays:[] + onEventdaysChanged: print(JSON.stringify(eventdays)) + + function showEvents(friend){ + if(friend=="backButton"){Service.eventsfromdb(db,login.username,function(eventArray,dayArray){ + events=eventArray; + eventdays=dayArray}) + } + else if (friend!=""){ + calendartab.calendartabstatus=friend.substring(friend.lastIndexOf("/")+1,friend.length) + Service.requestFriendsEvents(login,friend,calendartab,function(eventArray,dayArray){ + events=eventArray; + eventdays=dayArray}) + } + else {calendartab.calendartabstatus="Events"; + Service.eventsfromdb(db,login.username,function(eventArray,dayArray){ + events=eventArray; + eventdays=dayArray; + calBusy.running=false + }) + } + } + + BusyIndicator{ + id: calBusy + anchors.horizontalCenter: calendarView.horizontalCenter + anchors.top:calendarView.top + anchors.topMargin: 2*mm + width:10*mm + height: 10*mm + running: false + } + + + BlueButton{ + id: updateEvents + anchors.top: parent.top + anchors.topMargin: 0.5*mm + anchors.right:calendartabstatusButton.left + anchors.rightMargin:mm + text:"\uf021" + onClicked: { + + Service.getEvents(db,login, calendartab,function(){ + showEvents("") + })}} + + BlueButton{ + id: calendartabstatusButton + anchors.top: parent.top + anchors.topMargin: 0.5*mm + anchors.right: parent.right + anchors.rightMargin:2*mm + text: calendartab.calendartabstatus=="Events"?qsTr("Events"):calendartabstatus + onClicked: {calendartabmenu.popup()} + } + Menu { + id:calendartabmenu + MenuItem { + text: qsTr("Own Calendar") + onTriggered: { + calendartab.calendartabstatus="Events"; + // calendartabstatusButton.text=qsTr("own Calendar"); + showEvents("")} + } + } + + ListView{ + id: calendarView + x: mm;y:8*mm + width: parent.width-2*mm; height: parent.height-9*mm + clip: true + snapMode: ListView.SnapOneItem + orientation: ListView.Horizontal + highlightRangeMode: ListView.StrictlyEnforceRange + model: CalendarModel {id:calendarModel + from: new Date() + to: new Date(new Date().valueOf()+93312000000) + } + delegate: + ColumnLayout{ + width:calendarView.width + Text{ + font.bold: true + Layout.fillWidth: true + horizontalAlignment:Text.AlignHCenter + text: model.year + } + Text{ + text: Qt.locale().standaloneMonthName(model.month) + Layout.fillWidth: true + horizontalAlignment:Text.AlignHCenter + } + DayOfWeekRow{ + locale: monthgrid.locale + Layout.fillWidth: true + } + + MonthGrid { + id: monthgrid + Layout.fillWidth: true + month: model.month + year: model.year + locale: Qt.locale() + delegate: CalendarDay{} + } + } + ScrollIndicator.horizontal: ScrollIndicator { } + } + + Component.onCompleted: { + root.eventSignal.connect(showEvents); + if (calendartab.calendartabstatus=="Events"){showEvents("")} + } + } diff --git a/source-android/qml/calendarqml/EventList.qml b/source-android/qml/calendarqml/EventList.qml new file mode 100644 index 0000000..fbb1632 --- /dev/null +++ b/source-android/qml/calendarqml/EventList.qml @@ -0,0 +1,85 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.2 +import "qrc:/js/service.js" as Service +import "qrc:/js/helper.js" as Helperjs +import "qrc:/qml/genericqml" + +Rectangle{ + id:eventList + z:2 + border.color: "grey" + width: parent.width-4*mm + height:parent.height-12*mm + x:mm + y:mm + property var daylist:[] + + BlueButton{ + id:closeButton + anchors.top: parent.top + anchors.topMargin: 1*mm + anchors.right: parent.right + anchors.rightMargin: 1*mm + text: "\uf057" + onClicked:{eventList.destroy()} + } + ListView { + id: eventlistView + x: mm + y:closeButton.height+2*mm + width: eventList.width-2*mm + height: eventList.height-closeButton.height-4*mm + clip: true + model: eventModel + delegate: eventItem + } + + ListModel{ + id: eventModel + } + + Component.onCompleted:{ + //print(JSON.stringify(daylist)) + for (var i=0; i"+qsTr("Connect")+"
") + +Rectangle { + id: wrapper + + width:friendsTabView.width; + height:friendsTabView.height-15*mm + border.color: "grey" + color:"white" + Image { + id: photoImage + x:mm + y:mm + width: 15*mm + height:15*mm + source:(contact.profile_image!="")? "file://"+contact.profile_image : contact.profile_image_url + onStatusChanged: if (photoImage.status == Image.Error) {source="qrc:/images/defaultcontact.jpg"} + } + + Label { + id: namelabel + x: mm + width:friendsTabView.width-4*mm + height: 3*mm + text:Qt.atob(contact.name)+" (@"+contact.screen_name+")" + elide:Text.ElideRight + anchors.topMargin: 0 + anchors.left: photoImage.left + color: "#303030" + font.pixelSize: 4*mm + anchors.top: photoImage.bottom + } Rectangle{ id: detailsrectangle anchors.top: namelabel.bottom @@ -69,10 +107,27 @@ Rectangle{ } } + + BlueButton{ + id:eventbutton + visible:(contact.network=="dfrn") + text:"\uf073" + onClicked:{ + root.currentIndex=3; + calendartab.active=true; + calendartab.calendartabstatus="Friend" + root.eventSignal(contact.url); + } + } + BlueButton{ id: closeButton text: "\uf057" //"close" - onClicked:{detailsrectangle.destroy();contactComponent.state="";friendsTabView.contactSignal} + onClicked:{contactLargeComponent.destroy(); + //contactComponent.state=""; + friendsTabView.contactSignal} } } } +} +} diff --git a/source-android/qml/contactqml/ContactDetailsComponentOld.qml b/source-android/qml/contactqml/ContactDetailsComponentOld.qml new file mode 100644 index 0000000..ffdeeae --- /dev/null +++ b/source-android/qml/contactqml/ContactDetailsComponentOld.qml @@ -0,0 +1,91 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.3 +import "qrc:/qml/genericqml" + +Rectangle{ + id: detailsrectangle + anchors.top: namelabel.bottom + anchors.topMargin: 2*mm + + ScrollView{ + horizontalScrollBarPolicy:Qt.ScrollBarAlwaysOff + frameVisible: true + id:namelabelflickable + width: root.width-10*mm + height:friendsTabView.height-45*mm + x: mm + clip:true + Text{ + id:namelabeltext + width: namelabelflickable.width + height: implicitHeight + font.pixelSize: 3*mm + textFormat:Text.RichText + wrapMode: Text.Wrap + text:""+qsTr("Description")+": "+Qt.atob(contact.description)+"
"+qsTr("Location")+": "+contact.location+"
"+qsTr("Posts")+": "+contact.statuses_count+ + "
"+qsTr("URL")+": "+contact.url+"
"+ + connectUrl+ ""+qsTr("Created at")+": "+createdAtDate.toLocaleString(Qt.locale()) + onLinkActivated: { + Qt.openUrlExternally(link)} + } + } + + Row{ + anchors.top: namelabelflickable.bottom + anchors.topMargin: 2*mm + x: mm + spacing:4 + + BlueButton{ + id:photobutton + text: "\uf03e" // "Photos" + visible:(contact.network=="dfrn") + onClicked:{ + fotostab.phototabstatus="Contact"; + root.currentIndex=2; + fotostab.active=true; + root.fotoSignal(contact) ; + } + } + + BlueButton{ + id:messagebutton + text: "\uf0e6" //"Messages" + onClicked:{ + root.currentIndex=0; + newstab.active=true; + root.messageSignal(contact.id) ; + } + } + + BlueButton{ + id:dmbutton + visible: (contact.following=="true") + text: "\uf040" //"DM" + onClicked:{ + root.currentIndex=0; + newstab.active=true; + root.directmessageSignal(contact.screen_name); + } + } + + + BlueButton{ + id:eventbutton + visible:(contact.network=="dfrn") + text:"\uf073" + onClicked:{ + root.currentIndex=3; + calendartab.active=true; + calendartab.calendartabstatus="Friend" + root.eventSignal(contact.url); + } + } + + BlueButton{ + id: closeButton + text: "\uf057" //"close" + onClicked:{detailsrectangle.destroy();contactComponent.state="";friendsTabView.contactSignal} + } + } + } diff --git a/source-android/qml/contactqml/FriendsTab.qml b/source-android/qml/contactqml/FriendsTab.qml index 1686ddb..a82ce97 100644 --- a/source-android/qml/contactqml/FriendsTab.qml +++ b/source-android/qml/contactqml/FriendsTab.qml @@ -11,12 +11,13 @@ Rectangle { color: "white" function showContactdetails(contact){ + var component = Qt.createComponent("qrc:/qml/contactqml/ContactDetailsComponent.qml"); if(contact.isFriend){ friendsTabView.currentIndex=0; - friendsTabView.contactsSignal(contact) + var contactDetails = component.createObject(friendstab,{"contact": contact}) } else{friendsTabView.currentIndex=1; - friendsTabView.contactsSignal(contact) + var contactDetails = component.createObject(friendstab,{"contact": contact}) } } TabView{ @@ -30,7 +31,7 @@ Rectangle { signal contactsSignal(var contact) signal groupsSignal(var username) onCurrentIndexChanged:{ - if (currentIndex==0){//print("currentindex 0"); + if (currentIndex==0){ contactsSignal("") } else if (currentIndex==1){ @@ -60,18 +61,14 @@ Rectangle { title: qsTr("Friends") Rectangle{ id: friendsGridTab - function makebig(friendindex){print("friendindex"+friendindex);if (friendindex){friendsModel.set(friendindex,{"status":"large"})}} - function showFriends(contact,callback){//print("contact"+JSON.stringify(contact)); + function showFriends(contact){ try {friendsModel.clear()} catch(e){print(e)}; - var friendindex; Helperjs.readData(db,"contacts",root.login.username,function(friendsobject){ for (var i=0;i1){ + if(Helperjs.getCount(db,login,"contacts","screen_name",friendsobject[i].screen_name)>1){ friendsobject[i].screen_name=friendsobject[i].screen_name+"+"+friendsobject[i].cid } - if(contact){if (contact.cid==friendsobject[i].cid){status="large"}} - friendsModel.append({"contact":friendsobject[i],"status":status}); + friendsModel.append({"contact":friendsobject[i]}); } @@ -113,12 +110,11 @@ Rectangle { clip: true cellHeight: 16*mm cellWidth: 17*mm - add: Transition { - NumberAnimation { properties: "x,y"; from: 300; duration: 1000 } - } + //add: Transition { + // NumberAnimation { properties: "x,y"; from: 300; duration: 1000 } + // } model: friendsModel delegate: ContactComponent { } - Component.onCompleted: positionViewAtBeginning() } ListModel{id:friendsModel} @@ -132,7 +128,7 @@ Rectangle { } Tab{ - title: qsTr("Other Contacts") + title: qsTr("Contacts") Rectangle{ id: contactsGridTab @@ -140,9 +136,7 @@ Rectangle { try {contactsModel.clear()} catch(e){print(e)}; Helperjs.readData(db, "contacts",root.login.username,function(contactsobject){ for (var j=0;j0){// download first contact image and update db Service.updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])} else if (contactLoadType!=""){ @@ -49,6 +50,7 @@ TabView{ } onCurrentContactChanged:{// download next contact image after photoplaceholder is finished saving and update db + if(currentContact0){newstab.conversation=[]} else{Service.cleanNews(root.db,function(){Qt.quit()})} } else if (currentIndex==2){fotoSignal("backButton")} @@ -113,8 +117,8 @@ TabView{ tab: Rectangle { color: styleData.selected?"sky blue":"light blue" border.color: "light grey" - implicitWidth: root.width/4-2*mm - implicitHeight: 4*mm + implicitWidth: root.width/5-2*mm + implicitHeight: 5*mm Text { id: text anchors.centerIn: parent text: styleData.title @@ -145,9 +149,17 @@ TabView{ property string phototabstatus:"Images" source: (root.currentIndex==2)?"qrc:/qml/photoqml/PhotoTab.qml":"" } + Tab{ + title: "\uf073" + id: calendartab + property string calendartabstatus:"Events" + source: (root.currentIndex==3)?"qrc:/qml/calendarqml/CalendarTab.qml":"" + } + + Tab{ title:"\uf085" id: configtab - source: (root.currentIndex==3)?"qrc:/qml/configqml/ConfigTab.qml":"" + source: (root.currentIndex==4)?"qrc:/qml/configqml/ConfigTab.qml":"" } } diff --git a/source-android/qml/newsqml/Conversation.qml b/source-android/qml/newsqml/Conversation.qml index 6e3812e..4864f91 100644 --- a/source-android/qml/newsqml/Conversation.qml +++ b/source-android/qml/newsqml/Conversation.qml @@ -1,34 +1,106 @@ -// ConversationStack with buttons +// ConversationView with button import QtQuick 2.0 import "qrc:/js/helper.js" as Helperjs import "qrc:/qml/genericqml" Rectangle { - id:conversationStack + id:conversationList property var news y:1 - color: "white" - width:root.width-2*mm - height:root.height-8*mm + z:2 + color: "white" + border.color: "grey" + width:root.width-5*mm + height: conversationView.height+10*mm + Connections{ + target:newstab + onConversationChanged:{ + if(newstab.conversation.length==0){ + newsView.positionViewAtIndex(newsStack.conversationIndex,ListView.Beginning); + conversationList.destroy(); conversationsymbol.color="grey" + } + } + } ListView { id: conversationView x:3*mm y:8*mm - width: conversationStack.width-4*mm - height: conversationStack.height-10*mm + width: conversationList.width-4*mm + height: contentHeight clip: true spacing: 0 + footer: footerReply model: conversationModel delegate: Newsitem{} } - ListModel{id: conversationModel} + Component { id:footerReply + Rectangle{ + border.color: "#EEEEEE" + border.width: 1 + color:"lightgrey" + width:conversationView.width + height:Math.max(replyText.contentHeight+2*mm,6*mm) + Rectangle{ + color: "white" + radius:0.5*mm + anchors.left: parent.left + anchors.leftMargin:mm + anchors.top:parent.top + anchors.topMargin: 0.5*mm + width:parent.width-12*mm + height:Math.max( replyText.contentHeight,5*mm) - WorkerScript { - id: conversationWorker - source: "qrc:/js/newsworker.js" - } + TextInput { + id: replyText + font.pixelSize: 3*mm + wrapMode: Text.Wrap + anchors.fill: parent + selectByMouse: true + } + } + + BlueButton { + id: sendButton + text: "\uf1d9" + anchors.right: parent.right + anchors.rightMargin:mm + anchors.top:parent.top + anchors.topMargin: 0.5*mm + color:"white" + onClicked: { try{ + var body=replyText.getText(0,replyText.length); + newsBusy.running=true; + replyText.text="" + xhr.clearParams(); + xhr.setLogin(login.username+":"+Qt.atob(login.password)); + if (conversationModel.get(0).newsitemobject.messagetype==0){ + xhr.setParam("source", "Friendiqa"); + xhr.url= login.server + "/api/statuses/update.json"; + xhr.setParam("status", body); + xhr.setParam("in_reply_to_status_id", conversationModel.get(conversationModel.count-1).newsitemobject.status_id)} + else {xhr.url= login.server + "/api/direct_messages/new.json"; + xhr.setParam("text", body); + xhr.setParam("screen_name",conversationModel.get(conversationModel.count-1).newsitemobject.screen_name); + xhr.setParam("replyto", conversationModel.get(conversationModel.count-1).newsitemobject.status_id) + } + xhr.post(); + //replyText.text="" + } catch(e){Helperjs.showMessage("Error",e.toString(),root)} + } + } + } + } + + + + ListModel{id: conversationModel} + + WorkerScript { + id: conversationWorker + source: "qrc:/js/newsworker.js" + } BlueButton { id: closeButton @@ -37,10 +109,11 @@ Rectangle { anchors.topMargin: 1*mm anchors.right: parent.right anchors.rightMargin: 1*mm - text: "\uf057"// qsTr("Close") + text: "\uf057" onClicked: { - newstab.newstabstatus=login.newsViewType; - newsStack.pop() + newsView.positionViewAtIndex(newsStack.conversationIndex,ListView.Beginning); + conversationList.destroy(); + conversationsymbol.color="grey" } } diff --git a/source-android/qml/newsqml/ImageDialog.qml b/source-android/qml/newsqml/ImageDialog.qml index 4187fcf..34add5a 100644 --- a/source-android/qml/newsqml/ImageDialog.qml +++ b/source-android/qml/newsqml/ImageDialog.qml @@ -42,12 +42,11 @@ Rectangle{ clip: true model: imageModel delegate: imageItem - } FolderListModel{ id: imageModel - nameFilters: ["*.png", "*.jpg",".jpeg","*.JPG"] + nameFilters: ["*.png", "*.jpg",".jpeg","*.JPG","*.gif"] sortField: FolderListModel.Time sortReversed:false showDotAndDotDot: true @@ -111,8 +110,9 @@ Rectangle{ directory=fileURL } else{ - attachImageURL=fileURL; - imageDialog.destroy() + attachImageURLs.push(fileURL); + attachImage(fileURL); + imageDialog.destroy() } } } diff --git a/source-android/qml/newsqml/MessageSend.qml b/source-android/qml/newsqml/MessageSend.qml index 541c228..a093cc8 100644 --- a/source-android/qml/newsqml/MessageSend.qml +++ b/source-android/qml/newsqml/MessageSend.qml @@ -16,7 +16,7 @@ Flickable{ id:messageSend property string parentId: "" property string reply_to_user:"" - property string attachImageURL: ""; + property var attachImageURLs: []; property int directmessage: 0; property var contacts: [] property var groups: [] @@ -25,11 +25,13 @@ Flickable{ property var group_allow:login.permissions[2] property var group_deny:login.permissions[3] - onAttachImageURLChanged: {if(attachImageURL!=""){ - var imageAttachmentObject=Qt.createQmlObject('import QtQuick 2.0; Image {id:imageAttachment; source:"'+ - attachImageURL.toString()+'"; width: 15*mm; height: 15*mm;fillMode: Image.PreserveAspectFit;MouseArea{anchors.fill:parent;onClicked:{attachImageURL="";imageAttachment.destroy()}}}',messageColumn,"attachedImage"); - console.log("You chose: " + attachImageURL) - }} + function attachImage(url){ + //onAttachImageURLsChanged: {if(attachImageURL!=""){ + var imageAttachmentObject=Qt.createQmlObject('import QtQuick 2.0; Image {id:imageAttachment'+attachImageURLs.length+'; source:"'+ + url.toString()+'"; width: 15*mm; height: 15*mm;fillMode: Image.PreserveAspectFit;MouseArea{anchors.fill:parent;onClicked:{attachImageURLs.splice(attachImageURLs.indexOf("'+url+'",1)); imageAttachment'+attachImageURLs.length+'.destroy()}}}',messageColumn,"attachedImage"); + console.log("You chose: " + url) + } + function statusUpdate(title,status,in_reply_to_status_id,attachImageURL) { xhr.url= login.server + "/api/statuses/update.json"; xhr.setLogin(login.username+":"+Qt.atob(login.password)); @@ -42,7 +44,7 @@ Flickable{ if (group_deny.length>0) {xhr.setParam("group_deny", Helperjs.cleanArray(group_deny))}; if (contact_allow.length>0) {xhr.setParam("contact_allow", Helperjs.cleanArray(contact_allow))}; if (contact_deny.length>0) {xhr.setParam("contact_deny", Helperjs.cleanArray(contact_deny))}; - if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )}; + if (attachImageURL.length>0) {for (var image in attachImageURL){xhr.setImageFileParam("media", attachImageURL[image] )}}; xhr.post(); } @@ -122,12 +124,11 @@ Flickable{ } } - Row{ spacing:2 BlueButton{id:permButton visible: (directmessage==1)?false:true - text: ((contact_allow.length==0)&&(contact_deny.length==0)&&(group_allow.length==0)&&(group_deny.length==0))?"\uf09c":"\uf023"//qsTr("Permissions") + text: ((contact_allow.length==0)&&(contact_deny.length==0)&&(group_allow.length==0)&&(group_deny.length==0))?"\uf09c":"\uf023" onClicked: { var component = Qt.createComponent("qrc:/qml/newsqml/PermissionDialog.qml"); var permissions = component.createObject(messageColumn); @@ -137,14 +138,14 @@ Flickable{ text: "\uf0c6" visible:(directmessage==0) onClicked: { - if (attachImageURL!=""){ - Helperjs.showMessage( qsTr("Error"),qsTr("Only one attachment. Remove other attachment first!"), messageColumn)} - else{print(filesystem.homePath); - var defaultDirectory="file://"+osSettings.attachImageDir;//"file:///storage/emif.open() - print(defaultDirectory); - var component = Qt.createComponent("qrc:/qml/newsqml/ImageDialog.qml"); - var imagedialog = component.createObject(messageSend,{"directory": defaultDirectory}); - } + if (attachImageURLs.length>0){//Server currently accepts only one attachment + Helperjs.showMessage( qsTr("Error"),qsTr("Only one attachment supported at the moment.\n Remove other attachment first!"), messageColumn) + } + else{ + var defaultDirectory="file://"+osSettings.attachImageDir; + var component = Qt.createComponent("qrc:/qml/newsqml/ImageDialog.qml"); + var imagedialog = component.createObject(messageSend,{"directory": defaultDirectory}); + } } } BlueButton{ @@ -188,7 +189,7 @@ Flickable{ var title=titleField.text.replace("\"","\'"); var body=bodyField.getText(0,bodyField.length); if (directmessage==0){ - statusUpdate(title,body,messageSend.parentId,attachImageURL.toString())} + statusUpdate(title,body,messageSend.parentId,attachImageURLs)} else {dmUpdate(title,body,"",messageSend.reply_to_user) } newstab.newstabstatus=login.newsViewType; newsStack.pop() } diff --git a/source-android/qml/newsqml/NewsTab.qml b/source-android/qml/newsqml/NewsTab.qml index 9e1d57a..14dd731 100644 --- a/source-android/qml/newsqml/NewsTab.qml +++ b/source-android/qml/newsqml/NewsTab.qml @@ -13,23 +13,13 @@ Item { } } - Connections{ - target:newstab - onConversationChanged:{ - newsBusy.running=false; - newstab.newstabstatus="Conversation"; - //newsStack.push({item:"qrc:/qml/newsqml/Conversation.qml",properties:{"news": conversation}}) - showNews(conversation); - } - } - Connections{ target:root onCurrentContactChanged:{ if (root.newContacts.length>0){ if(root.currentContact(-15*mm-1)){print("refreshing"); + onDragEnded:{if(contentY<-8*mm){//print("refreshing"); + newsBusy.running=true; + newstab.newstabstatus=login.newsViewType; + root.contactLoadType="news"; + var onlynew=true; + Newsjs.getFriendsTimeline(login,db,contactlist,onlynew,newstab,function(ns,nc){ + root.news=ns;root.newContacts=nc;root.currentContact=0; + if (ns.length==0){// update last 20 existing news for changes and likes + onlynew=false; + Newsjs.getFriendsTimeline(login,db,contactlist,onlynew,newstab,function(rns,rnc){ + root.contactLoadType="news"; + root.news=rns;root.newContacts=rnc;root.currentContact=0}) + } + }) + }} + } ListModel{id: newsModel} @@ -331,10 +267,10 @@ Item { } MenuItem { - text: qsTr("Tree") + text: qsTr("Conversations") onTriggered:{ newsModel.clear(); - newstab.newstabstatus="Tree"; + newstab.newstabstatus="Conversations"; Newsjs.chatsfromdb(db,root.login.username,function(news){showNews(news)}) } } diff --git a/source-android/qml/newsqml/Newsitem.qml b/source-android/qml/newsqml/Newsitem.qml index 19a2185..d9c9fa7 100644 --- a/source-android/qml/newsqml/Newsitem.qml +++ b/source-android/qml/newsqml/Newsitem.qml @@ -7,9 +7,23 @@ import "qrc:/js/helper.js" as Helperjs Item { id: newsitem - width: newsView.width - height:Math.max((itemMessage.height+topFlow.height+friendicaActivities.height+4*mm),profileImage.height+user_name.height+mm) - + width: parent.width + height:toprow.height+friendicaActivities.height+controlrow.height+1//Math.max((itemMessage.height+topFlow.height+friendicaActivities.height+4*mm),profileImage.height+user_name.height+mm) + + Connections{ + target:newstab + onConversationChanged:{ + newsBusy.running=false; + if(index==newsStack.conversationIndex){ + if(newstab.conversation.length>0){ + var component = Qt.createComponent("qrc:/qml/newsqml/Conversation.qml"); + var conversation = component.createObject(friendicaActivities,{"news":newstab.conversation}); + } + else{conversationsymbol.color="grey"} + } + } + } + property string attending: "" onAttendingChanged: {attendLabel.visible=true; attendLabel.text= qsTr("attending: ")+ qsTr(attending)} @@ -19,9 +33,7 @@ Item { function showActivityContacts(contacts){ var component = Qt.createComponent("qrc:/qml/newsqml/FriendicaActivities.qml"); var imagedialog = component.createObject(friendicaActivities,{"activitymembers": contacts}); - } - Rectangle{width:newsitem.width; height: 1; anchors.bottom: newsitem.bottom; color:"light grey"} Rectangle{ @@ -29,7 +41,8 @@ Item { height:newsitem.height-1 color: (newsitemobject.messagetype==1)?"#ffe6e6" : "white" - Column { + Row{id:toprow + Column { id: authorcolumn width: 8*mm @@ -41,7 +54,7 @@ Item { height: 7*mm MouseArea{ anchors.fill: parent - onClicked:{print(root.currentIndex); + onClicked:{ try{root.currentIndex=1; friendstab.active=true; root.contactdetailsSignal(newsitemobject.user)} catch (e){Helperjs.showMessage("Error",e,root)} @@ -61,7 +74,7 @@ Item { Column { id:newscolumn width: newsitem.width-8*mm - anchors.left: authorcolumn.right + //anchors.left: authorcolumn.right Flow{ id:topFlow @@ -92,7 +105,7 @@ Item { Label { id:newscountLabel - visible:((newstabstatus=="Tree")&&(newsitemobject.newscount>1))?true:false + visible:((newstabstatus=="Conversations")&&(newsitemobject.newscount>1))?true:false color: "grey" height:3.5*mm font.pixelSize: 1.5*mm @@ -117,12 +130,25 @@ Item { wrapMode: Text.Wrap onLinkActivated:{ Qt.openUrlExternally(link)} + Component.onCompleted:{ + if (newsitemobject.attachmentList.length>0){ + for(var attachments in newsitemobject.attachmentList){// (newsitemobject.attachmentList[attachments].url); + var attachcomponent = Qt.createQmlObject('import QtQuick 2.0; '+ + 'AnimatedImage {id:gif;source: "'+newsitemobject.attachmentList[attachments].url+ + '";onStatusChanged: playing = (status == AnimatedImage.Ready)}', + friendicaActivities,"Attachment"+attachments); + } + } + } } - - Flow{ + } + } + Flow{ id:friendicaActivities + anchors.top:toprow.bottom width:parent.width spacing:mm + Label{color: "grey" font.pixelSize: 1.5*mm text: friendica_activities.likeText @@ -162,11 +188,22 @@ Item { onClicked: { showActivityContacts(newsitemobject.attendmaybe)} } } + Label{ + id:attendLabel + //visible: false + color: "grey" + height:3.5*mm + font.pixelSize: 1.5*mm + horizontalAlignment: Label.AlignRight + text: (friendica_activities.self.attending)?(qsTr("Attending: ")+ qsTr(friendica_activities.self.attending)):"" + } } - Row{ + Row{id:controlrow + anchors.top:friendicaActivities.bottom + CheckBox{ id:likeCheckbox - height:3*mm + //height:3*mm width:8*mm visible: (newsitemobject.messagetype==0)? true:false checked:(friendica_activities.self.liked==1)?true:false @@ -195,7 +232,7 @@ Item { } CheckBox{ id: dislikeCheckbox - height:3*mm + //height:3*mm width:8*mm visible: (newsitemobject.messagetype==0)? true:false checked: (friendica_activities.self.disliked==1)?true:false @@ -222,10 +259,30 @@ Item { if (dislikeCheckbox.checked==true){Newsjs.like(root.login,root.db,1,"dislike",newsitemobject.status_id,root);likeCheckbox.checked=false; model.friendica_activities.self.disliked=0} else {Newsjs.like(root.login,root.db,0,"dislike",newsitemobject.status_id,root); model.friendica_activities.self.disliked=1}} } + +// Rectangle{ +// width: 8*mm +// height: 3*mm +// color:"transparent" +// Text{ +// id:trashsymbol +// color: "grey" +// anchors.centerIn: parent +// font.pixelSize: 2*mm +// font.bold: true +// text: "\uf1f8" +// } +// MouseArea{ +// anchors.fill:parent +// onClicked: { +// Newsjs.deleteNews(root.login,root.db,newsitemobject.status_id,newsitemobject.messagetype,root,function(reply){ +// newsModel.remove(index)}) +// }} +// } CheckBox { id:favoritedCheckbox visible:(newsitemobject.messagetype==0) - width: 7*mm + width: 8*mm style: CheckBoxStyle { background: Rectangle { implicitWidth: 6*mm @@ -251,7 +308,7 @@ Item { } } Rectangle{ - width: 7*mm + width: 8*mm height: 3*mm color:"transparent" Text{ @@ -267,7 +324,7 @@ Item { onClicked: {newsmenu.popup()}} } Rectangle{ - width: 7*mm + width: 8*mm height: 3*mm visible:newstab.newstabstatus!="Conversation" color:"transparent" @@ -281,20 +338,15 @@ Item { } MouseArea{ anchors.fill:parent - onClicked: { conversationsymbol.color="black";showConversation(index,newsitemobject)} + onClicked:{ + conversationsymbol.color="black"; + showConversation(index,newsitemobject) + } } } - Label{ - id:attendLabel - //visible: false - color: "grey" - height:3.5*mm - font.pixelSize: 1.5*mm - horizontalAlignment: Label.AlignRight - text: (friendica_activities.self.attending)?(qsTr("Attending: ")+ qsTr(friendica_activities.self.attending)):"" - } + } -} + Menu { id:newsmenu MenuItem { @@ -350,6 +402,4 @@ Item { } } } -} -} - +}} diff --git a/source-android/qml/newsqml/PermissionDialog.qml b/source-android/qml/newsqml/PermissionDialog.qml index 8796326..4040c76 100644 --- a/source-android/qml/newsqml/PermissionDialog.qml +++ b/source-android/qml/newsqml/PermissionDialog.qml @@ -32,7 +32,7 @@ Rectangle{ Text{ x:0.5*mm y:0.5*mm - text: "Contacts" + text: qsTr("Friends") } ListView { id: contactView @@ -93,7 +93,7 @@ Rectangle{ Text{ x:contactView.width+2*mm y:0.5*mm - text: "Groups" + text: qsTr("Groups") } ListView { id: groupView diff --git a/source-android/qml/photoqml/PhotoTab.qml b/source-android/qml/photoqml/PhotoTab.qml index 10445e8..09ed13b 100644 --- a/source-android/qml/photoqml/PhotoTab.qml +++ b/source-android/qml/photoqml/PhotoTab.qml @@ -105,7 +105,7 @@ Rectangle { anchors.topMargin: 0.5*mm anchors.right: parent.right anchors.rightMargin:2*mm - text: qsTr(phototabstatus) + text: fotostab.phototabstatus=="Images"?qsTr("Own Images"):fotostab.phototabstatus onClicked: {phototabmenu.popup()} } Menu { @@ -114,7 +114,7 @@ Rectangle { text: qsTr("Own Images") onTriggered: { fotostab.phototabstatus="Images"; - phototabstatusButton.text=qsTr("own images"); + // phototabstatusButton.text=qsTr("Own images"); showFotos("")} } } diff --git a/source-android/translations/friendiqa-de.qm b/source-android/translations/friendiqa-de.qm new file mode 100644 index 0000000..3a0c325 Binary files /dev/null and b/source-android/translations/friendiqa-de.qm differ diff --git a/source-android/translations/friendiqa-de.ts b/source-android/translations/friendiqa-de.ts new file mode 100644 index 0000000..49396a7 --- /dev/null +++ b/source-android/translations/friendiqa-de.ts @@ -0,0 +1,470 @@ + + + + + CalendarTab + + + Events + Termine + + + + Own Calendar + Eigener Kalender + + + + ConfigTab + + + + + + User + Name + + + + Server + Server + + + + Password + Passwort + + + + Image dir. + Bildverz. + + + + Max. News + Max. Nachr. + + + + News as + Anzeige + + + + Interval (0=None) + Intervall (0=keins) + + + + Confirm + Bestätigen + + + + No server given! + Kein Server angegeben! + + + + No username given! + Kein Nutzername angegeben! + + + + No password given! + Kein Passwort angegeben! + + + + No image directory given! + Kein Verzeichnis für Bilder angegeben! + + + + No maximum news number given! + Maximale News-Anzahl nicht angegeben! + + + + Timeline + Chronologisch + + + + Conversations + Unterhaltungen + + + + ContactComponent + + + Connect + Kontaktanfrage + + + + ContactDetailsComponent + + + Connect + Kontaktanfrage + + + + Description + Beschreibung + + + + Location + Ort + + + + Posts + Beiträge + + + + URL + Profilseite + + + + Created at + Erstellt + + + + FriendsTab + + + Friends + Freunde + + + + Contacts + Kontakte + + + + Groups + Gruppen + + + + MessageSend + + + Title (optional) + Überschrift (optional) + + + + Error + Fehler + + + + Only one attachment supported at the moment. + Remove other attachment first! + Nur ein Anhang derzeit unterstützt. + Lösche zuerst den anderen Anhang! + + + + NewsTab + + + Download profile image for + Lade Profilbild für + + + + More + Mehr + + + + Timeline + Chronologisch + + + + Favorites + Markierte News + + + + Conversations + Unterhaltungen + + + + Notifications + Meldungen + + + + Newsitem + + + attending: + Teilnahme + + + + Source: + Quelle: + + + + Direct Message + Direktnachricht + + + + In reply to + Antwort an + + + + comments + Kommentare + + + + Attending: + Teilnahme: + + + + Reply + Antworten + + + + DM + Direktnachricht + + + + Repost + Teilen + + + + Conversation + Unterhaltung + + + + Attending + Teilnahme + + + + yes + ja + + + + maybe + vielleicht + + + + no + nein + + + + Delete + Löschen + + + + PermissionDialog + + + Friends + Freunde + + + + Groups + Gruppen + + + + PhotoTab + + + 's images + s Bilder + + + + + Own Images + Eigene Bilder + + + + More + Mehr + + + + SmileyDialog + + + Standard + Standard + + + + Addon + Addon + + + + Adult + XXX + + + + newsworker + + + likes this. + mag das. + + + + like this. + mögen das. + + + + doesn't like this. + mag das nicht. + + + + don't like this. + mögen das nicht. + + + + will attend. + nehmen teil. + + + + persons will attend. + Personen nehmen teil. + + + + will not attend. + nimmt nicht teil. + + + + persons will not attend. + Personen nehmen nicht teil. + + + + may attend. + nimmt vielleicht teil. + + + + persons may attend. + Personen nehmen vielleicht teil. + + + + yes + ja + + + + no + nein + + + + maybe + vielleicht + + + + seconds + Sekunden + + + + + + + + + + + + + ago + her + + + + minute + Minute + + + + minutes + Minuten + + + + hour + Stunde + + + + hours + Stunden + + + + day + Tag + + + + days + Tage + + + + month + Monat + + + + months + Monate + + + + years + + + + diff --git a/source-linux/application.qrc b/source-linux/application.qrc index ca84b0e..e7aba98 100644 --- a/source-linux/application.qrc +++ b/source-linux/application.qrc @@ -196,5 +196,17 @@ images/smileys/adult/finger.gif images/smileys/adult/sperm.gif images/smileys/adult/tits.gif + common/filesystem.cpp + common/filesystem.h + common/friendiqa.cpp + common/uploadableimage.cpp + common/uploadableimage.h + common/xhr.cpp + common/xhr.h + qml/calendarqml/CalendarTab.qml + qml/calendarqml/CalendarDay.qml + qml/calendarqml/EventList.qml + translations/friendiqa-de.qm + translations/friendiqa-de.ts diff --git a/source-linux/common/friendiqa.cpp b/source-linux/common/friendiqa.cpp index de055f0..06bcaf0 100644 --- a/source-linux/common/friendiqa.cpp +++ b/source-linux/common/friendiqa.cpp @@ -8,7 +8,9 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); QQuickView view; - + QTranslator qtTranslator; + qtTranslator.load("friendiqa-" + QLocale::system().name(),":/translations"); + app.installTranslator(&qtTranslator); XHR* xhr = XHR::instance(); view.rootContext()->setContextProperty("xhr", xhr); FILESYSTEM* filesystem = FILESYSTEM::instance(); diff --git a/source-linux/common/xhr.cpp b/source-linux/common/xhr.cpp index dd2e3df..d6fc091 100644 --- a/source-linux/common/xhr.cpp +++ b/source-linux/common/xhr.cpp @@ -3,7 +3,10 @@ #include #include #include - +#include +#include +#include +#include #include "uploadableimage.h" XHR *XHR::instance() @@ -114,7 +117,8 @@ void XHR::get() QByteArray loginData = m_login.toLocal8Bit().toBase64(); QString headerData = "Basic " + loginData; request.setRawHeader("Authorization", headerData.toLocal8Bit()); - + QNetworkCookieJar* cJar = new QNetworkCookieJar; + manager.setCookieJar(cJar); request.setUrl(requrl); reply = manager.get(request); @@ -206,6 +210,15 @@ void XHR::onReadyRead() { qDebug() << "."; buffer += reply->readAll(); + QList list = manager.cookieJar()->cookiesForUrl(m_url); + QFile f("/home/pankraz/cookie.txt"); + f.open(QIODevice::ReadWrite); + for(int i = 0; i < list.size(); ++i){ + QDataStream s(&f); + s << list.at(i).toRawForm(); + } + f.close(); + } //void XHR::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes) @@ -227,5 +240,3 @@ QString XHR::bufferToString() { return QTextCodec::codecForName("utf-8")->toUnicode(buffer); } - - diff --git a/source-linux/friendiqa.pro b/source-linux/friendiqa.pro index 31c1b2d..2d4eebe 100644 --- a/source-linux/friendiqa.pro +++ b/source-linux/friendiqa.pro @@ -34,6 +34,7 @@ OTHER_FILES += qml/friendiqa.qml \ # 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/friendiqa-de.ts HEADERS += \ @@ -41,4 +42,7 @@ HEADERS += \ common/xhr.h \ common/filesystem.h +DISTFILES += \ + qml/calendarqml/CalendarTab.qml + diff --git a/source-linux/js/helper.js b/source-linux/js/helper.js index 7935585..4deece4 100644 --- a/source-linux/js/helper.js +++ b/source-linux/js/helper.js @@ -9,12 +9,12 @@ function friendicaRequest(login,api,rootwindow,callback) { try{ if (xhrequest.status=200){ //if (xhrequest.responseText!=""){ callback(xhrequest.responseText) }else{ - showMessage("Error","API:" +api+"\n NO RESPONSE"+xhrequest.statusText,rootwindow); - callback(xhrequest.responseText) + showMessage("Error","API:" +login.server+api+"\n NO RESPONSE"+xhrequest.statusText,rootwindow); + //callback(xhrequest.responseText) } } - catch (e){ - showMessage("Error", api+" "+e+" "+xhrequest.statusText,rootwindow) + catch (e){print(e); + showMessage("Error", xhrequest.responseText,rootwindow) } } } @@ -60,7 +60,7 @@ function friendicaWebRequest(url,rootwindow,callback) { } else if(xhrequest.readyState === XMLHttpRequest.DONE) { try{ callback(xhrequest.responseText); } - catch (e){ + catch (e){print(e); showMessage("Error",url+" "+e, rootwindow) } } @@ -130,3 +130,8 @@ var arraystring=JSON.stringify(array); arraystring=arraystring.replace(/[\[\]]/g , ''); return arraystring; } + +function cleanDate(date){ +var cleanedDate= date.slice(0,3)+", "+date.slice(8,11)+date.slice(4,7)+date.slice(25,30)+date.slice(10,25); +return cleanedDate +} diff --git a/source-linux/js/news.js b/source-linux/js/news.js index 61082c3..98798ae 100644 --- a/source-linux/js/news.js +++ b/source-linux/js/news.js @@ -32,13 +32,12 @@ function requestGroups(login,database,rootwindow,callback){ function getFriendsTimeline(login,database,contacts,onlynew,rootwindow,callback){ // retrieve and return timeline since last news, return contacts which are not friends and older than 2 days for update (friends can be updated in Contactstab) var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]); - var parameter = ""; + var parameter = "?count=50"; if(onlynew){db.transaction( function(tx) { var result = tx.executeSql('SELECT status_id from news WHERE username="'+login.username+'" AND messagetype=0 ORDER BY status_id DESC LIMIT 1'); // check for last news id - try{parameter="&since_id="+result.rows.item(0).status_id;}catch(e){};})} + try{parameter=parameter+"&since_id="+result.rows.item(0).status_id;}catch(e){};})} var newContacts=[]; - //print("/api/statuses/friends_timeline"+parameter); - Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){ + Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){print(obj); var news=JSON.parse(obj); var newContacts=findNewContacts(news,contacts); callback(news,newContacts) @@ -53,7 +52,7 @@ function getCurrentContacts(login,database,callback){ contactlist.push(result.rows.item(i).url ) //print(result.rows.item(i).url) } - var lastDate=Date.now()-172800000;// 2 days old + var lastDate=Date.now()-604800000;// 7 days old //print('SELECT url from contacts WHERE username="'+login.username+'" AND isFriend=0 AND imageAge>'+lastDate); var result2 = tx.executeSql('SELECT url from contacts WHERE username="'+login.username+'" AND isFriend=0 AND imageAge > '+lastDate); for (var j=0;j0){ for (var j=0;j0){ for (var k=0;j0){ - if (newsitemobject.dislike.length==1){dislikeText= QT.atob(newsitemobject.dislike[0].name)+" "+ qsTr("doesn't like this.")} + if (newsitemobject.dislike.length==1){dislikeText= Qt.atob(newsitemobject.dislike[0].name)+" "+ qsTr("doesn't like this.")} else {dislikeText= newsitemobject.dislike.length+" "+ qsTr("don't like this.")} } if (newsitemobject.attendyes.length>0){ @@ -42,7 +42,15 @@ WorkerScript.onMessage = function(msg) { if (newsitemobject.friendica_activities_self.indexOf(2)!=-1){self.disliked=1} } var friendica_activities={likeText:likeText,dislikeText:dislikeText,attendyesText:attendyesText,attendnoText:attendnoText,attendmaybeText:attendmaybeText,self:self} - //print(JSON.stringify(friendica_activities) ) ; + + var attachmentList=[];if(newsitemobject.attachments){ + var attachArray=JSON.parse(Qt.atob(newsitemobject.attachments)); + for (var image in attachArray){if(attachArray[image].mimetype=="image/gif"){ + attachmentList.push(attachArray[image]) + } + } + } + newsitemobject.attachmentList=attachmentList; var seconds=(msg.currentTime-newsitemobject.created_at)/1000; var timestring=""; if (seconds<60) {timestring=seconds+" "+qsTr("seconds") +" "+qsTr("ago");} @@ -54,7 +62,7 @@ WorkerScript.onMessage = function(msg) { else if (seconds<3888000){timestring=Math.round(seconds/86400)+" "+qsTr("days") +" "+qsTr("ago");} else if (seconds<5832000){timestring=Math.round(seconds/3888000)+" "+qsTr("month") +" "+qsTr("ago");} else if (seconds<69984000){timestring=Math.round(seconds/3888000)+" "+qsTr("months") +" "+qsTr("ago");} - else {timestring=Math.round(seconds/69984000)+" "+qsTr("years") +" "+qsTr("ago");} + else {timestring=Math.round(seconds/46656000)+" "+qsTr("years") +" "+qsTr("ago");} var data=({"newsitemobject": newsitemobject,"dateDiff":timestring,"friendica_activities":friendica_activities})} //print("News:"+j+msg.news.length+JSON.stringify(data)); msg.model.append(data);} diff --git a/source-linux/js/service.js b/source-linux/js/service.js index e2f62d3..8ea1252 100644 --- a/source-linux/js/service.js +++ b/source-linux/js/service.js @@ -121,8 +121,93 @@ function initDatabase(database) { // initialize the database object tx.executeSql('CREATE TABLE IF NOT EXISTS news(username TEXT, messagetype INT, text TEXT, created_at INT, in_reply_to_status_id INT, source TEXT, status_id INT, in_reply_to_user_id INT, geo TEXT,favorited TEXT, uid INT, statusnet_html TEXT, statusnet_conversation_id TEXT,friendica_activities TEXT, friendica_activities_self TEXT, attachments TEXT, friendica_owner INT)'); tx.executeSql('CREATE TABLE IF NOT EXISTS contacts(username TEXT, id INT, name TEXT, screen_name TEXT, location TEXT,imageAge INT, profile_image_url TEXT, description TEXT, profile_image BLOB, url TEXT, protected TEXT, followers_count INT, friends_count INT, created_at INT, favourites_count TEXT, utc_offset TEXT, time_zone TEXT, statuses_count INT, following TEXT, verified TEXT, statusnet_blocking TEXT, notifications TEXT, statusnet_profile_url TEXT, cid INT, network TEXT, isFriend INT)'); tx.executeSql('CREATE TABLE IF NOT EXISTS groups(username TEXT, groupname TEXT, gid INT, members TEXT)'); +tx.executeSql('CREATE TABLE IF NOT EXISTS events(username TEXT, id INT, start INT, end INT, allday INT, title TEXT, j INT, d TEXT, isFirst INT, uid INT, cid INT, uri TEXT, created INT, edited INT, desc TEXT, location TEXT, type TEXT, nofinish TEXT, adjust INT, ignore INT, permissions TEXT, guid INT, itemid INT, plink TEXT, authorName TEXT, authorAvatar TEXT, authorLink TEXT, html TEXT)'); })} +function cleanPermissions(oldperms){ + var newperms=oldperms.replace("<","");newperms=newperms.replace(">","");newperms="["+newperms+"]"; + var newpermArray=JSON.parse(newperms); +return (newpermArray) +} + +function getEvents(database,login,rootwindow,callback){ +var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]); + Helperjs.friendicaWebRequest(login.server+"/cal/"+login.username+"/json",rootwindow,function(obj){ + var events = JSON.parse(obj); + db.transaction( function(tx) { + for (var i=0;imaxnews){var lastvalidtimers= tx.executeSql('select created_at from news ORDER BY created_at DESC LIMIT ' +(newscount-maxnews)); - var lastvalidtime=lastvalidtimers.rows.item(maxnews).created_at; + if (newscount>maxnews){ + var lastvalidtimers= tx.executeSql('SELECT DISTINCT created_at FROM news ORDER BY created_at ASC LIMIT ' +(newscount-maxnews)); + var lastvalidtime=lastvalidtimers.rows.item(newscount-maxnews-1).created_at; var deleters = tx.executeSql('DELETE from news WHERE created_at<='+lastvalidtime)} callback() }) @@ -260,13 +358,17 @@ function processNews(callback){ function updateContactInDB(login,database,isFriend,contact){// for newstab and friendstab // var suffix=contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("."), contact.profile_image_url.length); // var imagename=login.imagestore+"contacts/"+contact.screen_name.trim()+suffix; - var imagename=login.imagestore+"contacts/"+contact.screen_name+"-"+contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("/")+1, contact.profile_image_url.length); - contacttimer.restart(); + +var imagename=""; +contacttimer.restart(); var currentTime=Date.now(); + if(contact.profile_image_url==""){root.currentContact=root.currentContact+1 } else{//print(JSON.stringify(contact)) + imagename=login.imagestore+"contacts/"+contact.screen_name+"-"+contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("/")+1, contact.profile_image_url.length); + xhr.setUrl(Qt.resolvedUrl(contact.profile_image_url)); xhr.setFilename(imagename); xhr.setDownloadtype("contact"); - xhr.download(); + xhr.download();} var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]); var result; db.transaction( function(tx) { diff --git a/source-linux/qml/calendarqml/CalendarDay.qml b/source-linux/qml/calendarqml/CalendarDay.qml new file mode 100644 index 0000000..55ecffe --- /dev/null +++ b/source-linux/qml/calendarqml/CalendarDay.qml @@ -0,0 +1,47 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.4 + +Item { + id: calendarDay + width:7*mm + height: 7*mm + property int dateInt:Math.floor((Date.parse(model.date)-(new Date().getTimezoneOffset() * 60 * 1000))/86400000) + Rectangle { + id: placeHolder + color: 'lightblue'; antialiasing: true + anchors.fill:parent + } + Text { + id:daytext + anchors.right: parent.right + anchors.margins: 0.5*mm + color:(model.month==monthgrid.month)?"black":"grey" + wrapMode: Text.WrapAnywhere + text: model.day + font.bold: model.today + font.pixelSize: 4*mm + } + Rectangle { + id:eventRect + color:"black" + anchors.margins: 0.5*mm + anchors.bottom: calendarDay.bottom + width: parent.width-mm + height: mm + visible: eventdays.indexOf(dateInt)>-1 + } + MouseArea { + anchors.fill: calendarDay + onClicked: { + var eventDate=[]; + var idx = eventdays.indexOf(dateInt); + while (idx != -1) { + eventDate.push(idx); + idx = eventdays.indexOf(dateInt,idx + 1) + } + var component = Qt.createComponent("qrc:/qml/calendarqml/EventList.qml"); + if (component.status== Component.Ready){ + var eventlist = component.createObject(calendartab,{"daylist": eventDate})} + } + } +} diff --git a/source-linux/qml/calendarqml/CalendarTab.qml b/source-linux/qml/calendarqml/CalendarTab.qml new file mode 100644 index 0000000..7127a31 --- /dev/null +++ b/source-linux/qml/calendarqml/CalendarTab.qml @@ -0,0 +1,134 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.1 +import QtQml 2.2 +import Qt.labs.calendar 1.0 +import QtQuick.Layouts 1.3 +import "qrc:/js/service.js" as Service +import "qrc:/js/helper.js" as Helperjs +import "qrc:/qml/calendarqml" +import "qrc:/qml/genericqml" + +Rectangle { + id:calendarrectangle + y:1 + width:root.width-mm + height:root.height-5*mm + color: '#fff' + property date currentTime: new Date() + property int offsetTime: currentTime.getTimezoneOffset() * 60 * 1000 + property var events:[] + property var eventdays:[] + onEventdaysChanged: print(JSON.stringify(eventdays)) + + function showEvents(friend){ + if(friend=="backButton"){Service.eventsfromdb(db,login.username,function(eventArray,dayArray){ + events=eventArray; + eventdays=dayArray}) + } + else if (friend!=""){ + calendartab.calendartabstatus=friend.substring(friend.lastIndexOf("/")+1,friend.length) + Service.requestFriendsEvents(login,friend,calendartab,function(eventArray,dayArray){ + events=eventArray; + eventdays=dayArray}) + } + else {calendartab.calendartabstatus="Events"; + Service.eventsfromdb(db,login.username,function(eventArray,dayArray){ + events=eventArray; + eventdays=dayArray; + calBusy.running=false + }) + } + } + + BusyIndicator{ + id: calBusy + anchors.horizontalCenter: calendarView.horizontalCenter + anchors.top:calendarView.top + anchors.topMargin: 2*mm + width:10*mm + height: 10*mm + running: false + } + + + BlueButton{ + id: updateEvents + anchors.top: parent.top + anchors.topMargin: 0.5*mm + anchors.right:calendartabstatusButton.left + anchors.rightMargin:mm + text:"\uf021" + onClicked: { + + Service.getEvents(db,login, calendartab,function(){ + showEvents("") + })}} + + BlueButton{ + id: calendartabstatusButton + anchors.top: parent.top + anchors.topMargin: 0.5*mm + anchors.right: parent.right + anchors.rightMargin:2*mm + text: calendartab.calendartabstatus=="Events"?qsTr("Events"):calendartabstatus + onClicked: {calendartabmenu.popup()} + } + Menu { + id:calendartabmenu + MenuItem { + text: qsTr("Own Calendar") + onTriggered: { + calendartab.calendartabstatus="Events"; + // calendartabstatusButton.text=qsTr("own Calendar"); + showEvents("")} + } + } + + ListView{ + id: calendarView + x: mm;y:8*mm + width: parent.width-2*mm; height: parent.height-9*mm + clip: true + snapMode: ListView.SnapOneItem + orientation: ListView.Horizontal + highlightRangeMode: ListView.StrictlyEnforceRange + model: CalendarModel {id:calendarModel + from: new Date() + to: new Date(new Date().valueOf()+93312000000) + } + delegate: + ColumnLayout{ + width:calendarView.width + Text{ + font.bold: true + Layout.fillWidth: true + horizontalAlignment:Text.AlignHCenter + text: model.year + } + Text{ + text: Qt.locale().standaloneMonthName(model.month) + Layout.fillWidth: true + horizontalAlignment:Text.AlignHCenter + } + DayOfWeekRow{ + locale: monthgrid.locale + Layout.fillWidth: true + } + + MonthGrid { + id: monthgrid + Layout.fillWidth: true + month: model.month + year: model.year + locale: Qt.locale() + delegate: CalendarDay{} + } + } + ScrollIndicator.horizontal: ScrollIndicator { } + } + + Component.onCompleted: { + root.eventSignal.connect(showEvents); + if (calendartab.calendartabstatus=="Events"){showEvents("")} + } + } diff --git a/source-linux/qml/calendarqml/EventList.qml b/source-linux/qml/calendarqml/EventList.qml new file mode 100644 index 0000000..fbb1632 --- /dev/null +++ b/source-linux/qml/calendarqml/EventList.qml @@ -0,0 +1,85 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.2 +import "qrc:/js/service.js" as Service +import "qrc:/js/helper.js" as Helperjs +import "qrc:/qml/genericqml" + +Rectangle{ + id:eventList + z:2 + border.color: "grey" + width: parent.width-4*mm + height:parent.height-12*mm + x:mm + y:mm + property var daylist:[] + + BlueButton{ + id:closeButton + anchors.top: parent.top + anchors.topMargin: 1*mm + anchors.right: parent.right + anchors.rightMargin: 1*mm + text: "\uf057" + onClicked:{eventList.destroy()} + } + ListView { + id: eventlistView + x: mm + y:closeButton.height+2*mm + width: eventList.width-2*mm + height: eventList.height-closeButton.height-4*mm + clip: true + model: eventModel + delegate: eventItem + } + + ListModel{ + id: eventModel + } + + Component.onCompleted:{ + //print(JSON.stringify(daylist)) + for (var i=0; i"+qsTr("Connect")+"
") + +Rectangle { + id: wrapper + + width:friendsTabView.width; + height:friendsTabView.height-15*mm + border.color: "grey" + color:"white" + Image { + id: photoImage + x:mm + y:mm + width: 15*mm + height:15*mm + source:(contact.profile_image!="")? "file://"+contact.profile_image : contact.profile_image_url + onStatusChanged: if (photoImage.status == Image.Error) {source="qrc:/images/defaultcontact.jpg"} + } + + Label { + id: namelabel + x: mm + width:friendsTabView.width-4*mm + height: 3*mm + text:Qt.atob(contact.name)+" (@"+contact.screen_name+")" + elide:Text.ElideRight + anchors.topMargin: 0 + anchors.left: photoImage.left + color: "#303030" + font.pixelSize: 4*mm + anchors.top: photoImage.bottom + } Rectangle{ id: detailsrectangle anchors.top: namelabel.bottom @@ -69,10 +107,27 @@ Rectangle{ } } + + BlueButton{ + id:eventbutton + visible:(contact.network=="dfrn") + text:"\uf073" + onClicked:{ + root.currentIndex=3; + calendartab.active=true; + calendartab.calendartabstatus="Friend" + root.eventSignal(contact.url); + } + } + BlueButton{ id: closeButton text: "\uf057" //"close" - onClicked:{detailsrectangle.destroy();contactComponent.state="";friendsTabView.contactSignal} + onClicked:{contactLargeComponent.destroy(); + //contactComponent.state=""; + friendsTabView.contactSignal} } } } +} +} diff --git a/source-linux/qml/contactqml/FriendsTab.qml b/source-linux/qml/contactqml/FriendsTab.qml index 1686ddb..a82ce97 100644 --- a/source-linux/qml/contactqml/FriendsTab.qml +++ b/source-linux/qml/contactqml/FriendsTab.qml @@ -11,12 +11,13 @@ Rectangle { color: "white" function showContactdetails(contact){ + var component = Qt.createComponent("qrc:/qml/contactqml/ContactDetailsComponent.qml"); if(contact.isFriend){ friendsTabView.currentIndex=0; - friendsTabView.contactsSignal(contact) + var contactDetails = component.createObject(friendstab,{"contact": contact}) } else{friendsTabView.currentIndex=1; - friendsTabView.contactsSignal(contact) + var contactDetails = component.createObject(friendstab,{"contact": contact}) } } TabView{ @@ -30,7 +31,7 @@ Rectangle { signal contactsSignal(var contact) signal groupsSignal(var username) onCurrentIndexChanged:{ - if (currentIndex==0){//print("currentindex 0"); + if (currentIndex==0){ contactsSignal("") } else if (currentIndex==1){ @@ -60,18 +61,14 @@ Rectangle { title: qsTr("Friends") Rectangle{ id: friendsGridTab - function makebig(friendindex){print("friendindex"+friendindex);if (friendindex){friendsModel.set(friendindex,{"status":"large"})}} - function showFriends(contact,callback){//print("contact"+JSON.stringify(contact)); + function showFriends(contact){ try {friendsModel.clear()} catch(e){print(e)}; - var friendindex; Helperjs.readData(db,"contacts",root.login.username,function(friendsobject){ for (var i=0;i1){ + if(Helperjs.getCount(db,login,"contacts","screen_name",friendsobject[i].screen_name)>1){ friendsobject[i].screen_name=friendsobject[i].screen_name+"+"+friendsobject[i].cid } - if(contact){if (contact.cid==friendsobject[i].cid){status="large"}} - friendsModel.append({"contact":friendsobject[i],"status":status}); + friendsModel.append({"contact":friendsobject[i]}); } @@ -113,12 +110,11 @@ Rectangle { clip: true cellHeight: 16*mm cellWidth: 17*mm - add: Transition { - NumberAnimation { properties: "x,y"; from: 300; duration: 1000 } - } + //add: Transition { + // NumberAnimation { properties: "x,y"; from: 300; duration: 1000 } + // } model: friendsModel delegate: ContactComponent { } - Component.onCompleted: positionViewAtBeginning() } ListModel{id:friendsModel} @@ -132,7 +128,7 @@ Rectangle { } Tab{ - title: qsTr("Other Contacts") + title: qsTr("Contacts") Rectangle{ id: contactsGridTab @@ -140,9 +136,7 @@ Rectangle { try {contactsModel.clear()} catch(e){print(e)}; Helperjs.readData(db, "contacts",root.login.username,function(contactsobject){ for (var j=0;j0){// download first contact image and update db Service.updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])} else if (contactLoadType!=""){ @@ -49,6 +50,7 @@ TabView{ } onCurrentContactChanged:{// download next contact image after photoplaceholder is finished saving and update db + if(currentContact0){newstab.conversation=[]} else{Service.cleanNews(root.db,function(){Qt.quit()})} } else if (currentIndex==2){fotoSignal("backButton")} @@ -113,8 +117,8 @@ TabView{ tab: Rectangle { color: styleData.selected?"sky blue":"light blue" border.color: "light grey" - implicitWidth: root.width/4-2*mm - implicitHeight: 4*mm + implicitWidth: root.width/5-2*mm + implicitHeight: 5*mm Text { id: text anchors.centerIn: parent text: styleData.title @@ -145,9 +149,17 @@ TabView{ property string phototabstatus:"Images" source: (root.currentIndex==2)?"qrc:/qml/photoqml/PhotoTab.qml":"" } + Tab{ + title: "\uf073" + id: calendartab + property string calendartabstatus:"Events" + source: (root.currentIndex==3)?"qrc:/qml/calendarqml/CalendarTab.qml":"" + } + + Tab{ title:"\uf085" id: configtab - source: (root.currentIndex==3)?"qrc:/qml/configqml/ConfigTab.qml":"" + source: (root.currentIndex==4)?"qrc:/qml/configqml/ConfigTab.qml":"" } } diff --git a/source-linux/qml/newsqml/Conversation.qml b/source-linux/qml/newsqml/Conversation.qml index 6e3812e..4864f91 100644 --- a/source-linux/qml/newsqml/Conversation.qml +++ b/source-linux/qml/newsqml/Conversation.qml @@ -1,34 +1,106 @@ -// ConversationStack with buttons +// ConversationView with button import QtQuick 2.0 import "qrc:/js/helper.js" as Helperjs import "qrc:/qml/genericqml" Rectangle { - id:conversationStack + id:conversationList property var news y:1 - color: "white" - width:root.width-2*mm - height:root.height-8*mm + z:2 + color: "white" + border.color: "grey" + width:root.width-5*mm + height: conversationView.height+10*mm + Connections{ + target:newstab + onConversationChanged:{ + if(newstab.conversation.length==0){ + newsView.positionViewAtIndex(newsStack.conversationIndex,ListView.Beginning); + conversationList.destroy(); conversationsymbol.color="grey" + } + } + } ListView { id: conversationView x:3*mm y:8*mm - width: conversationStack.width-4*mm - height: conversationStack.height-10*mm + width: conversationList.width-4*mm + height: contentHeight clip: true spacing: 0 + footer: footerReply model: conversationModel delegate: Newsitem{} } - ListModel{id: conversationModel} + Component { id:footerReply + Rectangle{ + border.color: "#EEEEEE" + border.width: 1 + color:"lightgrey" + width:conversationView.width + height:Math.max(replyText.contentHeight+2*mm,6*mm) + Rectangle{ + color: "white" + radius:0.5*mm + anchors.left: parent.left + anchors.leftMargin:mm + anchors.top:parent.top + anchors.topMargin: 0.5*mm + width:parent.width-12*mm + height:Math.max( replyText.contentHeight,5*mm) - WorkerScript { - id: conversationWorker - source: "qrc:/js/newsworker.js" - } + TextInput { + id: replyText + font.pixelSize: 3*mm + wrapMode: Text.Wrap + anchors.fill: parent + selectByMouse: true + } + } + + BlueButton { + id: sendButton + text: "\uf1d9" + anchors.right: parent.right + anchors.rightMargin:mm + anchors.top:parent.top + anchors.topMargin: 0.5*mm + color:"white" + onClicked: { try{ + var body=replyText.getText(0,replyText.length); + newsBusy.running=true; + replyText.text="" + xhr.clearParams(); + xhr.setLogin(login.username+":"+Qt.atob(login.password)); + if (conversationModel.get(0).newsitemobject.messagetype==0){ + xhr.setParam("source", "Friendiqa"); + xhr.url= login.server + "/api/statuses/update.json"; + xhr.setParam("status", body); + xhr.setParam("in_reply_to_status_id", conversationModel.get(conversationModel.count-1).newsitemobject.status_id)} + else {xhr.url= login.server + "/api/direct_messages/new.json"; + xhr.setParam("text", body); + xhr.setParam("screen_name",conversationModel.get(conversationModel.count-1).newsitemobject.screen_name); + xhr.setParam("replyto", conversationModel.get(conversationModel.count-1).newsitemobject.status_id) + } + xhr.post(); + //replyText.text="" + } catch(e){Helperjs.showMessage("Error",e.toString(),root)} + } + } + } + } + + + + ListModel{id: conversationModel} + + WorkerScript { + id: conversationWorker + source: "qrc:/js/newsworker.js" + } BlueButton { id: closeButton @@ -37,10 +109,11 @@ Rectangle { anchors.topMargin: 1*mm anchors.right: parent.right anchors.rightMargin: 1*mm - text: "\uf057"// qsTr("Close") + text: "\uf057" onClicked: { - newstab.newstabstatus=login.newsViewType; - newsStack.pop() + newsView.positionViewAtIndex(newsStack.conversationIndex,ListView.Beginning); + conversationList.destroy(); + conversationsymbol.color="grey" } } diff --git a/source-linux/qml/newsqml/ImageDialog.qml b/source-linux/qml/newsqml/ImageDialog.qml index 4187fcf..34add5a 100644 --- a/source-linux/qml/newsqml/ImageDialog.qml +++ b/source-linux/qml/newsqml/ImageDialog.qml @@ -42,12 +42,11 @@ Rectangle{ clip: true model: imageModel delegate: imageItem - } FolderListModel{ id: imageModel - nameFilters: ["*.png", "*.jpg",".jpeg","*.JPG"] + nameFilters: ["*.png", "*.jpg",".jpeg","*.JPG","*.gif"] sortField: FolderListModel.Time sortReversed:false showDotAndDotDot: true @@ -111,8 +110,9 @@ Rectangle{ directory=fileURL } else{ - attachImageURL=fileURL; - imageDialog.destroy() + attachImageURLs.push(fileURL); + attachImage(fileURL); + imageDialog.destroy() } } } diff --git a/source-linux/qml/newsqml/MessageSend.qml b/source-linux/qml/newsqml/MessageSend.qml index 541c228..a093cc8 100644 --- a/source-linux/qml/newsqml/MessageSend.qml +++ b/source-linux/qml/newsqml/MessageSend.qml @@ -16,7 +16,7 @@ Flickable{ id:messageSend property string parentId: "" property string reply_to_user:"" - property string attachImageURL: ""; + property var attachImageURLs: []; property int directmessage: 0; property var contacts: [] property var groups: [] @@ -25,11 +25,13 @@ Flickable{ property var group_allow:login.permissions[2] property var group_deny:login.permissions[3] - onAttachImageURLChanged: {if(attachImageURL!=""){ - var imageAttachmentObject=Qt.createQmlObject('import QtQuick 2.0; Image {id:imageAttachment; source:"'+ - attachImageURL.toString()+'"; width: 15*mm; height: 15*mm;fillMode: Image.PreserveAspectFit;MouseArea{anchors.fill:parent;onClicked:{attachImageURL="";imageAttachment.destroy()}}}',messageColumn,"attachedImage"); - console.log("You chose: " + attachImageURL) - }} + function attachImage(url){ + //onAttachImageURLsChanged: {if(attachImageURL!=""){ + var imageAttachmentObject=Qt.createQmlObject('import QtQuick 2.0; Image {id:imageAttachment'+attachImageURLs.length+'; source:"'+ + url.toString()+'"; width: 15*mm; height: 15*mm;fillMode: Image.PreserveAspectFit;MouseArea{anchors.fill:parent;onClicked:{attachImageURLs.splice(attachImageURLs.indexOf("'+url+'",1)); imageAttachment'+attachImageURLs.length+'.destroy()}}}',messageColumn,"attachedImage"); + console.log("You chose: " + url) + } + function statusUpdate(title,status,in_reply_to_status_id,attachImageURL) { xhr.url= login.server + "/api/statuses/update.json"; xhr.setLogin(login.username+":"+Qt.atob(login.password)); @@ -42,7 +44,7 @@ Flickable{ if (group_deny.length>0) {xhr.setParam("group_deny", Helperjs.cleanArray(group_deny))}; if (contact_allow.length>0) {xhr.setParam("contact_allow", Helperjs.cleanArray(contact_allow))}; if (contact_deny.length>0) {xhr.setParam("contact_deny", Helperjs.cleanArray(contact_deny))}; - if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )}; + if (attachImageURL.length>0) {for (var image in attachImageURL){xhr.setImageFileParam("media", attachImageURL[image] )}}; xhr.post(); } @@ -122,12 +124,11 @@ Flickable{ } } - Row{ spacing:2 BlueButton{id:permButton visible: (directmessage==1)?false:true - text: ((contact_allow.length==0)&&(contact_deny.length==0)&&(group_allow.length==0)&&(group_deny.length==0))?"\uf09c":"\uf023"//qsTr("Permissions") + text: ((contact_allow.length==0)&&(contact_deny.length==0)&&(group_allow.length==0)&&(group_deny.length==0))?"\uf09c":"\uf023" onClicked: { var component = Qt.createComponent("qrc:/qml/newsqml/PermissionDialog.qml"); var permissions = component.createObject(messageColumn); @@ -137,14 +138,14 @@ Flickable{ text: "\uf0c6" visible:(directmessage==0) onClicked: { - if (attachImageURL!=""){ - Helperjs.showMessage( qsTr("Error"),qsTr("Only one attachment. Remove other attachment first!"), messageColumn)} - else{print(filesystem.homePath); - var defaultDirectory="file://"+osSettings.attachImageDir;//"file:///storage/emif.open() - print(defaultDirectory); - var component = Qt.createComponent("qrc:/qml/newsqml/ImageDialog.qml"); - var imagedialog = component.createObject(messageSend,{"directory": defaultDirectory}); - } + if (attachImageURLs.length>0){//Server currently accepts only one attachment + Helperjs.showMessage( qsTr("Error"),qsTr("Only one attachment supported at the moment.\n Remove other attachment first!"), messageColumn) + } + else{ + var defaultDirectory="file://"+osSettings.attachImageDir; + var component = Qt.createComponent("qrc:/qml/newsqml/ImageDialog.qml"); + var imagedialog = component.createObject(messageSend,{"directory": defaultDirectory}); + } } } BlueButton{ @@ -188,7 +189,7 @@ Flickable{ var title=titleField.text.replace("\"","\'"); var body=bodyField.getText(0,bodyField.length); if (directmessage==0){ - statusUpdate(title,body,messageSend.parentId,attachImageURL.toString())} + statusUpdate(title,body,messageSend.parentId,attachImageURLs)} else {dmUpdate(title,body,"",messageSend.reply_to_user) } newstab.newstabstatus=login.newsViewType; newsStack.pop() } diff --git a/source-linux/qml/newsqml/NewsTab.qml b/source-linux/qml/newsqml/NewsTab.qml index 9e1d57a..14dd731 100644 --- a/source-linux/qml/newsqml/NewsTab.qml +++ b/source-linux/qml/newsqml/NewsTab.qml @@ -13,23 +13,13 @@ Item { } } - Connections{ - target:newstab - onConversationChanged:{ - newsBusy.running=false; - newstab.newstabstatus="Conversation"; - //newsStack.push({item:"qrc:/qml/newsqml/Conversation.qml",properties:{"news": conversation}}) - showNews(conversation); - } - } - Connections{ target:root onCurrentContactChanged:{ if (root.newContacts.length>0){ if(root.currentContact(-15*mm-1)){print("refreshing"); + onDragEnded:{if(contentY<-8*mm){//print("refreshing"); + newsBusy.running=true; + newstab.newstabstatus=login.newsViewType; + root.contactLoadType="news"; + var onlynew=true; + Newsjs.getFriendsTimeline(login,db,contactlist,onlynew,newstab,function(ns,nc){ + root.news=ns;root.newContacts=nc;root.currentContact=0; + if (ns.length==0){// update last 20 existing news for changes and likes + onlynew=false; + Newsjs.getFriendsTimeline(login,db,contactlist,onlynew,newstab,function(rns,rnc){ + root.contactLoadType="news"; + root.news=rns;root.newContacts=rnc;root.currentContact=0}) + } + }) + }} + } ListModel{id: newsModel} @@ -331,10 +267,10 @@ Item { } MenuItem { - text: qsTr("Tree") + text: qsTr("Conversations") onTriggered:{ newsModel.clear(); - newstab.newstabstatus="Tree"; + newstab.newstabstatus="Conversations"; Newsjs.chatsfromdb(db,root.login.username,function(news){showNews(news)}) } } diff --git a/source-linux/qml/newsqml/Newsitem.qml b/source-linux/qml/newsqml/Newsitem.qml index 19a2185..d9c9fa7 100644 --- a/source-linux/qml/newsqml/Newsitem.qml +++ b/source-linux/qml/newsqml/Newsitem.qml @@ -7,9 +7,23 @@ import "qrc:/js/helper.js" as Helperjs Item { id: newsitem - width: newsView.width - height:Math.max((itemMessage.height+topFlow.height+friendicaActivities.height+4*mm),profileImage.height+user_name.height+mm) - + width: parent.width + height:toprow.height+friendicaActivities.height+controlrow.height+1//Math.max((itemMessage.height+topFlow.height+friendicaActivities.height+4*mm),profileImage.height+user_name.height+mm) + + Connections{ + target:newstab + onConversationChanged:{ + newsBusy.running=false; + if(index==newsStack.conversationIndex){ + if(newstab.conversation.length>0){ + var component = Qt.createComponent("qrc:/qml/newsqml/Conversation.qml"); + var conversation = component.createObject(friendicaActivities,{"news":newstab.conversation}); + } + else{conversationsymbol.color="grey"} + } + } + } + property string attending: "" onAttendingChanged: {attendLabel.visible=true; attendLabel.text= qsTr("attending: ")+ qsTr(attending)} @@ -19,9 +33,7 @@ Item { function showActivityContacts(contacts){ var component = Qt.createComponent("qrc:/qml/newsqml/FriendicaActivities.qml"); var imagedialog = component.createObject(friendicaActivities,{"activitymembers": contacts}); - } - Rectangle{width:newsitem.width; height: 1; anchors.bottom: newsitem.bottom; color:"light grey"} Rectangle{ @@ -29,7 +41,8 @@ Item { height:newsitem.height-1 color: (newsitemobject.messagetype==1)?"#ffe6e6" : "white" - Column { + Row{id:toprow + Column { id: authorcolumn width: 8*mm @@ -41,7 +54,7 @@ Item { height: 7*mm MouseArea{ anchors.fill: parent - onClicked:{print(root.currentIndex); + onClicked:{ try{root.currentIndex=1; friendstab.active=true; root.contactdetailsSignal(newsitemobject.user)} catch (e){Helperjs.showMessage("Error",e,root)} @@ -61,7 +74,7 @@ Item { Column { id:newscolumn width: newsitem.width-8*mm - anchors.left: authorcolumn.right + //anchors.left: authorcolumn.right Flow{ id:topFlow @@ -92,7 +105,7 @@ Item { Label { id:newscountLabel - visible:((newstabstatus=="Tree")&&(newsitemobject.newscount>1))?true:false + visible:((newstabstatus=="Conversations")&&(newsitemobject.newscount>1))?true:false color: "grey" height:3.5*mm font.pixelSize: 1.5*mm @@ -117,12 +130,25 @@ Item { wrapMode: Text.Wrap onLinkActivated:{ Qt.openUrlExternally(link)} + Component.onCompleted:{ + if (newsitemobject.attachmentList.length>0){ + for(var attachments in newsitemobject.attachmentList){// (newsitemobject.attachmentList[attachments].url); + var attachcomponent = Qt.createQmlObject('import QtQuick 2.0; '+ + 'AnimatedImage {id:gif;source: "'+newsitemobject.attachmentList[attachments].url+ + '";onStatusChanged: playing = (status == AnimatedImage.Ready)}', + friendicaActivities,"Attachment"+attachments); + } + } + } } - - Flow{ + } + } + Flow{ id:friendicaActivities + anchors.top:toprow.bottom width:parent.width spacing:mm + Label{color: "grey" font.pixelSize: 1.5*mm text: friendica_activities.likeText @@ -162,11 +188,22 @@ Item { onClicked: { showActivityContacts(newsitemobject.attendmaybe)} } } + Label{ + id:attendLabel + //visible: false + color: "grey" + height:3.5*mm + font.pixelSize: 1.5*mm + horizontalAlignment: Label.AlignRight + text: (friendica_activities.self.attending)?(qsTr("Attending: ")+ qsTr(friendica_activities.self.attending)):"" + } } - Row{ + Row{id:controlrow + anchors.top:friendicaActivities.bottom + CheckBox{ id:likeCheckbox - height:3*mm + //height:3*mm width:8*mm visible: (newsitemobject.messagetype==0)? true:false checked:(friendica_activities.self.liked==1)?true:false @@ -195,7 +232,7 @@ Item { } CheckBox{ id: dislikeCheckbox - height:3*mm + //height:3*mm width:8*mm visible: (newsitemobject.messagetype==0)? true:false checked: (friendica_activities.self.disliked==1)?true:false @@ -222,10 +259,30 @@ Item { if (dislikeCheckbox.checked==true){Newsjs.like(root.login,root.db,1,"dislike",newsitemobject.status_id,root);likeCheckbox.checked=false; model.friendica_activities.self.disliked=0} else {Newsjs.like(root.login,root.db,0,"dislike",newsitemobject.status_id,root); model.friendica_activities.self.disliked=1}} } + +// Rectangle{ +// width: 8*mm +// height: 3*mm +// color:"transparent" +// Text{ +// id:trashsymbol +// color: "grey" +// anchors.centerIn: parent +// font.pixelSize: 2*mm +// font.bold: true +// text: "\uf1f8" +// } +// MouseArea{ +// anchors.fill:parent +// onClicked: { +// Newsjs.deleteNews(root.login,root.db,newsitemobject.status_id,newsitemobject.messagetype,root,function(reply){ +// newsModel.remove(index)}) +// }} +// } CheckBox { id:favoritedCheckbox visible:(newsitemobject.messagetype==0) - width: 7*mm + width: 8*mm style: CheckBoxStyle { background: Rectangle { implicitWidth: 6*mm @@ -251,7 +308,7 @@ Item { } } Rectangle{ - width: 7*mm + width: 8*mm height: 3*mm color:"transparent" Text{ @@ -267,7 +324,7 @@ Item { onClicked: {newsmenu.popup()}} } Rectangle{ - width: 7*mm + width: 8*mm height: 3*mm visible:newstab.newstabstatus!="Conversation" color:"transparent" @@ -281,20 +338,15 @@ Item { } MouseArea{ anchors.fill:parent - onClicked: { conversationsymbol.color="black";showConversation(index,newsitemobject)} + onClicked:{ + conversationsymbol.color="black"; + showConversation(index,newsitemobject) + } } } - Label{ - id:attendLabel - //visible: false - color: "grey" - height:3.5*mm - font.pixelSize: 1.5*mm - horizontalAlignment: Label.AlignRight - text: (friendica_activities.self.attending)?(qsTr("Attending: ")+ qsTr(friendica_activities.self.attending)):"" - } + } -} + Menu { id:newsmenu MenuItem { @@ -350,6 +402,4 @@ Item { } } } -} -} - +}} diff --git a/source-linux/qml/newsqml/PermissionDialog.qml b/source-linux/qml/newsqml/PermissionDialog.qml index 8796326..4040c76 100644 --- a/source-linux/qml/newsqml/PermissionDialog.qml +++ b/source-linux/qml/newsqml/PermissionDialog.qml @@ -32,7 +32,7 @@ Rectangle{ Text{ x:0.5*mm y:0.5*mm - text: "Contacts" + text: qsTr("Friends") } ListView { id: contactView @@ -93,7 +93,7 @@ Rectangle{ Text{ x:contactView.width+2*mm y:0.5*mm - text: "Groups" + text: qsTr("Groups") } ListView { id: groupView diff --git a/source-linux/qml/photoqml/PhotoTab.qml b/source-linux/qml/photoqml/PhotoTab.qml index 10445e8..09ed13b 100644 --- a/source-linux/qml/photoqml/PhotoTab.qml +++ b/source-linux/qml/photoqml/PhotoTab.qml @@ -105,7 +105,7 @@ Rectangle { anchors.topMargin: 0.5*mm anchors.right: parent.right anchors.rightMargin:2*mm - text: qsTr(phototabstatus) + text: fotostab.phototabstatus=="Images"?qsTr("Own Images"):fotostab.phototabstatus onClicked: {phototabmenu.popup()} } Menu { @@ -114,7 +114,7 @@ Rectangle { text: qsTr("Own Images") onTriggered: { fotostab.phototabstatus="Images"; - phototabstatusButton.text=qsTr("own images"); + // phototabstatusButton.text=qsTr("Own images"); showFotos("")} } } diff --git a/source-linux/translations/friendiqa-de.qm b/source-linux/translations/friendiqa-de.qm new file mode 100644 index 0000000..3a0c325 Binary files /dev/null and b/source-linux/translations/friendiqa-de.qm differ diff --git a/source-linux/translations/friendiqa-de.ts b/source-linux/translations/friendiqa-de.ts new file mode 100644 index 0000000..49396a7 --- /dev/null +++ b/source-linux/translations/friendiqa-de.ts @@ -0,0 +1,470 @@ + + + + + CalendarTab + + + Events + Termine + + + + Own Calendar + Eigener Kalender + + + + ConfigTab + + + + + + User + Name + + + + Server + Server + + + + Password + Passwort + + + + Image dir. + Bildverz. + + + + Max. News + Max. Nachr. + + + + News as + Anzeige + + + + Interval (0=None) + Intervall (0=keins) + + + + Confirm + Bestätigen + + + + No server given! + Kein Server angegeben! + + + + No username given! + Kein Nutzername angegeben! + + + + No password given! + Kein Passwort angegeben! + + + + No image directory given! + Kein Verzeichnis für Bilder angegeben! + + + + No maximum news number given! + Maximale News-Anzahl nicht angegeben! + + + + Timeline + Chronologisch + + + + Conversations + Unterhaltungen + + + + ContactComponent + + + Connect + Kontaktanfrage + + + + ContactDetailsComponent + + + Connect + Kontaktanfrage + + + + Description + Beschreibung + + + + Location + Ort + + + + Posts + Beiträge + + + + URL + Profilseite + + + + Created at + Erstellt + + + + FriendsTab + + + Friends + Freunde + + + + Contacts + Kontakte + + + + Groups + Gruppen + + + + MessageSend + + + Title (optional) + Überschrift (optional) + + + + Error + Fehler + + + + Only one attachment supported at the moment. + Remove other attachment first! + Nur ein Anhang derzeit unterstützt. + Lösche zuerst den anderen Anhang! + + + + NewsTab + + + Download profile image for + Lade Profilbild für + + + + More + Mehr + + + + Timeline + Chronologisch + + + + Favorites + Markierte News + + + + Conversations + Unterhaltungen + + + + Notifications + Meldungen + + + + Newsitem + + + attending: + Teilnahme + + + + Source: + Quelle: + + + + Direct Message + Direktnachricht + + + + In reply to + Antwort an + + + + comments + Kommentare + + + + Attending: + Teilnahme: + + + + Reply + Antworten + + + + DM + Direktnachricht + + + + Repost + Teilen + + + + Conversation + Unterhaltung + + + + Attending + Teilnahme + + + + yes + ja + + + + maybe + vielleicht + + + + no + nein + + + + Delete + Löschen + + + + PermissionDialog + + + Friends + Freunde + + + + Groups + Gruppen + + + + PhotoTab + + + 's images + s Bilder + + + + + Own Images + Eigene Bilder + + + + More + Mehr + + + + SmileyDialog + + + Standard + Standard + + + + Addon + Addon + + + + Adult + XXX + + + + newsworker + + + likes this. + mag das. + + + + like this. + mögen das. + + + + doesn't like this. + mag das nicht. + + + + don't like this. + mögen das nicht. + + + + will attend. + nehmen teil. + + + + persons will attend. + Personen nehmen teil. + + + + will not attend. + nimmt nicht teil. + + + + persons will not attend. + Personen nehmen nicht teil. + + + + may attend. + nimmt vielleicht teil. + + + + persons may attend. + Personen nehmen vielleicht teil. + + + + yes + ja + + + + no + nein + + + + maybe + vielleicht + + + + seconds + Sekunden + + + + + + + + + + + + + ago + her + + + + minute + Minute + + + + minutes + Minuten + + + + hour + Stunde + + + + hours + Stunden + + + + day + Tag + + + + days + Tage + + + + month + Monat + + + + months + Monate + + + + years + + + +