Browse Source

Version 0.004

tags/v0.004
LubuWest 2 years ago
parent
commit
438f8a4e4d
64 changed files with 2736 additions and 636 deletions
  1. 30
    0
      CHANGELOG.md
  2. BIN
      Friendiqa.apk
  3. 42
    38
      README.md
  4. BIN
      Screenshots/ConfigTab.jpg
  5. BIN
      Screenshots/EventsTab.jpg
  6. BIN
      Screenshots/FriendsTab.jpg
  7. BIN
      Screenshots/NewsTab.jpg
  8. BIN
      Screenshots/PhotoTab.jpg
  9. 2
    2
      source-android/android/AndroidManifest.xml
  10. BIN
      source-android/android/res/drawable-hdpi/friendiqa.png
  11. BIN
      source-android/android/res/drawable-ldpi/friendiqa.png
  12. BIN
      source-android/android/res/drawable-mdpi/friendiqa.png
  13. BIN
      source-android/android/res/drawable-xhdpi/friendiqa.png
  14. BIN
      source-android/android/res/drawable-xxhdpi/friendiqa.png
  15. BIN
      source-android/android/res/drawable-xxxhdpi/friendiqa.png
  16. 12
    0
      source-android/application.qrc
  17. 3
    1
      source-android/common/friendiqa.cpp
  18. 10
    5
      source-android/js/helper.js
  19. 11
    12
      source-android/js/news.js
  20. 11
    3
      source-android/js/newsworker.js
  21. 107
    5
      source-android/js/service.js
  22. 47
    0
      source-android/qml/calendarqml/CalendarDay.qml
  23. 134
    0
      source-android/qml/calendarqml/CalendarTab.qml
  24. 85
    0
      source-android/qml/calendarqml/EventList.qml
  25. 47
    24
      source-android/qml/configqml/ConfigTab.qml
  26. 1
    28
      source-android/qml/contactqml/ContactComponent.qml
  27. 56
    1
      source-android/qml/contactqml/ContactDetailsComponent.qml
  28. 91
    0
      source-android/qml/contactqml/ContactDetailsComponentOld.qml
  29. 15
    22
      source-android/qml/contactqml/FriendsTab.qml
  30. 18
    6
      source-android/qml/friendiqa.qml
  31. 88
    15
      source-android/qml/newsqml/Conversation.qml
  32. 4
    4
      source-android/qml/newsqml/ImageDialog.qml
  33. 19
    18
      source-android/qml/newsqml/MessageSend.qml
  34. 53
    117
      source-android/qml/newsqml/NewsTab.qml
  35. 81
    31
      source-android/qml/newsqml/Newsitem.qml
  36. 2
    2
      source-android/qml/newsqml/PermissionDialog.qml
  37. 2
    2
      source-android/qml/photoqml/PhotoTab.qml
  38. BIN
      source-android/translations/friendiqa-de.qm
  39. 470
    0
      source-android/translations/friendiqa-de.ts
  40. 12
    0
      source-linux/application.qrc
  41. 3
    1
      source-linux/common/friendiqa.cpp
  42. 15
    4
      source-linux/common/xhr.cpp
  43. 4
    0
      source-linux/friendiqa.pro
  44. 10
    5
      source-linux/js/helper.js
  45. 11
    12
      source-linux/js/news.js
  46. 11
    3
      source-linux/js/newsworker.js
  47. 107
    5
      source-linux/js/service.js
  48. 47
    0
      source-linux/qml/calendarqml/CalendarDay.qml
  49. 134
    0
      source-linux/qml/calendarqml/CalendarTab.qml
  50. 85
    0
      source-linux/qml/calendarqml/EventList.qml
  51. 47
    24
      source-linux/qml/configqml/ConfigTab.qml
  52. 1
    28
      source-linux/qml/contactqml/ContactComponent.qml
  53. 56
    1
      source-linux/qml/contactqml/ContactDetailsComponent.qml
  54. 15
    22
      source-linux/qml/contactqml/FriendsTab.qml
  55. 18
    6
      source-linux/qml/friendiqa.qml
  56. 88
    15
      source-linux/qml/newsqml/Conversation.qml
  57. 4
    4
      source-linux/qml/newsqml/ImageDialog.qml
  58. 19
    18
      source-linux/qml/newsqml/MessageSend.qml
  59. 53
    117
      source-linux/qml/newsqml/NewsTab.qml
  60. 81
    31
      source-linux/qml/newsqml/Newsitem.qml
  61. 2
    2
      source-linux/qml/newsqml/PermissionDialog.qml
  62. 2
    2
      source-linux/qml/photoqml/PhotoTab.qml
  63. BIN
      source-linux/translations/friendiqa-de.qm
  64. 470
    0
      source-linux/translations/friendiqa-de.ts

+ 30
- 0
CHANGELOG.md View File

@@ -0,0 +1,30 @@
1
+## v0.004#
2
+
3
+
4
+# News #
5
+
6
+*  Conversation opens as child of news item
7
+*  Pull-to-refresh news
8
+*  Delete Icon
9
+*  Animated Gif attachments shown below news item
10
+*  Improved image selector for new message
11
+*  Gif attachments for new message
12
+*  Timeline reloaded after new message
13
+
14
+# Contacts #
15
+*  Contact details window mechanism completely reworked
16
+*  New calendar icon for Friendica contacts
17
+*  "Connect" opens connect request page for Friendica contacs
18
+
19
+# Calendar #
20
+*  new calendar tab
21
+*  shows own public events and public events of Friendica contacts
22
+*  list view of events of selected date
23
+*  click on event to show details
24
+
25
+# Config #
26
+*  the icon of the server is shown if url is correct
27
+*  Click on icon for server details
28
+
29
+# Translations #
30
+*  German

BIN
android-build-release-signed.apk → Friendiqa.apk View File


+ 42
- 38
README.md View File

@@ -1,16 +1,16 @@
1 1
 ## Friendiqa#
2 2
 
3 3
 QML based client for the Friendica Social Network.
4
- Tabs for news (incl. Direct Messages), friends and photos.
5
- Delete old version first when upgrading (due to database changes)
6
-OS: currently Linux and Android(4.3).
7
-Source code is a QtCreator project.
8
-
4
+ Tabs for news (incl. Direct Messages), friends, photos and events.
5
+ OS: currently Linux and Android(4.3).
6
+ Source code is a QtCreator project.
7
+
9 8
 ## Screenshots ##
10 9
 
11 10
 ![Newstab](Screenshots/NewsTab.jpg)
12 11
 ![Friendstab](Screenshots/FriendsTab.jpg)
13 12
 ![Photostab](Screenshots/PhotoTab.jpg)
13
+![Eventstab](Screenshots/EventTab.jpg)
14 14
 ![Configtab](Screenshots/ConfigTab.jpg)
15 15
 
16 16
 
@@ -18,34 +18,36 @@ Source code is a QtCreator project.
18 18
 
19 19
 # News #
20 20
 Currently supported:
21
-*  Shows Posts from friends, favorited messages, Direct Messages and Notifications
22
-*  Show news as timeline or tree (conversation opens in same window)
23
-*  Open links in external browser
24
-*  Click on contact phot for additional information
25
-*  Deletion, Reposting, Answering of Posts
26
-*  Liking, disliking, favoriting
21
+*  Shows Posts from friends, favorited messages, Direct Messages and Notifications
22
+*  Open links in external browser
23
+*  
Click on contact photo for contact details
27 24
 *  Click on like text for additional contact info
28
-*  Attending events
29
-*  Update fetches new posts since last in local DB
25
+*  Deletion, Reposting, Answering of Posts
26
+*  Liking, disliking, favoriting
27
+*  Attending for event posts
28
+*  Update fetches new posts (up to last 50) since last in local DB
30 29
 *  More shows older posts from local DB
31
-*  Create new Message with images or direct messages, Contact/Group access rights(can be stored), smileys
30
+*  Create new Message with images or direct messages, Contact/Group access rights(can be stored), smileys
32 31
 *  New image dialog
33 32
 
34 33
 ToDo:
35
-*  Videos and other binary data as attachment (sending and receiving)
36
-*  Rich text editing in Send Dialog
34
+
35
+*  Videos and other binary data as attachment (sending and receiving)
36
+*  More than one attachment
37
+*  Rich text editing in Send Dialog
37 38
 *  Attachments for Direct messages (currently not supported in API)
38
-
39
+
39 40
     
40 41
 # Friends #
41 42
 Currently supported:
43
+
42 44
 *  Tabs for friends, other contacts and groups
43
-*  Grid of all known contacts with locally downloaded pictures
44
-*  Large friend item for addional information and functionality
45
-*  Show news of contact from local database
46
-*  Send direct message, if contact is following  
47
-*  Show public pictures of contact (screenscraping of contact's website, works only with certain theme)
48
-*  Open website of contact or connect page (for other contacts) 
45
+*  Grid of all known contacts with locally downloaded pictures
46
+*  Large friend item for addional information and functionality
47
+*  Show news of contact from local database
48
+*  Send direct message, if contact is following
49
+*  Show public pictures of contact (screenscraping of contact's website, works only with certain theme)
50
+*  Open website of contact or connect page (for other contacts)
49 51
      
50 52
 ToDo:
51 53
 *  More information for contact from description page, possibly private information for friends
@@ -58,12 +60,21 @@ Currently supported:
58 60
 *  Show albums in grid, show images in album in grid and fullscreen
59 61
 *  Show albums and images of contacts
60 62
 *  Pinch to zoom, swipe to scroll
61
-
63
+
62 64
 ToDo:
63 65
 *  Private images of friends
64 66
 *  Support for all themes of friends
65 67
 *  Delete downloaded own images
66 68
 
69
+
70
+# Events #
71
+*  download own public events and public events of Friendica contacts
72
+*  list view of events of selected date
73
+*  click on event to show details
74
+
75
+ToDo
76
+* private events
77
+
67 78
      
68 79
 # Config #
69 80
 Currently supported:
@@ -73,27 +84,20 @@ Currently supported:
73 84
 
74 85
 ToDo
75 86
 *  OAuth?
76
-
87
+
77 88
      
78 89
 # Other #
79 90
 ToDo
80
-*  Calendar tab, video tab
91
+*  Video tab
81 92
 *  Photo upload to album (needs API change)
82 93
 *  Translation
83 94
 *  Blingbling
95
+
84 96
 
97
+# Translations #
98
+*  German
99
+
85 100
      
86
-# New in version 0.003
87
-*  improved BackButton behaviour
88
-*  click on contact everywhere to get to contact details
89
-*  Image dialog automatically opens in Android camera directory
90
-*  Smiley Dialog in Message Dialog
91
-*  Extensive use of FontAwesome for icons
92
-*  Bugfixes
93
-     
94
-     
95 101
 ## License ##
96
-*  v0.001 for Friendica < 3.5
97
-*  v0.002 for Friendica >= 3.5
98
-*  Published under the [GPL v3](http://gplv3.fsf.org).
102
+Pubished under the [GPL v3](http://gplv3.fsf.org).
99 103
 

BIN
Screenshots/ConfigTab.jpg View File


BIN
Screenshots/EventsTab.jpg View File


BIN
Screenshots/FriendsTab.jpg View File


BIN
Screenshots/NewsTab.jpg View File


BIN
Screenshots/PhotoTab.jpg View File


+ 2
- 2
source-android/android/AndroidManifest.xml View File

@@ -1,6 +1,6 @@
1 1
 <?xml version="1.0"?>
2
-<manifest package="org.qtproject.friendiqa" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.3" android:versionCode="3" android:installLocation="auto">
3
-    <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Friendiqa" android:icon="@drawable/icon" android:logo="@drawable/icon">
2
+<manifest package="org.qtproject.friendiqa" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.4" android:versionCode="4" android:installLocation="auto">
3
+    <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Friendiqa" android:icon="@drawable/friendiqa" android:logo="@drawable/friendiqa">
4 4
         <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="Friendiqa" android:screenOrientation="unspecified" android:launchMode="singleTop">
5 5
             <intent-filter>
6 6
                 <action android:name="android.intent.action.MAIN"/>

BIN
source-android/android/res/drawable-hdpi/friendiqa.png View File


BIN
source-android/android/res/drawable-ldpi/friendiqa.png View File


BIN
source-android/android/res/drawable-mdpi/friendiqa.png View File


BIN
source-android/android/res/drawable-xhdpi/friendiqa.png View File


BIN
source-android/android/res/drawable-xxhdpi/friendiqa.png View File


BIN
source-android/android/res/drawable-xxxhdpi/friendiqa.png View File


+ 12
- 0
source-android/application.qrc View File

@@ -196,5 +196,17 @@
196 196
         <file>images/smileys/adult/finger.gif</file>
197 197
         <file>images/smileys/adult/sperm.gif</file>
198 198
         <file>images/smileys/adult/tits.gif</file>
199
+        <file>common/filesystem.cpp</file>
200
+        <file>common/filesystem.h</file>
201
+        <file>common/friendiqa.cpp</file>
202
+        <file>common/uploadableimage.cpp</file>
203
+        <file>common/uploadableimage.h</file>
204
+        <file>common/xhr.cpp</file>
205
+        <file>common/xhr.h</file>
206
+        <file>qml/calendarqml/CalendarTab.qml</file>
207
+        <file>qml/calendarqml/CalendarDay.qml</file>
208
+        <file>qml/calendarqml/EventList.qml</file>
209
+        <file>translations/friendiqa-de.qm</file>
210
+        <file>translations/friendiqa-de.ts</file>
199 211
     </qresource>
200 212
 </RCC>

+ 3
- 1
source-android/common/friendiqa.cpp View File

@@ -7,7 +7,9 @@
7 7
 int main(int argc, char *argv[]) {
8 8
     QApplication app(argc, argv);
9 9
     QQuickView view;
10
-
10
+    QTranslator qtTranslator;
11
+    qtTranslator.load("friendiqa-" + QLocale::system().name(),":/translations");
12
+    app.installTranslator(&qtTranslator);
11 13
 
12 14
     XHR* xhr = XHR::instance();
13 15
     view.rootContext()->setContextProperty("xhr", xhr);

+ 10
- 5
source-android/js/helper.js View File

@@ -9,12 +9,12 @@ function friendicaRequest(login,api,rootwindow,callback) {
9 9
                 try{ if (xhrequest.status=200){ //if (xhrequest.responseText!=""){
10 10
                         callback(xhrequest.responseText)
11 11
                        }else{
12
-                        showMessage("Error","API:" +api+"\n NO RESPONSE"+xhrequest.statusText,rootwindow);
13
-                        callback(xhrequest.responseText)
12
+                        showMessage("Error","API:" +login.server+api+"\n NO RESPONSE"+xhrequest.statusText,rootwindow);
13
+                        //callback(xhrequest.responseText)
14 14
                     }
15 15
               }
16
-               catch (e){
17
-                     showMessage("Error", api+" "+e+" "+xhrequest.statusText,rootwindow)
16
+               catch (e){print(e);
17
+                     showMessage("Error",  xhrequest.responseText,rootwindow)
18 18
                 }
19 19
             }
20 20
         }
@@ -60,7 +60,7 @@ function friendicaWebRequest(url,rootwindow,callback) {
60 60
             } else if(xhrequest.readyState === XMLHttpRequest.DONE) {
61 61
                 try{ callback(xhrequest.responseText);
62 62
               }
63
-               catch (e){
63
+               catch (e){print(e);
64 64
                  showMessage("Error",url+" "+e, rootwindow)
65 65
                }
66 66
             }
@@ -130,3 +130,8 @@ var arraystring=JSON.stringify(array);
130 130
     arraystring=arraystring.replace(/[\[\]]/g , '');
131 131
 return arraystring;
132 132
 }
133
+
134
+function cleanDate(date){
135
+var cleanedDate= date.slice(0,3)+", "+date.slice(8,11)+date.slice(4,7)+date.slice(25,30)+date.slice(10,25);
136
+return cleanedDate
137
+}

+ 11
- 12
source-android/js/news.js View File

@@ -32,13 +32,12 @@ function requestGroups(login,database,rootwindow,callback){
32 32
 function getFriendsTimeline(login,database,contacts,onlynew,rootwindow,callback){
33 33
     // 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)
34 34
     var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
35
-    var parameter = "";
35
+    var parameter = "?count=50";
36 36
     if(onlynew){db.transaction( function(tx) {
37 37
         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
38
-        try{parameter="&since_id="+result.rows.item(0).status_id;}catch(e){};})}
38
+        try{parameter=parameter+"&since_id="+result.rows.item(0).status_id;}catch(e){};})}
39 39
         var newContacts=[];
40
-        //print("/api/statuses/friends_timeline"+parameter);
41
-        Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){
40
+        Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){print(obj);
42 41
             var news=JSON.parse(obj);
43 42
             var newContacts=findNewContacts(news,contacts);
44 43
             callback(news,newContacts)
@@ -53,7 +52,7 @@ function getCurrentContacts(login,database,callback){
53 52
            contactlist.push(result.rows.item(i).url )
54 53
            //print(result.rows.item(i).url)
55 54
          }
56
-    var lastDate=Date.now()-172800000;//  2 days old
55
+    var lastDate=Date.now()-604800000;//  7 days old
57 56
     //print('SELECT url from contacts WHERE username="'+login.username+'" AND isFriend=0 AND imageAge>'+lastDate);
58 57
     var result2 = tx.executeSql('SELECT url from contacts WHERE username="'+login.username+'" AND isFriend=0 AND imageAge > '+lastDate);
59 58
     for (var j=0;j<result2.rows.length;j++){
@@ -63,18 +62,18 @@ function getCurrentContacts(login,database,callback){
63 62
 callback(contactlist)
64 63
 }
65 64
 
66
-function findNewContacts(news,contacts){//print("contacts: "+JSON.stringify(contacts))
65
+function findNewContacts(news,contacts){//print("contacts: "+JSON.stringify(news))
67 66
     var newContacts=[];
68 67
     for (var i=0;i<news.length;i++){
69 68
         var url=news[i].user.url;
70
-        if(contacts.indexOf(url)==-1 &&  !(inArray(newContacts,"url",url))){print("new contact "+JSON.stringify(news[i].user));
69
+        if(contacts.indexOf(url)==-1 &&  !(inArray(newContacts,"url",url))){
71 70
             news[i].user.isFriend=0;
72 71
             newContacts.push(news[i].user);
73 72
             }
74 73
         if (news[i].friendica_activities.like.length>0){
75 74
             for (var j=0;j<news[i].friendica_activities.like.length;j++){
76 75
                 var like_url=news[i].friendica_activities.like[j].url;
77
-                if(contacts.indexOf(like_url)==-1 &&  !(inArray(newContacts,"url",like_url))){print("new like contact "+JSON.stringify(news[i].friendica_activities.like[j]));
76
+                if(contacts.indexOf(like_url)==-1 &&  !(inArray(newContacts,"url",like_url))){
78 77
                     news[i].friendica_activities.like[j].isFriend=0;
79 78
                     newContacts.push(news[i].friendica_activities.like[j]);
80 79
                 }
@@ -83,7 +82,7 @@ function findNewContacts(news,contacts){//print("contacts: "+JSON.stringify(cont
83 82
          if (news[i].friendica_activities.dislike.length>0){
84 83
             for (var k=0;j<news[k].friendica_activities.dislike.length;k++){
85 84
                 var dislike_url=news[i].friendica_activities.dislike[k].url;
86
-                if(contacts.indexOf(dislike_url)==-1 &&  !(inArray(newContacts,"url",dislike_url))){print("new dislike contact "+JSON.stringify(news[i].friendica_activities.dislike[k]));
85
+                if(contacts.indexOf(dislike_url)==-1 &&  !(inArray(newContacts,"url",dislike_url))){
87 86
                     news[i].friendica_activities.dislike[k].isFriend=0;
88 87
                         newContacts.push(news[i].friendica_activities.dislike[k]);
89 88
                 }
@@ -110,7 +109,7 @@ function storeNews(login,database,news,rootwindow,callback){
110 109
         var attendnoarray=[]; for (var user in news[i].friendica_activities.attendno){attendnoarray.push(news[i].friendica_activities.attendno[user].url)}
111 110
         var attendmaybearray=[]; for (var user in news[i].friendica_activities.attendmaybe){attendmaybearray.push(news[i].friendica_activities.attendmaybe[user].url)}
112 111
         var friendica_activities=[likearray,dislikearray,attendyesarray,attendnoarray,attendmaybearray]
113
-        var attachments="";if (news[i].attachments){attachments=Qt.btoa(JSON.stringify(news[i].attachments))}print(attachments)
112
+        var attachments="";if (news[i].attachments){attachments=Qt.btoa(JSON.stringify(news[i].attachments))}
114 113
         db.transaction( function(tx) {
115 114
             var result = tx.executeSql('SELECT * from news where username="'+login.username+'" AND status_id = "'+news[i].id+'" AND messagetype=0'); // check for news id
116 115
             if(result.rows.length === 1) {// use update
@@ -265,7 +264,7 @@ function  likerequest(login,database,verb,newsid,rootwindow){
265 264
             db.transaction( function(tx) {
266 265
                 var currentActivities_rs=tx.executeSql('select friendica_activities_self from news WHERE username="'+login.username+'" AND status_id='+newsid) ;
267 266
                 var currentActivities=JSON.parse(currentActivities_rs.rows.item(0).friendica_activities_self);
268
-                print(verb+"currentActivities "+JSON.stringify(currentActivities));
267
+                //print(verb+"currentActivities "+JSON.stringify(currentActivities));
269 268
                 if ((verb=="like")&&(currentActivities.indexOf(1)==-1)){ currentActivities.push(1);
270 269
                     if (currentActivities.indexOf(2)!=-1){currentActivities.splice(currentActivities.indexOf(2),1)}
271 270
                 }
@@ -349,7 +348,7 @@ function requestFavorites(login,database,contacts,rootwindow,callback){
349 348
 function favoritesfromdb(database,user,callback){
350 349
     var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
351 350
     db.transaction( function(tx) {
352
-        print('select * from news WHERE username="'+user+'" AND favorited=1 ORDER BY status_id DESC');
351
+        //print('select * from news WHERE username="'+user+'" AND favorited=1 ORDER BY status_id DESC');
353 352
         var newsrs=tx.executeSql('select * from news WHERE username="'+user+'" AND favorited=1 ORDER BY status_id DESC');
354 353
         var newsArray=[];
355 354
         for(var i = 0; i < newsrs.rows.length; i++) {

+ 11
- 3
source-android/js/newsworker.js View File

@@ -19,7 +19,7 @@ WorkerScript.onMessage = function(msg) {
19 19
               else {likeText= newsitemobject.like.length+" "+ qsTr("like this.")}
20 20
            }
21 21
            if (newsitemobject.dislike.length>0){
22
-              if (newsitemobject.dislike.length==1){dislikeText= QT.atob(newsitemobject.dislike[0].name)+" "+ qsTr("doesn't like this.")}
22
+              if (newsitemobject.dislike.length==1){dislikeText= Qt.atob(newsitemobject.dislike[0].name)+" "+ qsTr("doesn't like this.")}
23 23
               else {dislikeText= newsitemobject.dislike.length+" "+ qsTr("don't like this.")}
24 24
            }
25 25
            if (newsitemobject.attendyes.length>0){
@@ -42,7 +42,15 @@ WorkerScript.onMessage = function(msg) {
42 42
            if (newsitemobject.friendica_activities_self.indexOf(2)!=-1){self.disliked=1}
43 43
           }
44 44
            var friendica_activities={likeText:likeText,dislikeText:dislikeText,attendyesText:attendyesText,attendnoText:attendnoText,attendmaybeText:attendmaybeText,self:self}
45
-        //print(JSON.stringify(friendica_activities) )  ;
45
+
46
+        var attachmentList=[];if(newsitemobject.attachments){
47
+            var attachArray=JSON.parse(Qt.atob(newsitemobject.attachments));
48
+            for (var image in attachArray){if(attachArray[image].mimetype=="image/gif"){
49
+                attachmentList.push(attachArray[image])
50
+                }
51
+            }
52
+        }
53
+        newsitemobject.attachmentList=attachmentList;
46 54
         var seconds=(msg.currentTime-newsitemobject.created_at)/1000;
47 55
            var timestring="";
48 56
            if (seconds<60) {timestring=seconds+" "+qsTr("seconds") +" "+qsTr("ago");}
@@ -54,7 +62,7 @@ WorkerScript.onMessage = function(msg) {
54 62
                 else if (seconds<3888000){timestring=Math.round(seconds/86400)+" "+qsTr("days") +" "+qsTr("ago");}
55 63
                 else if (seconds<5832000){timestring=Math.round(seconds/3888000)+" "+qsTr("month") +" "+qsTr("ago");}
56 64
                 else if (seconds<69984000){timestring=Math.round(seconds/3888000)+" "+qsTr("months") +" "+qsTr("ago");}
57
-                else {timestring=Math.round(seconds/69984000)+" "+qsTr("years") +" "+qsTr("ago");}
65
+                else {timestring=Math.round(seconds/46656000)+" "+qsTr("years") +" "+qsTr("ago");}
58 66
             var data=({"newsitemobject": newsitemobject,"dateDiff":timestring,"friendica_activities":friendica_activities})}
59 67
           //print("News:"+j+msg.news.length+JSON.stringify(data));
60 68
             msg.model.append(data);}

+ 107
- 5
source-android/js/service.js View File

@@ -121,8 +121,93 @@ function initDatabase(database) { // initialize the database object
121 121
         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)');
122 122
         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)');
123 123
         tx.executeSql('CREATE TABLE IF NOT EXISTS groups(username TEXT, groupname TEXT, gid INT, members TEXT)');
124
+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)');
124 125
 })}
125 126
 
127
+function cleanPermissions(oldperms){
128
+    var newperms=oldperms.replace("<","");newperms=newperms.replace(">","");newperms="["+newperms+"]";
129
+    var newpermArray=JSON.parse(newperms);
130
+return (newpermArray)
131
+}
132
+
133
+function getEvents(database,login,rootwindow,callback){
134
+var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
135
+    Helperjs.friendicaWebRequest(login.server+"/cal/"+login.username+"/json",rootwindow,function(obj){
136
+    var events = JSON.parse(obj);
137
+    db.transaction( function(tx) {
138
+    for (var i=0;i<events.length;i++){
139
+    var permissions=[];
140
+    permissions.push(cleanPermissions(events[i].item.allow_cid));
141
+    permissions.push(cleanPermissions(events[i].item.allow_gid));
142
+    permissions.push(cleanPermissions(events[i].item.deny_cid));
143
+    permissions.push(cleanPermissions(events[i].item.deny_gid));
144
+    var result = tx.executeSql('SELECT * from events where username="'+login.username+'" AND id = '+events[i].id); // check for news id
145
+    if(result.rows.length === 1) {// use update
146
+        result = tx.executeSql('UPDATE events SET username="'+login.username+'", start="'+Date.parse(events[i].start)+'", end="'+Date.parse(events[i].end)+'", allday="'+Number(events[i].allday)+'", title="'+events[i].title+'", j="'+events[i].j+'", d="'+events[i].d+ '", isFirst="'+Number(events[i].isFirst)+'", uid="'+events[i].item.uid+'", cid="'+events[i].item.cid+'", uri="'+events[i].item.uri+'", created="'+ Date.parse(events[i].item.created)+'", edited="'+ Date.parse(events[i].item.edited)+'", desc="'+events[i].item.desc+'", location="'+events[i].item.location+'", type="'+events[i].item.type+'", nofinish="'+events[i].item.nofinish+'", adjust ="'+events[i].item.adjust+'", ignore="'+events[i].item.ignore+'", permissions="'+ JSON.stringify(permissions)+'", guid="'+events[i].item.guid+'", itemid="'+events[i].item.itemid+  '", plink="'+events[i].item.plink+  '", authorName="'+events[i].item["author-name"]+ '", authorAvatar="'+events[i].item["author-avatar"]+ '", authorLink="'+events[i].item["author-link"]+ '", html="'+Qt.btoa(events[i].html)+'" where username="'+login.username+'" AND id='+events[i].id);
147
+    } else {// use insert
148
+        result = tx.executeSql('INSERT INTO events (username,id,start,end,allday,title,j,d,isFirst,uid,cid,uri,created,edited,desc,location,type,nofinish,adjust,ignore,permissions,guid,itemid,plink,authorName,authorAvatar,authorLink,html) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username, events[i].id, Date.parse(events[i].start), Date.parse(events[i].end), events[i].allday, events[i].title, events[i].j, events[i].d, events[i].isFirst, events[i].item.uid, events[i].item.cid, events[i].item.uri, Date.parse(events[i].item.created), Date.parse(events[i].item.edited), events[i].item.desc, events[i].item.location, events[i].item.type, events[i].item.nofinish, events[i].item.adjust, events[i].item.ignore, JSON.stringify(permissions), events[i].item.guid, events[i].item.itemid, events[i].item.plink, events[i].item["author-name"], events[i].item["author-avatar"], events[i].item["author-link"], Qt.btoa(events[i].html)])}
149
+    callback()
150
+    }
151
+})})}
152
+
153
+function newscount(database, callback){
154
+    var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
155
+     db.transaction( function(tx) {
156
+            var newscountrs = tx.executeSql('SELECT COUNT(*) from news');
157
+            var newscount = newscountrs.rows.item(0)["COUNT(*)"];
158
+            callback(newscount)
159
+    })
160
+}
161
+
162
+function eventsfromdb(database, username,callback){
163
+var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
164
+    db.transaction( function(tx) {
165
+    var eventrs=tx.executeSql('select * from events WHERE username="'+username+'" ORDER BY start ASC');
166
+    var eventArray=[];
167
+    var dayArray=[];
168
+    for(var i = 0; i < eventrs.rows.length; i++) {
169
+        eventArray.push(eventrs.rows.item(i));
170
+       // eventArray[i]=fetchUsersForNews(database,username,newsArray[i])
171
+        dayArray.push(Math.floor(eventrs.rows.item(i).start/86400000));
172
+    }
173
+    callback(eventArray,dayArray)});
174
+}
175
+
176
+function requestFriendsEvents(login,friend,rootwindow,callback){
177
+// get calendar JSON  object of contact without user and password
178
+    Helperjs.friendicaWebRequest(friend.replace("profile","cal")+"/json",rootwindow,function(calhtml){
179
+    //print(calhtml);
180
+    var eventarray=[];var eventdays=[];
181
+    var events=JSON.parse(calhtml);
182
+    for (var i=0;i<events.length;i++){
183
+        var permissions=[];
184
+        permissions.push(cleanPermissions(events[i].item.allow_cid));
185
+        permissions.push(cleanPermissions(events[i].item.allow_gid));
186
+        permissions.push(cleanPermissions(events[i].item.deny_cid));
187
+        permissions.push(cleanPermissions(events[i].item.deny_gid));
188
+    
189
+        var event ={}
190
+        event.start=Date.parse(events[i].start);event.end=Date.parse(events[i].end);
191
+        event.allday=events[i].allday; event.title=events[i].title; event.j=events[i].j;
192
+        event.d=events[i].d; event.isFirst=events[i].isFirst; event.uid=events[i].item.uid;
193
+        event.cid=events[i].item.cid; event.uri=events[i].item.uri;
194
+        event.created=Date.parse(events[i].item.created); event.edited=Date.parse(events[i].item.edited);
195
+        event.desc=events[i].item.desc; event.location=events[i].item.location; event.type=events[i].item.type;
196
+        event.nofinish=events[i].item.nofinish; event.adjust =events[i].item.adjust; event.ignore=events[i].item.ignore;
197
+        event.permissions=JSON.stringify(permissions); event.guid=events[i].item.guid;
198
+        event.itemid=events[i].item.itemid; event.plink=events[i].plink; event.authorName=events[i].item["author-name"];
199
+        event.authorAvatar=events[i].item["author-avatar"]; event. authorLink=events[i].item["author-link"];
200
+        event.html=Qt.btoa(events[i].html);
201
+        eventarray.push(event);
202
+//        var offsetTime = new Date().getTimezoneOffset() * 60 * 1000;print(new Date(event.start).toLocaleString()+"Zeitverschiebung:"+offsetTime)
203
+//        var time = event.start - offsetTime;
204
+        eventdays.push(Math.floor(event.start/(24*60*60*1000)))
205
+    }
206
+    //print(JSON.stringify(eventarray));
207
+    callback(eventarray,eventdays)
208
+ })
209
+}
210
+
126 211
 function savePermissions(database,obj) { // stores config to DB
127 212
  var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
128 213
  var permissions=JSON.stringify(obj)
@@ -147,6 +232,18 @@ function storeConfig(database,obj) { // stores config to DB
147 232
         }
148 233
  })}
149 234
 
235
+function showServerConfig(url,rootwindow,callback){//print(url);
236
+Helperjs.friendicaWebRequest(url+"/api/statusnet/config",rootwindow, function (obj){
237
+    var serverconfig = JSON.parse(obj);
238
+    var serverConfigString="import QtQuick 2.0; import QtQuick.Dialogs 1.2; MessageDialog{ visible: true; title:'Server';standardButtons: StandardButton.Ok;text: 'Name: "+serverconfig.site.name+"\nLanguage: "+serverconfig.site.language+
239
+                        "\nEmail: "+serverconfig.site.email+"\nTimezone: "+serverconfig.site.timezone+"\nClosed: "+serverconfig.site.closed+
240
+                        "\nText limit: "+serverconfig.site.textlimit+"\nShort Url length: "+serverconfig.site.shorturllength+
241
+                        "\nFriendica version: "+serverconfig.site.friendica.FRIENDICA_VERSION+"\nDFRN version: "+serverconfig.site.friendica.DFRN_PROTOCOL_VERSION +
242
+                        "\nDB Update version: "+serverconfig.site.friendica.DB_UPDATE_VERSION+"'}";
243
+callback(serverConfigString)
244
+})}
245
+
246
+
150 247
 function getServerConfig(database,login,rootwindow,callback){
151 248
 // check server with given credentials
152 249
 try {Helperjs.friendicaRequest(login,"/api/statusnet/config",rootwindow, function (obj){
@@ -212,8 +309,9 @@ function  cleanNews(database,callback){
212 309
              var maxnews=maxnewsrs.rows.item(0).maxnews;
213 310
              var newscountrs = tx.executeSql('SELECT COUNT(*) from news');
214 311
              var newscount = newscountrs.rows.item(0)["COUNT(*)"];
215
-             if (newscount>maxnews){var lastvalidtimers= tx.executeSql('select created_at from news ORDER BY created_at DESC LIMIT ' +(newscount-maxnews));
216
-                 var lastvalidtime=lastvalidtimers.rows.item(maxnews).created_at;
312
+             if (newscount>maxnews){
313
+                 var lastvalidtimers= tx.executeSql('SELECT DISTINCT created_at FROM news ORDER BY created_at ASC LIMIT ' +(newscount-maxnews));
314
+                 var lastvalidtime=lastvalidtimers.rows.item(newscount-maxnews-1).created_at;
217 315
                  var deleters = tx.executeSql('DELETE from news WHERE created_at<='+lastvalidtime)}
218 316
              callback()
219 317
      })
@@ -260,13 +358,17 @@ function processNews(callback){
260 358
 function updateContactInDB(login,database,isFriend,contact){// for newstab and friendstab
261 359
 //    var suffix=contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("."), contact.profile_image_url.length);
262 360
 //    var imagename=login.imagestore+"contacts/"+contact.screen_name.trim()+suffix;
263
-    var imagename=login.imagestore+"contacts/"+contact.screen_name+"-"+contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("/")+1, contact.profile_image_url.length);
264
-    contacttimer.restart();
361
+    
362
+var imagename="";
363
+contacttimer.restart();
265 364
     var currentTime=Date.now();
365
+    if(contact.profile_image_url==""){root.currentContact=root.currentContact+1 } else{//print(JSON.stringify(contact))
366
+        imagename=login.imagestore+"contacts/"+contact.screen_name+"-"+contact.profile_image_url.substring(contact.profile_image_url.lastIndexOf("/")+1, contact.profile_image_url.length);
367
+    
266 368
     xhr.setUrl(Qt.resolvedUrl(contact.profile_image_url));
267 369
     xhr.setFilename(imagename);
268 370
     xhr.setDownloadtype("contact");
269
-    xhr.download();
371
+    xhr.download();}
270 372
     var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
271 373
     var result;
272 374
     db.transaction( function(tx) {

+ 47
- 0
source-android/qml/calendarqml/CalendarDay.qml View File

@@ -0,0 +1,47 @@
1
+import QtQuick 2.0
2
+import QtQuick.Controls 1.4
3
+
4
+Item {
5
+    id: calendarDay
6
+    width:7*mm
7
+    height: 7*mm
8
+    property int dateInt:Math.floor((Date.parse(model.date)-(new Date().getTimezoneOffset() * 60 * 1000))/86400000)
9
+    Rectangle {
10
+        id: placeHolder
11
+        color: 'lightblue'; antialiasing: true
12
+        anchors.fill:parent
13
+    }
14
+    Text {
15
+        id:daytext
16
+        anchors.right: parent.right
17
+        anchors.margins: 0.5*mm
18
+        color:(model.month==monthgrid.month)?"black":"grey"
19
+        wrapMode: Text.WrapAnywhere
20
+        text: model.day
21
+        font.bold: model.today
22
+        font.pixelSize: 4*mm
23
+    }
24
+    Rectangle {
25
+        id:eventRect
26
+        color:"black"
27
+        anchors.margins: 0.5*mm
28
+        anchors.bottom: calendarDay.bottom
29
+        width: parent.width-mm
30
+        height: mm
31
+        visible: eventdays.indexOf(dateInt)>-1
32
+    }
33
+    MouseArea {
34
+        anchors.fill: calendarDay
35
+        onClicked: {
36
+            var eventDate=[];
37
+            var idx = eventdays.indexOf(dateInt);
38
+            while (idx != -1) {
39
+                eventDate.push(idx);
40
+                idx = eventdays.indexOf(dateInt,idx + 1)
41
+            }
42
+            var component = Qt.createComponent("qrc:/qml/calendarqml/EventList.qml");
43
+            if (component.status== Component.Ready){
44
+                var eventlist = component.createObject(calendartab,{"daylist": eventDate})}
45
+        }
46
+    }
47
+}

+ 134
- 0
source-android/qml/calendarqml/CalendarTab.qml View File

@@ -0,0 +1,134 @@
1
+import QtQuick 2.0
2
+import QtQuick.Controls 2.1
3
+import QtQml 2.2
4
+import Qt.labs.calendar 1.0
5
+import QtQuick.Layouts 1.3
6
+import "qrc:/js/service.js" as Service
7
+import "qrc:/js/helper.js" as Helperjs
8
+import "qrc:/qml/calendarqml"
9
+import "qrc:/qml/genericqml"
10
+
11
+Rectangle {
12
+    id:calendarrectangle
13
+    y:1
14
+    width:root.width-mm
15
+    height:root.height-5*mm
16
+    color: '#fff'
17
+    property date currentTime: new Date()
18
+    property int offsetTime: currentTime.getTimezoneOffset() * 60 * 1000
19
+    property var events:[]
20
+    property var eventdays:[]
21
+    onEventdaysChanged: print(JSON.stringify(eventdays))
22
+
23
+    function showEvents(friend){
24
+        if(friend=="backButton"){Service.eventsfromdb(db,login.username,function(eventArray,dayArray){
25
+            events=eventArray;
26
+            eventdays=dayArray})
27
+        }
28
+        else if (friend!=""){
29
+           calendartab.calendartabstatus=friend.substring(friend.lastIndexOf("/")+1,friend.length)
30
+            Service.requestFriendsEvents(login,friend,calendartab,function(eventArray,dayArray){
31
+            events=eventArray;
32
+            eventdays=dayArray})
33
+        }
34
+        else {calendartab.calendartabstatus="Events";
35
+ Service.eventsfromdb(db,login.username,function(eventArray,dayArray){
36
+            events=eventArray;
37
+            eventdays=dayArray;
38
+            calBusy.running=false
39
+            })
40
+        }
41
+    }
42
+
43
+    BusyIndicator{
44
+         id: calBusy
45
+         anchors.horizontalCenter: calendarView.horizontalCenter
46
+         anchors.top:calendarView.top
47
+         anchors.topMargin: 2*mm
48
+         width:10*mm
49
+         height: 10*mm
50
+         running: false
51
+       }
52
+
53
+
54
+    BlueButton{
55
+        id:  updateEvents
56
+        anchors.top: parent.top
57
+        anchors.topMargin: 0.5*mm
58
+        anchors.right:calendartabstatusButton.left
59
+        anchors.rightMargin:mm
60
+        text:"\uf021"
61
+        onClicked: {
62
+            
63
+            Service.getEvents(db,login, calendartab,function(){
64
+               showEvents("")
65
+    })}}
66
+
67
+    BlueButton{
68
+        id:  calendartabstatusButton
69
+        anchors.top: parent.top
70
+        anchors.topMargin: 0.5*mm
71
+        anchors.right: parent.right
72
+        anchors.rightMargin:2*mm
73
+        text: calendartab.calendartabstatus=="Events"?qsTr("Events"):calendartabstatus
74
+        onClicked: {calendartabmenu.popup()}
75
+    }
76
+    Menu {
77
+        id:calendartabmenu
78
+        MenuItem {
79
+            text: qsTr("Own Calendar")
80
+            onTriggered: {
81
+                calendartab.calendartabstatus="Events";
82
+               // calendartabstatusButton.text=qsTr("own Calendar");
83
+                showEvents("")}
84
+        }
85
+    }
86
+
87
+    ListView{
88
+        id: calendarView
89
+        x: mm;y:8*mm
90
+        width: parent.width-2*mm; height: parent.height-9*mm
91
+        clip: true
92
+        snapMode: ListView.SnapOneItem
93
+        orientation: ListView.Horizontal
94
+        highlightRangeMode: ListView.StrictlyEnforceRange
95
+        model:     CalendarModel {id:calendarModel
96
+            from: new Date()
97
+            to: new Date(new Date().valueOf()+93312000000)
98
+        }
99
+        delegate:
100
+            ColumnLayout{
101
+                width:calendarView.width
102
+                Text{
103
+                    font.bold: true
104
+                    Layout.fillWidth: true
105
+                    horizontalAlignment:Text.AlignHCenter
106
+                    text: model.year
107
+                }
108
+                Text{
109
+                    text: Qt.locale().standaloneMonthName(model.month)
110
+                    Layout.fillWidth: true
111
+                   horizontalAlignment:Text.AlignHCenter
112
+                }
113
+                DayOfWeekRow{
114
+                    locale: monthgrid.locale
115
+                    Layout.fillWidth: true
116
+                }
117
+
118
+                MonthGrid {
119
+                    id: monthgrid
120
+                    Layout.fillWidth: true
121
+                    month: model.month
122
+                    year: model.year
123
+                    locale: Qt.locale()
124
+                    delegate: CalendarDay{}
125
+               }
126
+        }
127
+        ScrollIndicator.horizontal: ScrollIndicator { }
128
+    }
129
+    
130
+    Component.onCompleted: {
131
+        root.eventSignal.connect(showEvents);
132
+        if (calendartab.calendartabstatus=="Events"){showEvents("")}
133
+    }
134
+ }

+ 85
- 0
source-android/qml/calendarqml/EventList.qml View File

@@ -0,0 +1,85 @@
1
+import QtQuick 2.0
2
+import QtQuick.Controls 1.2
3
+import "qrc:/js/service.js" as Service
4
+import "qrc:/js/helper.js" as Helperjs
5
+import "qrc:/qml/genericqml"
6
+
7
+Rectangle{
8
+    id:eventList
9
+    z:2
10
+    border.color: "grey"
11
+    width: parent.width-4*mm
12
+    height:parent.height-12*mm
13
+    x:mm
14
+    y:mm
15
+    property var daylist:[]
16
+
17
+    BlueButton{
18
+       id:closeButton
19
+       anchors.top: parent.top
20
+       anchors.topMargin: 1*mm
21
+       anchors.right: parent.right
22
+       anchors.rightMargin: 1*mm
23
+       text: "\uf057"
24
+       onClicked:{eventList.destroy()}
25
+    }
26
+      ListView {
27
+          id: eventlistView
28
+          x: mm
29
+          y:closeButton.height+2*mm
30
+          width: eventList.width-2*mm
31
+          height: eventList.height-closeButton.height-4*mm
32
+          clip: true
33
+          model: eventModel
34
+          delegate: eventItem
35
+     }
36
+
37
+     ListModel{
38
+         id: eventModel
39
+     }
40
+
41
+     Component.onCompleted:{
42
+         //print(JSON.stringify(daylist))
43
+         for (var i=0; i<daylist.length;i++){//print(JSON.stringify(events[daylist[i]]));
44
+             var liststate="";if(daylist.length<2){liststate="large"}
45
+             eventModel.append({"event":events[daylist[i]],"eventstatus":liststate});
46
+         }
47
+     }
48
+
49
+     Component{
50
+         id:eventItem
51
+         Rectangle{
52
+            property string status: eventstatus
53
+             width:eventlistView.width
54
+             height:eventNameText.height+eventDetailsText.height+mm
55
+             border.color: "light grey"
56
+             border.width: 1
57
+            Text {
58
+                id:eventNameText
59
+                x:mm
60
+                width:parent.width
61
+                height:contentHeight
62
+                text: new Date(event.start+calendarrectangle.offsetTime).toLocaleTimeString()+": "+event.title
63
+                font.pixelSize: 3*mm
64
+                wrapMode:Text.Wrap
65
+            }
66
+            
67
+            Text {
68
+                id:eventDetailsText
69
+                x:mm
70
+                z:4
71
+                width: parent.width
72
+                height: contentHeight
73
+                text: status==""?"":Qt.atob(event.html)
74
+                anchors.top: eventNameText.bottom
75
+                font.pixelSize: 3*mm
76
+                wrapMode:Text.Wrap
77
+            }
78
+            MouseArea{
79
+                anchors.fill: parent
80
+                onClicked:{if (status==""){status="large"} else {status=""}
81
+                }
82
+            }
83
+         }
84
+    }
85
+}

+ 47
- 24
source-android/qml/configqml/ConfigTab.qml View File

@@ -1,4 +1,4 @@
1
-import QtQuick 2.0
1
+import QtQuick 2.7
2 2
 import QtQuick.Dialogs 1.2
3 3
 import QtQuick.Controls 1.2
4 4
 import "qrc:/js/service.js" as Service
@@ -15,13 +15,18 @@ StackView{
15 15
     height:root.height-12*mm
16 16
     contentHeight: configBackground.height
17 17
     boundsBehavior: Flickable.StopAtBounds
18
+   
18 19
     Rectangle{
19 20
         id:configBackground
20 21
         color: "white"
21 22
         width:parent.width
22 23
         height:Math.max(90*mm,root.height-12*mm)
23 24
         property var users:[]
24
-
25
+        function setServericon(server){
26
+           try {Helperjs.friendicaWebRequest(server+"/api/statusnet/config",configBackground, function (obj){
27
+                         var serverdata = JSON.parse(obj);
28
+                         servericon.source=serverdata.site.logo})} catch(e){print(e)}
29
+        }
25 30
         BlueButton{
26 31
             id:userButton
27 32
             text:qsTr("User")
@@ -35,6 +40,7 @@ StackView{
35 40
                         "'; onTriggered: {Service.readConfig(db,function(obj){
36 41
                         userButton.text=obj.username;
37 42
                         servername.text=obj.server;
43
+                        configBackground.setServericon(obj.server);
38 44
                         username.text= obj.username;
39 45
                         password.text=Qt.atob(obj.password);
40 46
                         imagestore.text=obj.imagestore;
@@ -49,37 +55,51 @@ StackView{
49 55
             }
50 56
 
51 57
     Text {
52
-      text: "Server"
58
+      text: qsTr("Server")
53 59
      x: 4*mm; y: 10*mm
54 60
     }
55 61
     Text {
56
-      text: "User"
62
+      text: qsTr("User")
57 63
      x: 4*mm; y: 20*mm
58 64
     }
59 65
 
60 66
     Text {
61
-        text: "Password"
67
+        text: qsTr("Password")
62 68
        x: 4*mm; y: 30*mm
63 69
       }
64 70
     Text {
65
-       text: "Image dir."
71
+       text: qsTr("Image dir.")
66 72
       x: 4*mm; y: 40*mm
67 73
      }
68 74
 
69 75
    Text {
70
-       text: "Max. News"
76
+       text: qsTr("Max. News")
71 77
       x: 4*mm; y: 50*mm
72 78
      }
73 79
    Text {
74
-       text: "News as"
80
+       text: qsTr("News as")
75 81
       x: 4*mm; y: 60*mm
76 82
      }
77 83
     Text {
78
-        text: "Interval (0=None)"
84
+        text: qsTr("Interval (0=None)")
79 85
         visible: false
80 86
         x: 4*mm; y: 70*mm; width:20*mm;wrapMode: Text.Wrap
81 87
       }
82 88
 
89
+        Image{
90
+            id:servericon
91
+            x:19*mm;y:10*mm
92
+            width:5*mm; height: 5*mm
93
+            source:""
94
+            MouseArea{
95
+                anchors.fill:parent
96
+                onClicked:{
97
+                    Service.showServerConfig(servername.text, configBackground, function(configString){
98
+                    var serverconfigObject=Qt.createQmlObject(configString,configBackground,"serverconfigOutput");})
99
+                }
100
+            }
101
+        }
102
+
83 103
         Rectangle{color: "light grey";  x: 25*mm; y: 10*mm; width: root.width/2; height: 5*mm;}
84 104
          Flickable {
85 105
          id: servernameFlickable
@@ -93,9 +113,13 @@ StackView{
93 113
              height: servernameFlickable.height
94 114
              focus: true
95 115
              text:"https://..."
96
-             //wrapMode: TextEdit.NoWrap
97
-             //validator: RegExpValidator { regExp: /^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$/}
98
-            // onEditingFinished:{}
116
+             onEditingFinished:{
117
+                 if((servername.text).substring(0,14) =="https://...http"){
118
+                     serverstring.text= (serverstring.text).substring(11)
119
+                 }
120
+
121
+               configBackground.setServericon(servername.text)
122
+             }
99 123
             onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,servernameFlickable)
100 124
          }
101 125
      }
@@ -134,9 +158,11 @@ StackView{
134 158
          }
135 159
      }
136 160
     Slider{ id: maxNews
137
-        x:37*mm; y: 50*mm;width: root.width/3;height:5*mm
138
-        minimumValue: 0;maximumValue:100000; stepSize: 1000
161
+        x:34*mm; y: 50*mm;width: root.width/3;height:5*mm
162
+        minimumValue: 0;maximumValue:2000; stepSize: 100
139 163
     }
164
+
165
+
140 166
     Rectangle{color: "light grey"; x: 25*mm; y: 50*mm; width: 9*mm; height: 5*mm;
141 167
         TextEdit{id:maxNewsText;
142 168
             anchors.fill: parent
@@ -199,13 +225,12 @@ StackView{
199 225
 
200 226
 
201 227
     BlueButton {
202
-    x: 25*mm; y: 80*mm
203
-    text: "Confirm"
228
+    x: 25*mm; y: 78*mm
229
+    text: qsTr("Confirm")
204 230
     onClicked:{
205 231
          var userconfig={server: servername.text, username: username.text, password:Qt.btoa(password.text), imagestore:imagestore.text,maxnews:maxNewsText.text,interval:  messageIntervalField.text, newsViewType:newsTypeField.text};
206 232
          var errormessage="";
207 233
          if (servername.text==""){errormessage=qsTr("No server given! ")}
208
-         //if (!servername.acceptableInput){errormessage+=qsTr("Server name not valid! ")}
209 234
          else if (username.text==""){errormessage+=qsTr("No username given! ")}
210 235
          else if (password.text=="") {errormessage+=qsTr("No password given! ")}
211 236
          else if (imagestore.text=="") {errormessage+=qsTr("No image directory given!")}
@@ -228,11 +253,6 @@ StackView{
228 253
              userButton.color="black"
229 254
              //reset values
230 255
              root.login=userconfig;
231
-//             root.contactlist=[];
232
-//             root.news=[];
233
-//             root.newContacts=[];
234
-//             root.currentContact= 0;
235
-//             root.contactLoadType= "";
236 256
              newstab.newstabstatus=userconfig.newsViewType;
237 257
              root.currentIndex=0;
238 258
              newstab.active=true;
@@ -252,6 +272,7 @@ StackView{
252 272
            filesystem.Directory=imagestore.text+"albums";
253 273
            filesystem.rmDir();
254 274
            servername.text="https://...";
275
+           servericon.source="";
255 276
            username.text="";
256 277
            password.text="";
257 278
            imagestore.text="";
@@ -272,6 +293,7 @@ StackView{
272 293
     text: "+"
273 294
     onClicked:{
274 295
         servername.text="https://..."
296
+        servericon.source="";
275 297
         username.text=""
276 298
         password.text=""
277 299
         imagestore.text=""
@@ -297,8 +319,8 @@ StackView{
297 319
             onTriggered: {newsTypeField.text="Timeline"}
298 320
             }
299 321
         MenuItem {
300
-            text: qsTr("Tree")
301
-            onTriggered: {newsTypeField.text="Tree"}
322
+            text: qsTr("Conversations")
323
+            onTriggered: {newsTypeField.text="Conversations"}
302 324
             }
303 325
     }
304 326
 
@@ -311,6 +333,7 @@ StackView{
311 333
           Service.readConfig(db,function(obj){
312 334
             userButton.text=obj.username;
313 335
             servername.text=obj.server;
336
+            configBackground.setServericon(obj.server);
314 337
             username.text= obj.username;
315 338
             password.text=Qt.atob(obj.password);
316 339
             imagestore.text=obj.imagestore;

+ 1
- 28
source-android/qml/contactqml/ContactComponent.qml View File

@@ -47,38 +47,11 @@ Rectangle {
47 47
         anchors.topMargin: mm
48 48
         anchors.top: parent.top
49 49
         onClicked:{
50
-            contactComponent.state="large";
51 50
             var component = Qt.createComponent("qrc:/qml/contactqml/ContactDetailsComponent.qml");
52 51
             if (component.status== Component.Ready){
53
-                var contactDetails = component.createObject(wrapper,{"contact": contact})}
52
+                var contactDetails = component.createObject(friendstab,{"contact": contact})}
54 53
             }
55 54
         }
56 55
    }
57
-    Timer{id:selectiontimer; //weird behaviour when state set to "large" onCompleted
58
-    interval: 200; running: false; repeat: false
59
-        onTriggered: {
60 56
 
61
-            contactComponent.state="large";
62
-            var component = Qt.createComponent("qrc:/qml/contactqml/ContactDetailsComponent.qml");
63
-            if (component.status== Component.Ready){
64
-                var contactDetails = component.createObject(wrapper,{"contact": contact})}
65
-               }
66
-    }
67
-    Component.onCompleted: {
68
-        if(status=="large"){selectiontimer.start()}
69
-        else{contactComponent.state=""}
70
-    }
71
-
72
-states: [
73
-    State {
74
-        name: "large"
75
-        PropertyChanges { target: namelabel; font.pixelSize: 4*mm; x:mm; width:friendsTabView.width-4*mm; text:Qt.atob(contact.name)+" (@"+contact.screen_name+")"}
76
-        ParentChange{target:contactComponent;parent:root; x:mm;y:2*mm}
77
-        //PropertyChanges { target: contactComponent; z: 2; x:0;y:0}
78
-        PropertyChanges { target: wrapper; width:friendsTabView.width;height:friendsTabView.height-15*mm}
79
-        PropertyChanges { target: photoImage; width:15*mm;height:15*mm;x:mm;y:mm }
80
-PropertyChanges { target: contactComponent.GridView.view; interactive:false}
81
-
82
-        }
83
-]
84 57
 }

+ 56
- 1
source-android/qml/contactqml/ContactDetailsComponent.qml View File

@@ -2,6 +2,44 @@ import QtQuick 2.0
2 2
 import QtQuick.Controls 1.3
3 3
 import "qrc:/qml/genericqml"
4 4
 
5
+Item {
6
+id: contactLargeComponent
7
+x:mm
8
+y:mm
9
+property var contact:{}
10
+property var createdAtDate: new Date(contact.created_at)
11
+property string connectUrl: (contact.network!=="dfrn")||(contact.isFriend==1)?"":( "<a href='"+contact.url.replace("profile","dfrn_request") +"'>"+qsTr("Connect")+"</a><br>")
12
+
13
+Rectangle {
14
+    id: wrapper
15
+
16
+    width:friendsTabView.width;
17
+    height:friendsTabView.height-15*mm
18
+    border.color:  "grey"
19
+    color:"white"
20
+    Image {
21
+        id: photoImage
22
+        x:mm
23
+        y:mm
24
+        width: 15*mm
25
+        height:15*mm
26
+        source:(contact.profile_image!="")? "file://"+contact.profile_image : contact.profile_image_url
27
+        onStatusChanged: if (photoImage.status == Image.Error) {source="qrc:/images/defaultcontact.jpg"}
28
+        }
29
+
30
+    Label {
31
+        id: namelabel
32
+        x: mm
33
+        width:friendsTabView.width-4*mm
34
+        height: 3*mm
35
+        text:Qt.atob(contact.name)+" (@"+contact.screen_name+")"
36
+        elide:Text.ElideRight
37
+        anchors.topMargin: 0
38
+        anchors.left: photoImage.left
39
+        color: "#303030"
40
+        font.pixelSize: 4*mm
41
+        anchors.top: photoImage.bottom
42
+        }
5 43
 Rectangle{
6 44
    id: detailsrectangle
7 45
    anchors.top: namelabel.bottom
@@ -69,10 +107,27 @@ Rectangle{
69 107
                 }
70 108
             }
71 109
 
110
+
111
+            BlueButton{
112
+                id:eventbutton
113
+                visible:(contact.network=="dfrn")
114
+                text:"\uf073"
115
+                onClicked:{
116
+                    root.currentIndex=3;
117
+                    calendartab.active=true;
118
+                    calendartab.calendartabstatus="Friend"
119
+                    root.eventSignal(contact.url);
120
+                }
121
+            }
122
+
72 123
             BlueButton{
73 124
                 id: closeButton
74 125
                 text: "\uf057" //"close"
75
-                onClicked:{detailsrectangle.destroy();contactComponent.state="";friendsTabView.contactSignal}
126
+                onClicked:{contactLargeComponent.destroy();
127
+                    //contactComponent.state="";
128
+                    friendsTabView.contactSignal}
76 129
             }
77 130
         }
78 131
     }
132
+}
133
+}

+ 91
- 0
source-android/qml/contactqml/ContactDetailsComponentOld.qml View File

@@ -0,0 +1,91 @@
1
+import QtQuick 2.0
2
+import QtQuick.Controls 1.3
3
+import "qrc:/qml/genericqml"
4
+
5
+Rectangle{
6
+   id: detailsrectangle
7
+   anchors.top: namelabel.bottom
8
+   anchors.topMargin: 2*mm
9
+
10
+   ScrollView{
11
+       horizontalScrollBarPolicy:Qt.ScrollBarAlwaysOff
12
+       frameVisible: true
13
+       id:namelabelflickable
14
+       width: root.width-10*mm
15
+       height:friendsTabView.height-45*mm
16
+       x: mm
17
+       clip:true
18
+       Text{
19
+           id:namelabeltext
20
+           width: namelabelflickable.width
21
+           height: implicitHeight
22
+           font.pixelSize: 3*mm
23
+           textFormat:Text.RichText
24
+           wrapMode: Text.Wrap
25
+           text:"<b>"+qsTr("Description")+": </b> "+Qt.atob(contact.description)+"<br> <b>"+qsTr("Location")+":</b> "+contact.location+"<br> <b>"+qsTr("Posts")+":</b> "+contact.statuses_count+
26
+               "<br> <b>"+qsTr("URL")+":</b> <a href='"+ contact.url+"'>"+contact.url+"</a><br>"+
27
+               connectUrl+ "<b>"+qsTr("Created at")+":</b> "+createdAtDate.toLocaleString(Qt.locale())
28
+            onLinkActivated: {
29
+              Qt.openUrlExternally(link)}
30
+            }
31
+        }
32
+
33
+        Row{
34
+            anchors.top: namelabelflickable.bottom
35
+            anchors.topMargin: 2*mm
36
+            x: mm
37
+            spacing:4
38
+
39
+            BlueButton{
40
+                id:photobutton
41
+                text: "\uf03e" // "Photos"
42
+                visible:(contact.network=="dfrn")
43
+                onClicked:{
44
+                    fotostab.phototabstatus="Contact";
45
+                    root.currentIndex=2;
46
+                    fotostab.active=true;
47
+                    root.fotoSignal(contact) ;
48
+                    }
49
+             }
50
+
51
+            BlueButton{
52
+                id:messagebutton
53
+                text: "\uf0e6" //"Messages"
54
+                onClicked:{
55
+                    root.currentIndex=0;
56
+                    newstab.active=true;
57
+                    root.messageSignal(contact.id) ;
58
+                }
59
+            }
60
+
61
+            BlueButton{
62
+                id:dmbutton
63
+                visible: (contact.following=="true")
64
+                text: "\uf040" //"DM"
65
+                onClicked:{
66
+                    root.currentIndex=0;
67
+                    newstab.active=true;
68
+                    root.directmessageSignal(contact.screen_name);
69
+                }
70
+            }
71
+
72
+
73
+            BlueButton{
74
+                id:eventbutton
75
+                visible:(contact.network=="dfrn")
76
+                text:"\uf073"
77
+                onClicked:{
78
+                    root.currentIndex=3;
79
+                    calendartab.active=true;
80
+                    calendartab.calendartabstatus="Friend"
81
+                    root.eventSignal(contact.url);
82
+                }
83
+            }
84
+
85
+            BlueButton{
86
+                id: closeButton
87
+                text: "\uf057" //"close"
88
+                onClicked:{detailsrectangle.destroy();contactComponent.state="";friendsTabView.contactSignal}
89
+            }
90
+        }
91
+    }

+ 15
- 22
source-android/qml/contactqml/FriendsTab.qml View File

@@ -11,12 +11,13 @@ Rectangle {
11 11
     color: "white"
12 12
 
13 13
     function showContactdetails(contact){
14
+        var component = Qt.createComponent("qrc:/qml/contactqml/ContactDetailsComponent.qml");
14 15
         if(contact.isFriend){
15 16
             friendsTabView.currentIndex=0;
16
-            friendsTabView.contactsSignal(contact)
17
+           var contactDetails = component.createObject(friendstab,{"contact": contact})
17 18
         }
18 19
         else{friendsTabView.currentIndex=1;
19
-            friendsTabView.contactsSignal(contact)
20
+           var contactDetails = component.createObject(friendstab,{"contact": contact})
20 21
         }
21 22
     }
22 23
     TabView{
@@ -30,7 +31,7 @@ Rectangle {
30 31
         signal contactsSignal(var contact)
31 32
         signal groupsSignal(var username)
32 33
         onCurrentIndexChanged:{
33
-            if (currentIndex==0){//print("currentindex 0");
34
+            if (currentIndex==0){
34 35
                 contactsSignal("")
35 36
             }
36 37
             else if (currentIndex==1){
@@ -60,18 +61,14 @@ Rectangle {
60 61
         title: qsTr("Friends")
61 62
         Rectangle{
62 63
             id: friendsGridTab
63
-            function makebig(friendindex){print("friendindex"+friendindex);if (friendindex){friendsModel.set(friendindex,{"status":"large"})}}
64
-            function showFriends(contact,callback){//print("contact"+JSON.stringify(contact));
64
+            function showFriends(contact){
65 65
                 try {friendsModel.clear()} catch(e){print(e)};
66
-                var friendindex;
67 66
                 Helperjs.readData(db,"contacts",root.login.username,function(friendsobject){
68 67
                     for (var i=0;i<friendsobject.length;i++){
69
-                        var status="";
70
-                        if(Helperjs.getCount(db,login,"contacts","screen_name",friendsobject[i].screen_name)>1){
68
+                         if(Helperjs.getCount(db,login,"contacts","screen_name",friendsobject[i].screen_name)>1){
71 69
                             friendsobject[i].screen_name=friendsobject[i].screen_name+"+"+friendsobject[i].cid
72 70
                         }
73
-                        if(contact){if (contact.cid==friendsobject[i].cid){status="large"}}
74
-                        friendsModel.append({"contact":friendsobject[i],"status":status});
71
+                        friendsModel.append({"contact":friendsobject[i]});
75 72
                     }
76 73
 
77 74
 
@@ -113,12 +110,11 @@ Rectangle {
113 110
               clip: true
114 111
               cellHeight: 16*mm
115 112
               cellWidth: 17*mm
116
-              add: Transition {
117
-                       NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
118
-                   }
113
+              //add: Transition {
114
+               //        NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
115
+               //    }
119 116
               model: friendsModel
120 117
               delegate: ContactComponent { }
121
-              Component.onCompleted: positionViewAtBeginning()
122 118
              }
123 119
 
124 120
             ListModel{id:friendsModel}
@@ -132,7 +128,7 @@ Rectangle {
132 128
       }
133 129
 
134 130
       Tab{
135
-        title: qsTr("Other Contacts")
131
+        title: qsTr("Contacts")
136 132
 
137 133
         Rectangle{
138 134
         id: contactsGridTab
@@ -140,9 +136,7 @@ Rectangle {
140 136
                 try {contactsModel.clear()} catch(e){print(e)};
141 137
                 Helperjs.readData(db, "contacts",root.login.username,function(contactsobject){
142 138
                 for (var j=0;j<contactsobject.length;j++){
143
-                    var status="";
144
-                    if(contact){if (contact.id==contactsobject[j].id){status="large"}}
145
-                    contactsModel.append({"contact":contactsobject[j],"status":status});
139
+                     contactsModel.append({"contact":contactsobject[j]});
146 140
                     }
147 141
                 },"isFriend",0,"screen_name ASC");
148 142
             }
@@ -156,12 +150,11 @@ Rectangle {
156 150
                  clip: true
157 151
                  cellHeight: 16*mm
158 152
                  cellWidth: 17*mm
159
-                 add: Transition {
160
-                          NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
161
-                      }
153
+                 //add: Transition {
154
+                  //        NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
155
+                  //    }
162 156
                  model: contactsModel
163 157
                  delegate: ContactComponent { }
164
-                 Component.onCompleted: positionViewAtBeginning()
165 158
                  }
166 159
 
167 160
              ListModel{id: contactsModel}

+ 18
- 6
source-android/qml/friendiqa.qml View File

@@ -24,6 +24,7 @@ TabView{
24 24
     signal newsSignal(var news)
25 25
     signal friendsSignal(var username)
26 26
     signal contactdetailsSignal(var contact)
27
+    signal eventSignal(var contact)
27 28
     //currentIndex: (login=="")? 3:0
28 29
 
29 30
     property var news:[]
@@ -32,13 +33,13 @@ TabView{
32 33
     property string contactLoadType: ""
33 34
 
34 35
     onLoginChanged:{
35
-        if(login==""){root.currentIndex=3}
36
+        if(login==""){root.currentIndex=4}
36 37
         else{
37 38
             newstab.newstabstatus=login.newsViewType;
38 39
             Newsjs.getCurrentContacts(login,db,function(contacts){
39 40
                 contactlist=contacts})}
40 41
     }
41
-    onNewContactsChanged:{
42
+    onNewContactsChanged:{//print(JSON.stringify(newContacts));
42 43
         if(newContacts.length>0){// download first contact image and update db
43 44
             Service.updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])}
44 45
         else if (contactLoadType!=""){
@@ -49,6 +50,7 @@ TabView{
49 50
     }
50 51
 
51 52
     onCurrentContactChanged:{// download next contact image after photoplaceholder is finished saving and update db
53
+
52 54
         if(currentContact<newContacts.length){
53 55
                     Service.updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])}
54 56
         else if (contactLoadType!=""){
@@ -96,10 +98,12 @@ TabView{
96 98
                     if(login.newsViewType=="Timeline"){Newsjs.newsfromdb(db,login.username,function(dbnews){
97 99
                         newsSignal(dbnews)
98 100
                     })}
99
-                    else{Newsjs.chatsfromdb(db,login.username,function(dbnews){
101
+                    else{
102
+                         Newsjs.chatsfromdb(db,login.username,function(dbnews){
100 103
                         newsSignal(dbnews)
101 104
                     })}
102 105
                 }
106
+                else if (newstab.conversation.length>0){newstab.conversation=[]}
103 107
                 else{Service.cleanNews(root.db,function(){Qt.quit()})}
104 108
              }
105 109
          else if (currentIndex==2){fotoSignal("backButton")}
@@ -113,8 +117,8 @@ TabView{
113 117
         tab: Rectangle {
114 118
             color: styleData.selected?"sky blue":"light blue"
115 119
             border.color: "light grey"
116
-            implicitWidth: root.width/4-2*mm
117
-            implicitHeight: 4*mm
120
+            implicitWidth: root.width/5-2*mm
121
+            implicitHeight: 5*mm
118 122
             Text { id: text
119 123
                 anchors.centerIn: parent
120 124
                 text: styleData.title
@@ -145,9 +149,17 @@ TabView{
145 149
         property string phototabstatus:"Images"
146 150
         source: (root.currentIndex==2)?"qrc:/qml/photoqml/PhotoTab.qml":""
147 151
     }
152
+    Tab{
153
+        title: "\uf073"
154
+        id: calendartab
155
+        property string calendartabstatus:"Events"
156
+        source: (root.currentIndex==3)?"qrc:/qml/calendarqml/CalendarTab.qml":""
157
+    }
158
+
159
+
148 160
     Tab{
149 161
         title:"\uf085"
150 162
         id: configtab
151
-        source: (root.currentIndex==3)?"qrc:/qml/configqml/ConfigTab.qml":""
163
+        source: (root.currentIndex==4)?"qrc:/qml/configqml/ConfigTab.qml":""
152 164
     }
153 165
 }

+ 88
- 15
source-android/qml/newsqml/Conversation.qml View File

@@ -1,34 +1,106 @@
1
-// ConversationStack with buttons
1
+// ConversationView with button
2 2
 import QtQuick 2.0
3 3
 import "qrc:/js/helper.js" as Helperjs
4 4
 import "qrc:/qml/genericqml"
5 5
 
6 6
 Rectangle {
7
-    id:conversationStack
7
+    id:conversationList
8 8
     property var news
9 9
     y:1
10
-        color: "white"
11
-        width:root.width-2*mm
12
-        height:root.height-8*mm
10
+    z:2
11
+    color: "white"
12
+    border.color: "grey"
13
+    width:root.width-5*mm
14
+    height: conversationView.height+10*mm
15
+    Connections{
16
+        target:newstab
17
+        onConversationChanged:{
18
+                if(newstab.conversation.length==0){
19
+                    newsView.positionViewAtIndex(newsStack.conversationIndex,ListView.Beginning);
20
+                    conversationList.destroy(); conversationsymbol.color="grey"
21
+                }
22
+        }
23
+    }
13 24
 
14 25
    ListView {
15 26
           id: conversationView
16 27
           x:3*mm
17 28
           y:8*mm
18
-          width: conversationStack.width-4*mm
19
-          height: conversationStack.height-10*mm
29
+          width: conversationList.width-4*mm
30
+          height: contentHeight
20 31
           clip: true
21 32
           spacing: 0
33
+          footer: footerReply
22 34
           model: conversationModel
23 35
           delegate: Newsitem{}
24 36
           }
25 37
 
26
-       ListModel{id: conversationModel}
38
+   Component {  id:footerReply
39
+       Rectangle{
40
+           border.color: "#EEEEEE"
41
+           border.width: 1
42
+           color:"lightgrey"
43
+           width:conversationView.width
44
+           height:Math.max(replyText.contentHeight+2*mm,6*mm)
45
+           Rectangle{
46
+               color: "white"
47
+               radius:0.5*mm
48
+               anchors.left: parent.left
49
+               anchors.leftMargin:mm
50
+               anchors.top:parent.top
51
+               anchors.topMargin: 0.5*mm
52
+               width:parent.width-12*mm
53
+               height:Math.max( replyText.contentHeight,5*mm)
27 54
 
28
-       WorkerScript {
29
-              id: conversationWorker
30
-              source: "qrc:/js/newsworker.js"
31
-          }
55
+               TextInput {
56
+                id: replyText
57
+                font.pixelSize: 3*mm
58
+                wrapMode: Text.Wrap
59
+                anchors.fill: parent
60
+                selectByMouse: true
61
+                }
62
+           }
63
+
64
+            BlueButton {
65
+                id: sendButton
66
+                text: "\uf1d9"
67
+                anchors.right: parent.right
68
+                anchors.rightMargin:mm
69
+                anchors.top:parent.top
70
+                anchors.topMargin: 0.5*mm
71
+                color:"white"
72
+                onClicked: { try{
73
+                   var body=replyText.getText(0,replyText.length);
74
+                   newsBusy.running=true;
75
+                        replyText.text=""
76
+                   xhr.clearParams();
77
+                   xhr.setLogin(login.username+":"+Qt.atob(login.password));
78
+                   if (conversationModel.get(0).newsitemobject.messagetype==0){
79
+                       xhr.setParam("source", "Friendiqa");
80
+                       xhr.url= login.server + "/api/statuses/update.json";
81
+                       xhr.setParam("status", body);
82
+                       xhr.setParam("in_reply_to_status_id", conversationModel.get(conversationModel.count-1).newsitemobject.status_id)}
83
+                   else {xhr.url= login.server + "/api/direct_messages/new.json";
84
+                       xhr.setParam("text", body);
85
+                       xhr.setParam("screen_name",conversationModel.get(conversationModel.count-1).newsitemobject.screen_name);
86
+                       xhr.setParam("replyto", conversationModel.get(conversationModel.count-1).newsitemobject.status_id)
87
+                   }
88
+                   xhr.post();
89
+                  //replyText.text=""
90
+                   } catch(e){Helperjs.showMessage("Error",e.toString(),root)}
91
+               }
92
+           }
93
+       }
94
+   }
95
+
96
+
97
+
98
+    ListModel{id: conversationModel}
99
+
100
+    WorkerScript {
101
+        id: conversationWorker
102
+        source: "qrc:/js/newsworker.js"
103
+    }
32 104
 
33 105
     BlueButton {
34 106
             id: closeButton
@@ -37,10 +109,11 @@ Rectangle {
37 109
             anchors.topMargin: 1*mm
38 110
             anchors.right: parent.right
39 111
             anchors.rightMargin: 1*mm
40
-            text: "\uf057"//  qsTr("Close")
112
+            text: "\uf057"
41 113
             onClicked: {
42
-                newstab.newstabstatus=login.newsViewType;
43
-                newsStack.pop()
114
+                newsView.positionViewAtIndex(newsStack.conversationIndex,ListView.Beginning);
115
+                conversationList.destroy();
116
+                conversationsymbol.color="grey"
44 117
             }
45 118
     }
46 119
 

+ 4
- 4
source-android/qml/newsqml/ImageDialog.qml View File

@@ -42,12 +42,11 @@ Rectangle{
42 42
           clip: true
43 43
           model: imageModel
44 44
           delegate: imageItem
45
-
46 45
      }
47 46
 
48 47
      FolderListModel{
49 48
          id: imageModel
50
-         nameFilters: ["*.png", "*.jpg",".jpeg","*.JPG"]
49
+         nameFilters: ["*.png", "*.jpg",".jpeg","*.JPG","*.gif"]
51 50
          sortField: FolderListModel.Time
52 51
          sortReversed:false
53 52
          showDotAndDotDot: true
@@ -111,8 +110,9 @@ Rectangle{
111 110
                             directory=fileURL
112 111
                         }
113 112
                         else{
114
-                            attachImageURL=fileURL;
115
-                            imageDialog.destroy()
113
+                            attachImageURLs.push(fileURL);
114
+                           attachImage(fileURL);
115
+                      imageDialog.destroy()
116 116
                         }
117 117
                     }
118 118
                 }

+ 19
- 18
source-android/qml/newsqml/MessageSend.qml View File

@@ -16,7 +16,7 @@ Flickable{
16 16
     id:messageSend
17 17
     property string parentId: ""
18 18
     property string reply_to_user:""
19
-    property string attachImageURL: "";
19
+    property var attachImageURLs: [];
20 20
     property int directmessage: 0;
21 21
     property var contacts: []
22 22
     property var groups: []
@@ -25,11 +25,13 @@ Flickable{
25 25
     property var group_allow:login.permissions[2]
26 26
     property var group_deny:login.permissions[3]
27 27
 
28
-    onAttachImageURLChanged: {if(attachImageURL!=""){
29
-            var imageAttachmentObject=Qt.createQmlObject('import QtQuick 2.0; Image {id:imageAttachment; source:"'+
30
-                attachImageURL.toString()+'"; width: 15*mm; height: 15*mm;fillMode: Image.PreserveAspectFit;MouseArea{anchors.fill:parent;onClicked:{attachImageURL="";imageAttachment.destroy()}}}',messageColumn,"attachedImage");
31
-            console.log("You chose: " + attachImageURL)
32
-        }}
28
+    function attachImage(url){
29
+    //onAttachImageURLsChanged: {if(attachImageURL!=""){
30
+            var imageAttachmentObject=Qt.createQmlObject('import QtQuick 2.0; Image {id:imageAttachment'+attachImageURLs.length+'; source:"'+
31
+                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");
32
+            console.log("You chose: " + url)
33
+        }
34
+
33 35
     function statusUpdate(title,status,in_reply_to_status_id,attachImageURL) {
34 36
         xhr.url= login.server + "/api/statuses/update.json";
35 37
         xhr.setLogin(login.username+":"+Qt.atob(login.password));
@@ -42,7 +44,7 @@ Flickable{
42 44
         if (group_deny.length>0) {xhr.setParam("group_deny",  Helperjs.cleanArray(group_deny))};
43 45
         if (contact_allow.length>0) {xhr.setParam("contact_allow", Helperjs.cleanArray(contact_allow))};
44 46
         if (contact_deny.length>0) {xhr.setParam("contact_deny",  Helperjs.cleanArray(contact_deny))};
45
-        if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )};
47
+        if (attachImageURL.length>0) {for (var image in attachImageURL){xhr.setImageFileParam("media", attachImageURL[image] )}};
46 48
         xhr.post();
47 49
         }
48 50
 
@@ -122,12 +124,11 @@ Flickable{
122 124
                         }
123 125
                     }
124 126
 
125
-
126 127
           Row{
127 128
               spacing:2
128 129
               BlueButton{id:permButton
129 130
                   visible: (directmessage==1)?false:true
130
-                  text: ((contact_allow.length==0)&&(contact_deny.length==0)&&(group_allow.length==0)&&(group_deny.length==0))?"\uf09c":"\uf023"//qsTr("Permissions")
131
+                  text: ((contact_allow.length==0)&&(contact_deny.length==0)&&(group_allow.length==0)&&(group_deny.length==0))?"\uf09c":"\uf023"
131 132
                   onClicked: {
132 133
                      var component = Qt.createComponent("qrc:/qml/newsqml/PermissionDialog.qml");
133 134
                      var permissions = component.createObject(messageColumn);
@@ -137,14 +138,14 @@ Flickable{
137 138
                   text: "\uf0c6"
138 139
                   visible:(directmessage==0)
139 140
                   onClicked: {
140
-                    if (attachImageURL!=""){
141
-                        Helperjs.showMessage( qsTr("Error"),qsTr("Only one attachment. Remove other attachment first!"), messageColumn)}
142
-                    else{print(filesystem.homePath);
143
-                    var defaultDirectory="file://"+osSettings.attachImageDir;//"file:///storage/emif.open()
144
-                        print(defaultDirectory);
145
-                        var component = Qt.createComponent("qrc:/qml/newsqml/ImageDialog.qml");
146
-                        var imagedialog = component.createObject(messageSend,{"directory": defaultDirectory});
147
-                    }
141
+                      if (attachImageURLs.length>0){//Server currently accepts only one attachment
142
+                          Helperjs.showMessage( qsTr("Error"),qsTr("Only one attachment supported at the moment.\n Remove other attachment first!"), messageColumn)
143
+                      }
144
+                      else{
145
+                          var defaultDirectory="file://"+osSettings.attachImageDir;
146
+                          var component = Qt.createComponent("qrc:/qml/newsqml/ImageDialog.qml");
147
+                          var imagedialog = component.createObject(messageSend,{"directory": defaultDirectory});
148
+                      }
148 149
                   }
149 150
                }
150 151
                BlueButton{
@@ -188,7 +189,7 @@ Flickable{
188 189
                        var title=titleField.text.replace("\"","\'");
189 190
                        var body=bodyField.getText(0,bodyField.length);
190 191
                        if (directmessage==0){
191
-                           statusUpdate(title,body,messageSend.parentId,attachImageURL.toString())}
192
+                           statusUpdate(title,body,messageSend.parentId,attachImageURLs)}
192 193
                        else {dmUpdate(title,body,"",messageSend.reply_to_user) }
193 194
                        newstab.newstabstatus=login.newsViewType; newsStack.pop()
194 195
                     }

+ 53
- 117
source-android/qml/newsqml/NewsTab.qml View File

@@ -13,23 +13,13 @@ Item {
13 13
         }
14 14
     }
15 15
 
16
-    Connections{
17
-        target:newstab
18
-        onConversationChanged:{
19
-            newsBusy.running=false;
20
-            newstab.newstabstatus="Conversation";
21
-            //newsStack.push({item:"qrc:/qml/newsqml/Conversation.qml",properties:{"news": conversation}})
22
-         showNews(conversation);
23
-        }
24
-    }
25
-
26 16
     Connections{
27 17
         target:root
28 18
         onCurrentContactChanged:{
29 19
             if (root.newContacts.length>0){
30 20
                 if(root.currentContact<root.newContacts.length){
31 21
                 downloadNotice.text= qsTr("Download profile image for ")+ root.newContacts[root.currentContact].name;
32
-                print(root.newContacts[root.currentContact].name)
22
+                //print(root.newContacts[root.currentContact].name)
33 23
                 }
34 24
             }else{downloadNotice.text=""}
35 25
         }
@@ -62,23 +52,19 @@ Item {
62 52
        newsWorker.sendMessage(msg);
63 53
     }
64 54
 
65
-    function showConversation(timelineIndex,newsitemobject){
66
-
55
+    function showConversation(conversationIndex,newsitemobject){
67 56
         newsBusy.running=true;
68 57
         root.contactLoadType="conversation";
69
-       newsStack.timelineIndex= timelineIndex;
70
-       if(newsitemobject.messagetype==0){
71
-           Newsjs.requestConversation(root.login,db,newsitemobject.status_id,root.contactlist,root,function(ns,nc){
58
+        newsStack.conversationIndex= conversationIndex;
59
+        if(newsitemobject.messagetype==0){
60
+            Newsjs.requestConversation(root.login,db,newsitemobject.status_id,root.contactlist,root,function(ns,nc){
72 61
             root.news=ns;root.newContacts=nc;root.currentContact=0;
73 62
         })}
74
-       else{Newsjs.conversationfromdb(root.db,root.login.username,newsitemobject.statusnet_conversation_id, function(newsarray){
75
-           root.news=newsarray;root.newContacts=[];root.currentContact=1;
76
-       })}
63
+        else{Newsjs.conversationfromdb(root.db,root.login.username,newsitemobject.statusnet_conversation_id, function(newsarray){
64
+            root.news=newsarray;root.newContacts=[];root.currentContact=1;
65
+        })}
77 66
     }
78 67
 
79
-
80
-
81
-
82 68
     function onFriendsMessages(friend){
83 69
         newstab.newstabstatus="Contact"
84 70
        Newsjs.newsfromdb(db,root.login.username, function(dbnews){showNews(dbnews)},friend)
@@ -92,14 +78,11 @@ Item {
92 78
    StackView{
93 79
        id: newsStack
94 80
        anchors.fill:parent
95
-       property int timelineIndex: 0
96
-       onTimelineIndexChanged:print("timelineindex:"+ timelineIndex)
81
+       property int conversationIndex: 0
97 82
 
98
-   initialItem:Rectangle {
83
+       initialItem:Rectangle {
99 84
         y:1
100 85
         color: "white"
101
-        width:root.width-2*mm
102
-        height:root.height-8*mm
103 86
 
104 87
         BlueButton{
105 88
             id:newstabstatusButton
@@ -116,26 +99,27 @@ Item {
116 99
            anchors.right: parent.right
117 100
 
118 101
            BlueButton {
119
-            id: newMessageButton
120
-            width:10*mm
121
-            text: "\uf040"
122
-            onClicked: {
123
-               var groups=[];
124
-                Helperjs.readData(root.db,"groups",root.login.username,function(groupobject){
125
-                   groups=groupobject});
126
-                newstab.newstabstatus="SendMessage";
127
-                Helperjs.readData(root.db,"contacts",root.login.username,function(friends){
128
-                   newsStack.push({item:"qrc:/qml/newsqml/MessageSend.qml",properties:{"contacts": friends,"login":root.login}})
129
-               },"isFriend",1);
130
-            }
131
-        }
132
-        BlueButton {
133
-            id: quitButton
134
-            width:10*mm
135
-            text: "\uf08b"
136
-            onClicked: {Service.cleanNews(root.db,function(){Qt.quit() })}
137
-        }
138
-        BlueButton {
102
+               id: newMessageButton
103
+               width:10*mm
104
+               text: "\uf040"
105
+               onClicked: {
106
+                   var groups=[];
107
+                   Helperjs.readData(root.db,"groups",root.login.username,function(groupobject){
108
+                       groups=groupobject
109
+                   });
110
+                   newstab.newstabstatus="SendMessage";
111
+                   Helperjs.readData(root.db,"contacts",root.login.username,function(friends){
112
+                      newsStack.push({item:"qrc:/qml/newsqml/MessageSend.qml",properties:{"contacts": friends,"login":root.login}})
113
+                   },"isFriend",1);
114
+               }
115
+           }
116
+           BlueButton {
117
+             id: quitButton
118
+             width:10*mm
119
+             text: "\uf08b"
120
+             onClicked: {Service.cleanNews(root.db,function(){Qt.quit() })}
121
+           }
122
+           BlueButton {
139 123
             id: update
140 124
             text: "\uf021"
141 125
             onClicked: {
@@ -176,7 +160,7 @@ Item {
176 160
                           var msg = {'currentTime': currentTime, 'model': newsModel,'news':news,'appendnews':true};
177 161
                           newsWorker.sendMessage(msg);
178 162
                           },false,lastnews_id)}
179
-                      if(newstab.newstabstatus=="Tree"){
163
+                      if(newstab.newstabstatus=="Conversations"){
180 164
                             var lastnews_id=newsModel.get(newsModel.count-1).newsitemobject.created_at;
181 165
                             Newsjs.chatsfromdb(root.db,root.login.username, function(news){
182 166
                           var msg = {'currentTime': currentTime, 'model': newsModel,'news':news,'appendnews':true};
@@ -191,83 +175,35 @@ Item {
191 175
                   }
192 176
         }
193 177
 
194
-        Component {  id:footerReply
195
-            Rectangle{
196
-                border.color: "#EEEEEE"
197
-                border.width: 1
198
-                color:"lightgrey"
199
-                width:newsView.width
200
-                height:Math.max(replyText.contentHeight+2*mm,6*mm)
201
-                Rectangle{
202
-                    color: "white"
203
-                    radius:0.5*mm
204
-                    anchors.left: parent.left
205
-                    anchors.leftMargin:mm
206
-                    anchors.top:parent.top
207
-                    anchors.topMargin: 0.5*mm
208
-                    width:parent.width-12*mm
209
-                    height:Math.max( replyText.contentHeight,5*mm)
210
-
211
-                     TextInput {
212
-                     id: replyText
213
-                     font.pixelSize: 3*mm
214
-                     wrapMode: Text.Wrap
215
-                     //width: parent.width
216
-                     anchors.fill: parent
217
-                     selectByMouse: true
218
-                     }
219
-                }
220
-
221
-                 BlueButton {
222
-                     id: sendButton
223
-                     text: "\uf1d9"
224
-                     anchors.right: parent.right
225
-                     anchors.rightMargin:mm
226
-                     anchors.top:parent.top
227
-                     anchors.topMargin: 0.5*mm
228
-                     color:"white"
229
-                     onClicked: { try{
230
-                        var body=replyText.getText(0,replyText.length);
231
-                        newsBusy.running=true;
232
-                             replyText.text=""
233
-                        xhr.clearParams();
234
-                        xhr.setLogin(login.username+":"+Qt.atob(login.password));
235
-                        if (newsModel.get(0).newsitemobject.messagetype==0){
236
-                            xhr.setParam("source", "Friendiqa");
237
-                            xhr.url= login.server + "/api/statuses/update.json";
238
-                            xhr.setParam("status", body);
239
-                            xhr.setParam("in_reply_to_status_id", newsModel.get(newsModel.count-1).newsitemobject.status_id)}
240
-                        else {xhr.url= login.server + "/api/direct_messages/new.json";
241
-                            xhr.setParam("text", body);
242
-                            xhr.setParam("screen_name",newsModel.get(newsModel.count-1).newsitemobject.screen_name);
243
-                            xhr.setParam("replyto", newsModel.get(newsModel.count-1).newsitemobject.status_id)
244
-                        }
245
-                        xhr.post();
246
-                       //replyText.text=""
247
-                        } catch(e){Helperjs.showMessage("Error",e.toString(),root)}
248
-                    }
249
-                }
250
-            }
251
-        }
252 178
 
253 179
         ListView {
254 180
           id: newsView
255 181
           anchors.fill: parent
256
-          anchors.topMargin: 8*root.mm
182
+          anchors.topMargin: 7*root.mm
257 183
           anchors.leftMargin: 3*root.mm; anchors.rightMargin: root.mm
258 184
           anchors.bottomMargin: 1*root.mm
259 185
           clip: true
260 186
           spacing: 0
261
-          footer: (newstab.newstabstatus=="Conversation")?footerReply:footerComponent
187
+          footer: footerComponent
262 188
           model: newsModel
263 189
           delegate: Newsitem{}
264
-          Component.onCompleted: {//print(newstab.newstabstatus);
265
-              if(newstab.newstabstatus!="Conversation"){
266
-                  positionViewAtIndex(newsStack.timelineIndex-1, ListView.Beginning)}
267
-          else {positionViewAtBeginning();
268
-               newsStack.timelineIndex=0
269
-}}
270
-          }
190
+          //onContentYChanged:{if(contentY<-15*mm&&contentY>(-15*mm-1)){print("refreshing");
191
+          onDragEnded:{if(contentY<-8*mm){//print("refreshing");
192
+                  newsBusy.running=true;
193
+                  newstab.newstabstatus=login.newsViewType;
194
+                  root.contactLoadType="news";
195
+                  var onlynew=true;
196
+                  Newsjs.getFriendsTimeline(login,db,contactlist,onlynew,newstab,function(ns,nc){
197
+                      root.news=ns;root.newContacts=nc;root.currentContact=0;
198
+                      if (ns.length==0){// update last 20 existing news for changes and likes
199
+                          onlynew=false;
200
+                          Newsjs.getFriendsTimeline(login,db,contactlist,onlynew,newstab,function(rns,rnc){
201
+                              root.contactLoadType="news";
202
+                              root.news=rns;root.newContacts=rnc;root.currentContact=0})
203
+                      }
204
+                  })
205
+              }}
206
+        }
271 207
 
272 208
        ListModel{id: newsModel}
273 209
 
@@ -331,10 +267,10 @@ Item {
331 267
            }
332 268
 
333 269
            MenuItem {
334
-                text: qsTr("Tree")
270
+                text: qsTr("Conversations")
335 271
                 onTriggered:{
336 272
                     newsModel.clear();
337
-                    newstab.newstabstatus="Tree";
273
+                    newstab.newstabstatus="Conversations";
338 274
                     Newsjs.chatsfromdb(db,root.login.username,function(news){showNews(news)})
339 275
                 }
340 276
            }

+ 81
- 31
source-android/qml/newsqml/Newsitem.qml View File

@@ -7,9 +7,23 @@ import "qrc:/js/helper.js" as Helperjs
7 7
 
8 8
 Item {
9 9
     id: newsitem
10
-    width: newsView.width
11
-    height:Math.max((itemMessage.height+topFlow.height+friendicaActivities.height+4*mm),profileImage.height+user_name.height+mm)
12
-    
10
+    width: parent.width
11
+    height:toprow.height+friendicaActivities.height+controlrow.height+1//Math.max((itemMessage.height+topFlow.height+friendicaActivities.height+4*mm),profileImage.height+user_name.height+mm)
12
+
13
+    Connections{
14
+        target:newstab
15
+        onConversationChanged:{
16
+            newsBusy.running=false;
17
+            if(index==newsStack.conversationIndex){
18
+               if(newstab.conversation.length>0){
19
+                   var component = Qt.createComponent("qrc:/qml/newsqml/Conversation.qml");
20
+                   var conversation = component.createObject(friendicaActivities,{"news":newstab.conversation});
21
+               }
22
+               else{conversationsymbol.color="grey"}
23
+            }
24
+        }
25
+    }
26
+
13 27
     property string attending: ""
14 28
     onAttendingChanged: {attendLabel.visible=true;
15 29
             attendLabel.text= qsTr("attending: ")+ qsTr(attending)}
@@ -19,9 +33,7 @@ Item {
19 33
     function showActivityContacts(contacts){
20 34
         var component = Qt.createComponent("qrc:/qml/newsqml/FriendicaActivities.qml");
21 35
         var imagedialog = component.createObject(friendicaActivities,{"activitymembers": contacts});
22
-
23 36
     }
24
-
25 37
     Rectangle{width:newsitem.width; height: 1; anchors.bottom: newsitem.bottom; color:"light grey"}
26 38
 
27 39
     Rectangle{
@@ -29,7 +41,8 @@ Item {
29 41
     height:newsitem.height-1
30 42
     color:  (newsitemobject.messagetype==1)?"#ffe6e6" : "white"
31 43
 
32
-    Column {
44
+    Row{id:toprow
45
+        Column {
33 46
         id: authorcolumn
34 47
         width: 8*mm
35 48
 
@@ -41,7 +54,7 @@ Item {
41 54
             height: 7*mm
42 55
             MouseArea{
43 56
                 anchors.fill: parent
44
-                onClicked:{print(root.currentIndex);
57
+                onClicked:{
45 58
                     try{root.currentIndex=1;
46 59
                     friendstab.active=true;
47 60
                     root.contactdetailsSignal(newsitemobject.user)} catch (e){Helperjs.showMessage("Error",e,root)}
@@ -61,7 +74,7 @@ Item {
61 74
     Column {
62 75
         id:newscolumn
63 76
         width: newsitem.width-8*mm
64
-        anchors.left: authorcolumn.right
77
+        //anchors.left: authorcolumn.right
65 78
 
66 79
         Flow{
67 80
             id:topFlow
@@ -92,7 +105,7 @@ Item {
92 105
 
93 106
             Label {
94 107
                 id:newscountLabel
95
-                visible:((newstabstatus=="Tree")&&(newsitemobject.newscount>1))?true:false
108
+                visible:((newstabstatus=="Conversations")&&(newsitemobject.newscount>1))?true:false
96 109
                 color: "grey"
97 110
                 height:3.5*mm
98 111
                 font.pixelSize: 1.5*mm
@@ -117,12 +130,25 @@ Item {
117 130
             wrapMode: Text.Wrap
118 131
             onLinkActivated:{ 
119 132
                Qt.openUrlExternally(link)}
133
+            Component.onCompleted:{
134
+                if (newsitemobject.attachmentList.length>0){
135
+                    for(var attachments in newsitemobject.attachmentList){//   (newsitemobject.attachmentList[attachments].url);
136
+                        var attachcomponent = Qt.createQmlObject('import QtQuick 2.0; '+
137
+                        'AnimatedImage {id:gif;source: "'+newsitemobject.attachmentList[attachments].url+
138
+                        '";onStatusChanged: playing = (status == AnimatedImage.Ready)}',
139
+                        friendicaActivities,"Attachment"+attachments);
140
+                     }
141
+                }
142
+            }
120 143
         }
121
-
122
-   Flow{
144
+    }
145
+    }
146
+    Flow{
123 147
        id:friendicaActivities
148
+       anchors.top:toprow.bottom
124 149
        width:parent.width
125 150
        spacing:mm
151
+
126 152
        Label{color: "grey"
127 153
              font.pixelSize: 1.5*mm
128 154
              text: friendica_activities.likeText
@@ -162,11 +188,22 @@ Item {
162 188
                  onClicked: { showActivityContacts(newsitemobject.attendmaybe)}
163 189
              }
164 190
        }
191
+       Label{
192
+           id:attendLabel
193
+           //visible: false
194
+           color: "grey"
195
+           height:3.5*mm
196
+           font.pixelSize: 1.5*mm
197
+           horizontalAlignment: Label.AlignRight
198
+           text: (friendica_activities.self.attending)?(qsTr("Attending: ")+ qsTr(friendica_activities.self.attending)):""
199
+       }
165 200
    }
166
-   Row{
201
+   Row{id:controlrow
202
+       anchors.top:friendicaActivities.bottom
203
+
167 204
        CheckBox{
168 205
            id:likeCheckbox
169
-           height:3*mm
206
+           //height:3*mm
170 207
            width:8*mm
171 208
            visible: (newsitemobject.messagetype==0)? true:false
172 209
            checked:(friendica_activities.self.liked==1)?true:false
@@ -195,7 +232,7 @@ Item {
195 232
            }
196 233
        CheckBox{
197 234
            id: dislikeCheckbox
198
-           height:3*mm
235
+           //height:3*mm
199 236
            width:8*mm
200 237
            visible: (newsitemobject.messagetype==0)? true:false
201 238
            checked: (friendica_activities.self.disliked==1)?true:false
@@ -222,10 +259,30 @@ Item {
222 259
             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}
223 260
             else {Newsjs.like(root.login,root.db,0,"dislike",newsitemobject.status_id,root); model.friendica_activities.self.disliked=1}}
224 261
            }
262
+
263
+//       Rectangle{
264
+//           width: 8*mm
265
+//           height: 3*mm
266
+//           color:"transparent"
267
+//           Text{
268
+//               id:trashsymbol
269
+//               color: "grey"
270
+//               anchors.centerIn: parent
271
+//               font.pixelSize: 2*mm
272
+//               font.bold: true
273
+//               text: "\uf1f8"
274
+//           }
275
+//           MouseArea{
276
+//               anchors.fill:parent
277
+//               onClicked: {
278
+//                   Newsjs.deleteNews(root.login,root.db,newsitemobject.status_id,newsitemobject.messagetype,root,function(reply){
279
+//                   newsModel.remove(index)})
280
+//               }}
281
+//       }
225 282
        CheckBox {
226 283
            id:favoritedCheckbox
227 284
            visible:(newsitemobject.messagetype==0)
228
-           width: 7*mm
285
+           width: 8*mm
229 286
            style: CheckBoxStyle {
230 287
            background: Rectangle {
231 288
                implicitWidth: 6*mm
@@ -251,7 +308,7 @@ Item {
251 308
            }
252 309
        }
253 310
        Rectangle{
254
-            width: 7*mm
311
+            width: 8*mm
255 312
             height: 3*mm
256 313
             color:"transparent"
257 314
             Text{
@@ -267,7 +324,7 @@ Item {
267 324
                 onClicked: {newsmenu.popup()}}
268 325
             }
269 326
        Rectangle{
270
-            width: 7*mm
327
+            width: 8*mm
271 328
             height: 3*mm
272 329
             visible:newstab.newstabstatus!="Conversation"
273 330
             color:"transparent"
@@ -281,20 +338,15 @@ Item {
281 338
             }
282 339
             MouseArea{
283 340
                 anchors.fill:parent
284
-                onClicked:       {  conversationsymbol.color="black";showConversation(index,newsitemobject)}
341
+                onClicked:{
342
+                    conversationsymbol.color="black";
343
+                    showConversation(index,newsitemobject)
344
+                }
285 345
             }
286 346
         }
287
-        Label{
288
-            id:attendLabel
289
-            //visible: false
290
-            color: "grey"
291
-            height:3.5*mm
292
-            font.pixelSize: 1.5*mm
293
-            horizontalAlignment: Label.AlignRight
294
-            text: (friendica_activities.self.attending)?(qsTr("Attending: ")+ qsTr(friendica_activities.self.attending)):""
295
-        }
347
+
296 348
     }
297
-}
349
+
298 350
     Menu {
299 351
         id:newsmenu
300 352
         MenuItem {
@@ -350,6 +402,4 @@ Item {
350 402
             }
351 403
         }
352 404
     }
353
-}
354
-}
355
-
405
+}}

+ 2
- 2
source-android/qml/newsqml/PermissionDialog.qml View File

@@ -32,7 +32,7 @@ Rectangle{
32 32
     Text{
33 33
          x:0.5*mm
34 34
          y:0.5*mm
35
-         text: "Contacts"
35
+         text: qsTr("Friends")
36 36
     }
37 37
     ListView {
38 38
           id: contactView
@@ -93,7 +93,7 @@ Rectangle{
93 93
      Text{
94 94
          x:contactView.width+2*mm
95 95
          y:0.5*mm
96
-         text: "Groups"
96
+         text: qsTr("Groups")
97 97
     }
98 98
     ListView {
99 99
           id: groupView

+ 2
- 2
source-android/qml/photoqml/PhotoTab.qml View File

@@ -105,7 +105,7 @@ Rectangle {
105 105
         anchors.topMargin: 0.5*mm
106 106
         anchors.right: parent.right
107 107
         anchors.rightMargin:2*mm
108
-        text: qsTr(phototabstatus)
108
+        text: fotostab.phototabstatus=="Images"?qsTr("Own Images"):fotostab.phototabstatus
109 109
         onClicked: {phototabmenu.popup()}
110 110
     }
111 111
     Menu {
@@ -114,7 +114,7 @@ Rectangle {
114 114
             text: qsTr("Own Images")
115 115
             onTriggered: {
116 116
                 fotostab.phototabstatus="Images";
117
-                phototabstatusButton.text=qsTr("own images");
117
+               // phototabstatusButton.text=qsTr("Own images");
118 118
                 showFotos("")}
119 119
         }
120 120
     }

BIN
source-android/translations/friendiqa-de.qm View File


+ 470
- 0
source-android/translations/friendiqa-de.ts View File

@@ -0,0 +1,470 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<!DOCTYPE TS>
3
+<TS version="2.1" language="de">
4
+<context>
5
+    <name>CalendarTab</name>
6
+    <message>
7
+        <location filename="../qml/calendarqml/CalendarTab.qml" line="73"/>
8
+        <source>Events</source>
9
+        <translation>Termine</translation>
10
+    </message>
11
+    <message>
12
+        <location filename="../qml/calendarqml/CalendarTab.qml" line="79"/>
13
+        <source>Own Calendar</source>
14
+        <translation>Eigener Kalender</translation>
15
+    </message>
16
+</context>
17
+<context>
18
+    <name>ConfigTab</name>
19
+    <message>
20
+        <location filename="../qml/configqml/ConfigTab.qml" line="32"/>
21
+        <location filename="../qml/configqml/ConfigTab.qml" line="62"/>
22
+        <location filename="../qml/configqml/ConfigTab.qml" line="288"/>
23
+        <location filename="../qml/configqml/ConfigTab.qml" line="309"/>
24
+        <source>User</source>
25
+        <translation>Name</translation>
26
+    </message>
27
+    <message>
28
+        <location filename="../qml/configqml/ConfigTab.qml" line="58"/>
29
+        <source>Server</source>
30
+        <translation>Server</translation>
31
+    </message>
32
+    <message>
33
+        <location filename="../qml/configqml/ConfigTab.qml" line="67"/>
34
+        <source>Password</source>
35
+        <translation>Passwort</translation>
36
+    </message>
37
+    <message>
38
+        <location filename="../qml/configqml/ConfigTab.qml" line="71"/>
39
+        <source>Image dir.</source>
40
+        <translation>Bildverz.</translation>
41
+    </message>
42
+    <message>
43
+        <location filename="../qml/configqml/ConfigTab.qml" line="76"/>
44
+        <source>Max. News</source>
45
+        <translation>Max. Nachr.</translation>
46
+    </message>
47
+    <message>
48
+        <location filename="../qml/configqml/ConfigTab.qml" line="80"/>
49
+        <source>News as</source>
50
+        <translation>Anzeige</translation>
51
+    </message>
52
+    <message>
53
+        <location filename="../qml/configqml/ConfigTab.qml" line="84"/>
54
+        <source>Interval (0=None)</source>
55
+        <translation>Intervall (0=keins)</translation>
56
+    </message>
57
+    <message>
58
+        <location filename="../qml/configqml/ConfigTab.qml" line="235"/>
59
+        <source>Confirm</source>
60
+        <translation>Bestätigen</translation>
61
+    </message>
62
+    <message>
63
+        <location filename="../qml/configqml/ConfigTab.qml" line="239"/>
64
+        <source>No server given! </source>
65
+        <translation>Kein Server angegeben!</translation>
66
+    </message>
67
+    <message>
68
+        <location filename="../qml/configqml/ConfigTab.qml" line="240"/>
69
+        <source>No username given! </source>
70
+        <translation>Kein Nutzername angegeben!</translation>
71
+    </message>
72
+    <message>
73
+        <location filename="../qml/configqml/ConfigTab.qml" line="241"/>
74
+        <source>No password given! </source>
75
+        <translation>Kein Passwort angegeben!</translation>
76
+    </message>
77
+    <message>
78
+        <location filename="../qml/configqml/ConfigTab.qml" line="242"/>
79
+        <source>No image directory given!</source>
80
+        <translation>Kein Verzeichnis für Bilder angegeben!</translation>
81
+    </message>
82
+    <message>
83
+        <location filename="../qml/configqml/ConfigTab.qml" line="243"/>
84
+        <source>No maximum news number given!</source>
85
+        <translation>Maximale News-Anzahl nicht angegeben!</translation>
86
+    </message>
87
+    <message>
88
+        <location filename="../qml/configqml/ConfigTab.qml" line="324"/>
89
+        <source>Timeline</source>
90
+        <translation>Chronologisch</translation>
91
+    </message>
92
+    <message>
93
+        <location filename="../qml/configqml/ConfigTab.qml" line="328"/>
94
+        <source>Conversations</source>
95
+        <translation>Unterhaltungen</translation>
96
+    </message>
97
+</context>
98
+<context>
99
+    <name>ContactComponent</name>
100
+    <message>
101
+        <location filename="../qml/contactqml/ContactComponent.qml" line="8"/>
102
+        <source>Connect</source>
103
+        <translation>Kontaktanfrage</translation>
104
+    </message>
105
+</context>
106
+<context>
107
+    <name>ContactDetailsComponent</name>
108
+    <message>
109
+        <location filename="../qml/contactqml/ContactDetailsComponent.qml" line="11"/>
110
+        <source>Connect</source>
111
+        <translation>Kontaktanfrage</translation>
112
+    </message>
113
+    <message>
114
+        <location filename="../qml/contactqml/ContactDetailsComponent.qml" line="63"/>
115
+        <source>Description</source>
116
+        <translation>Beschreibung</translation>
117
+    </message>
118
+    <message>
119
+        <location filename="../qml/contactqml/ContactDetailsComponent.qml" line="63"/>
120
+        <source>Location</source>
121
+        <translation>Ort</translation>
122
+    </message>
123
+    <message>
124
+        <location filename="../qml/contactqml/ContactDetailsComponent.qml" line="63"/>
125
+        <source>Posts</source>
126
+        <translation>Beiträge</translation>
127
+    </message>
128
+    <message>
129
+        <location filename="../qml/contactqml/ContactDetailsComponent.qml" line="64"/>
130
+        <source>URL</source>
131
+        <translation>Profilseite</translation>
132
+    </message>
133
+    <message>
134
+        <location filename="../qml/contactqml/ContactDetailsComponent.qml" line="65"/>
135
+        <source>Created at</source>
136
+        <translation>Erstellt</translation>
137
+    </message>
138
+</context>
139
+<context>
140
+    <name>FriendsTab</name>
141
+    <message>
142
+        <location filename="../qml/contactqml/FriendsTab.qml" line="61"/>
143
+        <source>Friends</source>
144
+        <translation>Freunde</translation>
145
+    </message>
146
+    <message>
147
+        <location filename="../qml/contactqml/FriendsTab.qml" line="131"/>
148
+        <source>Contacts</source>
149
+        <translation>Kontakte</translation>
150
+    </message>
151
+    <message>
152
+        <location filename="../qml/contactqml/FriendsTab.qml" line="167"/>
153
+        <source>Groups</source>
154
+        <translation>Gruppen</translation>
155
+    </message>
156
+</context>
157
+<context>
158
+    <name>MessageSend</name>
159
+    <message>
160
+        <location filename="../qml/newsqml/MessageSend.qml" line="69"/>
161
+        <source>Title (optional)</source>
162
+        <translation>Überschrift (optional)</translation>
163
+    </message>
164
+    <message>
165
+        <location filename="../qml/newsqml/MessageSend.qml" line="142"/>
166
+        <source>Error</source>
167
+        <translation>Fehler</translation>
168
+    </message>
169
+    <message>
170
+        <location filename="../qml/newsqml/MessageSend.qml" line="142"/>
171
+        <source>Only one attachment supported at the moment.
172
+ Remove other attachment first!</source>
173
+        <translation>Nur ein Anhang derzeit unterstützt.
174
+ Lösche zuerst den anderen Anhang!</translation>
175
+    </message>
176
+</context>
177
+<context>
178
+    <name>NewsTab</name>
179
+    <message>
180
+        <location filename="../qml/newsqml/NewsTab.qml" line="21"/>
181
+        <source>Download profile image for </source>
182
+        <translation>Lade Profilbild für </translation>
183
+    </message>
184
+    <message>
185
+        <location filename="../qml/newsqml/NewsTab.qml" line="152"/>
186
+        <source>More</source>
187
+        <translation>Mehr</translation>
188
+    </message>
189
+    <message>
190
+        <location filename="../qml/newsqml/NewsTab.qml" line="249"/>
191
+        <source>Timeline</source>
192
+        <translation>Chronologisch</translation>
193
+    </message>
194
+    <message>
195
+        <location filename="../qml/newsqml/NewsTab.qml" line="258"/>
196
+        <source>Favorites</source>
197
+        <translation>Markierte News</translation>
198
+    </message>
199
+    <message>
200
+        <location filename="../qml/newsqml/NewsTab.qml" line="270"/>
201
+        <source>Conversations</source>
202
+        <translation>Unterhaltungen</translation>
203
+    </message>
204
+    <message>
205
+        <location filename="../qml/newsqml/NewsTab.qml" line="278"/>
206
+        <source>Notifications</source>
207
+        <translation>Meldungen</translation>
208
+    </message>
209
+</context>
210
+<context>
211
+    <name>Newsitem</name>
212
+    <message>
213
+        <location filename="../qml/newsqml/Newsitem.qml" line="29"/>
214
+        <source>attending: </source>
215
+        <translation>Teilnahme</translation>
216
+    </message>
217
+    <message>
218
+        <location filename="../qml/newsqml/Newsitem.qml" line="86"/>
219
+        <source>Source: </source>
220
+        <translation>Quelle: </translation>
221
+    </message>
222
+    <message>
223
+        <location filename="../qml/newsqml/Newsitem.qml" line="87"/>
224
+        <source>Direct Message</source>
225
+        <translation>Direktnachricht</translation>
226
+    </message>
227
+    <message>
228
+        <location filename="../qml/newsqml/Newsitem.qml" line="102"/>
229
+        <source>In reply to </source>
230
+        <translation>Antwort an </translation>
231
+    </message>
232
+    <message>
233
+        <location filename="../qml/newsqml/Newsitem.qml" line="114"/>
234
+        <source> comments</source>
235
+        <translation> Kommentare</translation>
236
+    </message>
237
+    <message>
238
+        <location filename="../qml/newsqml/Newsitem.qml" line="198"/>
239
+        <source>Attending: </source>
240
+        <translation>Teilnahme: </translation>
241
+    </message>
242
+    <message>
243
+        <location filename="../qml/newsqml/Newsitem.qml" line="353"/>
244
+        <source>Reply</source>
245
+        <translation>Antworten</translation>
246
+    </message>
247
+    <message>
248
+        <location filename="../qml/newsqml/Newsitem.qml" line="361"/>
249
+        <source>DM</source>
250
+        <translation>Direktnachricht</translation>
251
+    </message>
252
+    <message>
253
+        <location filename="../qml/newsqml/Newsitem.qml" line="367"/>
254
+        <source>Repost</source>
255
+        <translation>Teilen</translation>
256
+    </message>
257
+    <message>
258
+        <location filename="../qml/newsqml/Newsitem.qml" line="374"/>
259
+        <source>Conversation</source>
260
+        <translation>Unterhaltung</translation>
261
+    </message>
262
+    <message>
263
+        <location filename="../qml/newsqml/Newsitem.qml" line="379"/>
264
+        <source>Attending</source>
265
+        <translation>Teilnahme</translation>
266
+    </message>
267
+    <message>
268
+        <location filename="../qml/newsqml/Newsitem.qml" line="381"/>
269
+        <source>yes</source>
270
+        <translation>ja</translation>
271
+    </message>
272
+    <message>
273
+        <location filename="../qml/newsqml/Newsitem.qml" line="386"/>
274
+        <source>maybe</source>
275
+        <translation>vielleicht</translation>