Version 0.001

This commit is contained in:
LubuWest 2016-09-26 21:39:46 +02:00
parent 1986e59b58
commit 2bc729d02c
77 changed files with 6020 additions and 819 deletions

View File

@ -1,9 +1,77 @@
## Friendica#
## Friendiqa#
## Screenshot ##
QML based client for the Friendica Social Network. Tabs for news (incl. Direct Messages), friends and photos.
OS: currently Linux and Android(4.4.4).
![screenshot]()
## Screenshots ##
![Newstab](Screenshots/NewsTab.jpg)
![Friendstab](Screenshots/FriendsTab.jpg)
![Photostab](Screenshots/PhotoTab.jpg)
![Configtab](Screenshots/ConfigTab.jpg)
## Features ##
# News #
Currently supported:
Shows Posts from friends, Direct Messages and Notifications
Open links in external browser
Deletion, Reposting, Answering of Posts
Liking, disliking, favoriting
Update fetches new posts since last in local DB , More shows older posts from local DB
New Message with images, also possible as DM, Contact selection
ToDo:
Test new Aspargus features
Nice symbols for liking, disliking and menu for deletion, reposting and answering (currently press on contact picture, press on news would interfere with external link functionality)
Videos as attachment (sending and receiving)
Rich text editing in Send Dialog
# Friends #
Currently supported:
Grid of all known contacts with locally downloaded pictures
Large friend item for addional information and functionality
Show news of contact from local database
Send direct message, if contact is following
Show public pictures of contact (screenscraping of contact's website, works only with certain theme)
Open website of contact
ToDo:
More information for contact from description page, possibly private information for friends
Filter contacts for friends, forums,groups etc.
Groups: create, change, delete
# Images #
Currently supported:
Download all own images to local directory
Show albums in grid, show images in album in grid and fullscreen
Show albums and images of contacts
ToDo:
Better download mechanism for own images
Private images of friends
Support for all themes of friends
Delete downloaded own images
# Config #
Currently supported:
Multiple accounts
Check for valid url string
Maximum news (deleted after use of Quit button)
ToDo
OAuth?
View mode for news (chronological or tree)
# Other #
Friendstab and Newstab buggy after account change, restart helps
ToDo
Calendar tab, video tab
Photo upload to album (needs API change)
Translation
Blingbling
## License ##
Pubished under the [GPL v3](http://gplv3.fsf.org).
## Details ##
Friendica Client with Javascript and QML in an early stage

BIN
Screenshots/ConfigTab.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
Screenshots/FriendsTab.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
Screenshots/NewsTab.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
Screenshots/PhotoTab.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

View File

@ -1,256 +0,0 @@
function friendicaRequest(url,user,password,api,callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
} else if(xhr.readyState === XMLHttpRequest.DONE) {
try{ callback(xhr.responseText);
}
catch (e){
print("friendicaRequest: Data retrieval failure! "+ e);
}
}
}
xhr.open("GET", url+api,false,user,password);
xhr.send();
}
function requestFriends(url,user,password,database,callback){
friendicaRequest(url,user,password,"/api/statuses/friends", function (obj){
var friends=JSON.parse(obj);
for (var i=0;i<friends.length;i++){
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('store friends data for ' + friends[i].name);
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from contacts where id = "'+obj[i].id+'"'); // check for user id
if(result.rows.length === 1) {// use update
print(list[i].id +' exists, update it')
result = tx.executeSql('UPDATE contacts SET id="'+friends[i].id+'", name="'+friends[i].name+'", screen_name="'+friends[i].screen_name+'", location="'+friends[i].location+'", description="'+friends[i].description+'", profile_image="'+getBase64Image(friends[i].profile_image_url)+'", url="'+friends[i].url+'", protected="'+friends[i].protected+'", followers_count="'+friends[i].followers_count+'", friends_count="'+friends[i].friends_count+'", created_at="'+friends[i].created_at+'", favourites_count="'+friends[i].favourites_count+'", utc_offset="'+ friends[i].utc_offset+'", time_zone="'+friends[i].time_zone+'",statuses_count="' +friends[i].statuses_count+'", following="'+friends[i].following+'", verified="'+friends[i].verified+'", statusnet_blocking="'+friends[i].statusnet_blocking+'", notifications="'+friends[i].notifications+'", statusnet_profile_url="'+friends[i].statusnet_profile_url+'", cid="'+friends[i].cid+'", network="'+friends[i].network+'" WHERE cid="'+friends[i].cid+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO contacts VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [friends[i].id,friends[i].name,friends[i].screen_name,friends[i].location,friends[i].description,getBase64Image(friends[i].profile_image_url),friends[i].url,friends[i].protected,friends[i].followers_count,friends[i].friends_count,friends[i].created_at,friends[i].favourites_count,friends[i].utc_offset,friends[i].time_zone,friends[i].statuses_count,friends[i].following,friends[i].verified,friends[i].statusnet_blocking,friends[i].notifications,friends[i].statusnet_profile_url,friends[i].cid,friends[i].network]);}
print("Result: " + result)
});
}
callback();});}
function requestNews(url,user,password,database,callback){
friendicaRequest(url,user,password,"/api/statuses/friends_timeline", function (obj){
var news=JSON.parse(obj);
for (var i=0;i<news.length;i++){
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('store news data for ' + news[i].status_id);
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where id = "'+news[i].status_id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(news[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET text="'+news[i].text+'", truncated="'+news[i].truncated+'", created_at="'+news[i].created_at+'", in_reply_to_status_id="'+news[i].in_reply_to_status_id+'", source="'+news[i].source+'", status_id="'+news[i].status_id+'", in_reply_to_user_id="'+news[i].in_reply_to_user_id+'", geo="'+news[i].geo+'", favorited="'+news[i].favorited+'", uid="'+news[i].uid+'", status_html="'+news[i].status_html+'", statusnet_conversation_id="'+news[i].statusnet_conversation_id+'", attachments="'+news[i].attachments+'" where status_id="'+news[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [news[i].text,news[i].truncated,news[i].created_at, news[i].in_reply_to_status_id, news[i].source, news[i].status_id,news[i].in_reply_to_user_id,news[i].geo,news[i].favorited, news[i].uid,news[i].status_html,news[i].statusnet_conversation_id, news[i].attachments]);
print("Inserted");}
});}
callback();}
);}
function requestFriendsAlbumPictures(url,user,password,db){
readField("screen_name",db,"contacts",function(obj){
for (i=0; i<obj.length;i++){
friendicaRequest(url,user,password,"/photos/"+screen_name,function(photohtml){
print(photohtml);
var photoarray=[];
var arr = photohtml.split("photo-top-image-wrapper lframe");
for (j=1;j<arr.length;i++){
var photo = arr[i].substring(arr[i].indexOf('<img src=')+11,arr[i].indexOf('alt=')-3);
photoarray.push(photo);
}})}},"network","FRIENDICA")
}
function newsfromdb(database,user,callback,stop_id){
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
if (!stop_id){var rs = tx.executeSql('select status_id from news ORDER BY status_id DESC LIMIT 1');
var stop_id=rs.rows.item;}
var newsrs=tx.executeSql('select * from news WHERE (status_id<'+stop_id+') DESC LIMIT 20');
var newsArray;
for(var i = 0; i < newsrs.rows.length; i++) {
newsArray.push(newsrs.rows.item(i))
}
callback(newsArray);
});}
function requestList(url,user,password,database,callback) {
friendicaRequest(url,user,password,"/api/friendica/photos/list", function (obj){
var obj=JSON.parse(obj);
readField("resourceID",database,"imageData",function(AllStoredImages){
for(var i=0;i< AllStoredImages.length;i++){
obj.splice(obj.indexOf(AllStoredImages[i]),1);
}
});
callback(obj);
})}
function uploadData(url,user,password,api,data,callback) {
var xhr = new XMLHttpRequest();
print(url+api+data);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
print('HEADERS_RECEIVED')
} else if(xhr.readyState === XMLHttpRequest.DONE) {
print('DONE');
var obj=xhr.responseText.toString();
print("Upload message: "+obj);
callback(obj);
}
}
xhr.open("POST", url+api+data,false,user,password);
xhr.send();
}
function uploadMedia(url,user,password,picture,callback) {
uploadData(url,user,password,"/api/media/upload?media=", getBase64Image(picture),callback)
}
function statusUpdate(url,user,password,title,status,in_reply_to_status_id,media,group_allow,contact_allow,group_deny,contact_deny,callback) {
if(title){titleString="&title="+title}
if(status){statusString="&status="+status}
if(in_reply_to_status_id){replyString="&in_reply_to_status_id="+in_reply_to_status_id}
if(media){mediaString="&media="+base64Image(media)}
if(group_allow){groupallowString="&group_allow="+group_allow}
if(group_deny){groupdenyString="&group_deny="+group_deny}
if(contact_allow){contactallowString="&contact_allow="+contact_allow}
if(contact_deny){contactdenyString="&contact_deny="+contact_deny}
if(in_reply_to_status_id){replyString="&in_reply_to_status_id="+in_reply_to_status_id}
upload_data(url,user,password,"statuses/update?"+titleString+statusString+replyString+mediaString+groupallowString+groupdenyString+contactallowString+contactdenyString, function (obj){
var obj=JSON.parse(obj);
})}
function getBase64Image(img) {
var ctx = getContext("2d");
ctx.width = img.width;
ctx.height = img.height;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
// escape data:image prefix
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
// or just return dataURL
// return dataURL
}
function dataRequest(url,user,password,photoID,database) {
friendicaRequest(url,user,password,"/api/friendica/photo?photo_id="+photoID, function (obj){
try{ var image = JSON.parse(obj);
print(" Data retrieval success!");
storeData(image,database)
}
catch (e){
infobox.text="Data retrieval failure! "+ e;
}
});
}
function initDatabase(database) { // initialize the database object
var db =LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('initDatabase()'+database[0]+database[1]+database[2]+database[3])
db.transaction( function(tx) {
print('... create table')
tx.executeSql('CREATE TABLE IF NOT EXISTS imageData(id INT, uid INT, contact_id INT, guid TEXT, resourceID TEXT, created TEXT,edited TEXT, title TEXT, desc TEXT, album TEXT,filename TEXT, type TEXT, height INT, width INT, datasize INT, data BLOB, scale INT, profile INT, allow_cid TEXT, allow_gid TEXT, deny_cid TEXT, deny_gid TEXT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS config(server TEXT, username TEXT, password TEXT,isActive BOOL)');
tx.executeSql('CREATE TABLE IF NOT EXISTS news(text TEXT, truncated BOOL, created_at TEXT, in_reply_to_status_id INT, source TEXT, status_id INT, in_reply_to_user_id INT, geo TEXT,favorited BOOL, uid INT, statusnet_html TEXT, statusnet_conversation_id TEXT,attachments TEXT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS contacts(id INT, name TEXT, screen_name TEXT, location TEXT,description TEXT, profile_image BLOB, url TEXT, protected BOOL, followers_count INT, friends_count INT, created_at TEXT, favourites_count INT, utc_offset TEXT, time_zone TEXT, statuses_count INT, following BOOL, verified BOOL, statusnet_blocking BOOL, notifications BOOL, statusnet_profile_url TEXT, cid INT, network TEXT)');
})}
function storeConfig(database,obj) { // stores config to DB
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('storeConfig() for ' + obj.username)
print('database: ' + database[0]);
db.transaction( function(tx) {
print('... check if a object exists: '+obj.username)
var result = tx.executeSql('SELECT * from config WHERE username="'+obj.username+'"');
if(result.rows.length === 1) {// use update
print(obj.username +' exists, update it');
var result2 = tx.executeSql('UPDATE config SET server="'+obj.server+'",password="'+obj.password+'", isActive="TRUE" WHERE username="'+obj.username +'"');
var result3 = tx.executeSql('UPDATE config SET isActive="FALSE" WHERE username !="'+obj.username +'"');
} else {// use insert print('... does not exists, create it')
var result2 = tx.executeSql('INSERT INTO config VALUES (?,?,?,?)', [obj.server, obj.username, obj.password, "TRUE"]);
var result3 = tx.executeSql('UPDATE config SET isActive="FALSE" WHERE username !="'+obj.username +'"');
print("Inserted");}
});}
function getServerConfig(url,user,password,callback){
try {friendicaRequest(url,user,password,"/api/statusnet/config", function (obj){
var serverconfig = JSON.parse(obj);
var serverconfigString="import QtQuick 2.0; Text{x: 20; y: 150; color:'white'; text: 'Name: "+serverconfig.site.name+"\nLanguage: "+serverconfig.site.language+
"\nEmail: "+serverconfig.site.email+"\nTimezone: "+serverconfig.site.timezone+"\nClosed: "+serverconfig.site.closed+
"\nText limit: "+serverconfig.site.textlimit+"\nShort Url length: "+serverconfig.site.shorturllength+
"\nFriendica version: "+serverconfig.site.friendica.FRIENDICA_VERSION+"\nDFRN version: "+serverconfig.site.friendica.DFRN_PROTOCOL_VERSION +
"\nDB Update version: "+serverconfig.site.friendica.DB_UPDATE_VERSION+"'}";
callback(serverconfigString);
})}
catch (e){callback (e);
}}
function readConfig(database,callback,filter,filtervalue) { // reads and applies data from DB
print('readConfig()')
if (filter){var where = " WHERE "+ filter +" = '" + filtervalue+"'";} else { var where="";}
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
print('... read from database '+where)
var rs = tx.executeSql('select * from config'+where);
var rsArray=[];
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i))
}
print(rs.toString);
var rsObject={server:rsArray[0].server,username:rsArray[0].username, password:rsArray[0].password};
callback(rsObject);
});
}
function storeData(obj,database) { // stores data to DB
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('storeData() for ' + obj["resource-id"])
print('database: ' + database[0]);
db.transaction( function(tx) {
print('... check if a object exists: '+obj["resource-id"])
var result = tx.executeSql('SELECT * from imageData where resourceID = "'+obj["resource-id"]+'"'); // prepare object to be stored as JSON
if(result.rows.length === 1) {// use update
print(obj["resource-id"] +' exists, update it')
result = tx.executeSql('UPDATE imageData SET id="'+obj.id+'", uid="'+obj.uid+'", contact_id="'+obj.contact_id+'", guid="'+obj.guid+'", created="'+obj.created+'", edited="'+obj.edited+'", datasize="'+obj.datasize+'", scale="'+obj.scale+'", profile="'+obj.profile+'", allow_cid="'+obj.allow_cid+'", allow_gid="'+obj.allow_gid+'", deny_cid="'+obj.deny_cid+'", deny_gid="'+obj.deny_gid+'", filename="'+obj.filename+'",title="'+obj.title+'", desc="'+obj.desc+'", type="'+obj.type+'", width="'+obj.width+'", height="'+obj.height+'", album="'+obj.album+'", data="'+obj.data+'", where resourceID="'+obj["resource-id"]+'"');
} else {// use insert print('... does not exists, create it')
result = tx.executeSql('INSERT INTO imageData VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [obj.id,obj.uid,obj.contact_id,obj.guid, obj["resource-id"], obj.created,obj.edited, obj.title, obj.desc, obj.album, obj.filename, obj.type, obj.height, obj.width, obj.datasize, obj.data,obj.scale, obj.profile,obj.allow_cid,obj.allow_gid,obj.deny_cid,obj.deny_gid]);
print("Inserted");}
});}
function readData(resourceID) { // reads and applies data from DB
print('readData()')
if(!db) { return; }
db.transaction( function(tx) {
print('... read object')
var result = tx.executeSql('select * from imageData where resourceID="'+resourceID+'"');
return result;
});
}
function readField(field,database,table, callback,filter,filtervalue) { // reads and applies data from DB
print('readData()')
if (filter){
var where = " WHERE "+ filter +" = '" + filtervalue+"'";
} else { var where="";}
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
print('... read from database ' + field)
var rsArray=[];
print('select DISTINCT '+field+' from '+table+where);
var rs = tx.executeSql('select DISTINCT '+field+' from '+table+where);
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i)[field])
}
callback(rsArray);
});
}

View File

@ -1,392 +0,0 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Window 2.0
import "service.js" as Service
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
import QtMultimedia 5.0
TabView{
tabPosition: Qt.BottomEdge
width: 600
height: 600
property var db: ["Photos", "1.0", "Stores Friendica data", 100000000]
Tab{
title: "Fotos"
Rectangle {
property var db;
width: 600
height: 600
color: '#fff'
property var imageList
Image {
id: updatePhoto
x: 10; y: 10
source: "Update.png"
MouseArea {
anchors.fill: parent
onClicked: {
updatePhoto.rotation += 25;
print("clicked");
var url="http://cubie.fritz.box";
var user="marco";
var password="rx3715";
var db = ["Photos", "1.0", "Stores photo data", 100000000];
Service.initDatabase(db);
print("Database:" +db[0]);
Service.requestList(url,user,password,db, function(obj){
for (var i=0; i<obj.length; i++){
infoboxGallery.text="Loading "+i+" of "+ obj.length+" pictures...";
print ("Requesting and storing data for "+obj[i]);
Service.dataRequest(url,user,password,obj[i],db);
}
});
}}
}
ComboBox{
width: 150
model: ["album", "type","filename"]
onCurrentIndexChanged:{
var db = ["Photos", "1.0", "Stores photo data", 100000000];
photoModel.clear();
Service.readField(currentText,db, "imageData",function(filter){
for (var j=0;j<filter.length;j++){
Service.readField("data",db,"imageData",function(obj){
// obj.sort(function(obj1,obj2){return obj1.data-obj2.data});
if (obj[j]) {photoModel.append({"imageString": "data:image/jpeg;base64," + obj[j], "selectionName": filter[j]});
};
},currentText,filter[j]);
}})
}
}
Text {
id:infoboxGallery
width: parent.width - 60;height: 30
anchors.left:parent.left
text: ""
color: "black"
font.family: "Monospace"
font.pixelSize: 10
}
Image {
id: liste
x: 300; y: 10
sourceSize.height: 150
source: "Update.png"
MouseArea {
anchors.fill: parent
onClicked: {
var db = ["Photos", "1.0", "Stores photo data", 100000000];
Service.readField("album",db, "imageData",function(albums){
for (var j=0;j<albums.length;j++){
Service.readField("data",db,"imageData",function(obj){
// obj.sort(function(obj1,obj2){return obj1.data-obj2.data});
if (obj[i]) {photoModel.append({"imageString": "data:image/jpeg;base64," + obj[j]})};
},"album",albums[j]);
}
})
}
}}
ListModel{
id: photoModel
dynamicRoles: false
}
GridView {
id: view
cellWidth: 80
cellHeight: 80
x: 10;y:50
anchors.fill: parent
anchors.margins: 50
clip: true
add: Transition {
NumberAnimation { properties: "x,y"; from: 0; duration: 1000 }
}
model: photoModel
delegate: photoDelegate
}
Component {
id: photoDelegate
Rectangle {
id: wrapper
width: 80
height: 80
border.color: "red"
Text {
text: selectionName
color: "#303030"
font.family: "Monospace"
font.pixelSize: 14
}
Image {
id: photoImage
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: imageString
MouseArea {
anchors.fill: parent
onClicked: {
}}
}
}
}
ListModel{
id:photoslideshow
}
}
}
Tab{
title: "Upload"
Rectangle{
property string photofile:"Update.png"
color: "grey"
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: shortcuts.pictures
selectMultiple: true
onAccepted: {
photofile=fileDialog.fileUrls[0];
console.log("You chose: " + fileDialog.fileUrls)
Service.readConfig(db,function(login){
var url=login.url; var user=login.user; var password=login.password;
Service.friendlist(url,user,password,function(obj){
for (var i=0; i<obj.length; i++){
print(obj[i]);
if (obj[i]) {friendsModel.append({"friendName": obj[i]});
};
};
});
});
}
onRejected: {
console.log("Canceled")
}
}
Component.onCompleted: {fileDialog.open()}
Image {
id: photoFromFilesystem
x: 20;y:50
height: 200
fillMode: Image.PreserveAspectFit
source: photofile
}
Button {
text: "Upload"
onClicked:{
Service.readConfig(db,function(obj){
var url=obj.url;
var user=obj.user;
var password=obj.password;
// img.src=file;
Service.uploadMedia(url,user,password,photofile, function(returnvalue){print("Upload return"+returnvalue)})
},"isActive","TRUE");}
}
ListModel{
id: friendsModel
dynamicRoles: false
}
GridView {
id: view
cellWidth: 50
cellHeight: 50
x: 300;y:50
// anchors.fill: parent
// anchors.margins: 50
clip: true
add: Transition {
NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
}
model: friendsModel
delegate: friendsDelegate
}
Component {
id: friendsDelegate
Rectangle {
id: wrapper
width: 50
height: 50
border.color: "grey"
Text {
text: friendName
color: "#303030"
font.family: "Monospace"
font.pixelSize: 10
}
// Image {
// id: photoImage
// anchors.fill: parent
// fillMode: Image.PreserveAspectFit
// source: imageString
// }
state: "neutral"
states: [
State {
name: "neutral"
PropertyChanges { target: wrapper; color: "grey" }
},
State {
name: "positive"
PropertyChanges { target: wrapper; color: "green" }
},
State {
name: "negative"
PropertyChanges { target: wrapper; color: "red" }
}
]
MouseArea {
anchors.fill: parent
onClicked: {
if (parent.state == "neutral"){ parent.state="positive"};
if (parent.state=="positive") {parent.state="negative"};
if (parent.state=="positive") {parent.state="neutral"};
}
}
}}
}}
Tab {
title: "Camera"
property string photofile;
VideoOutput {
anchors.fill: parent
source: localCamera
}
Camera {
id: localCamera
}
Button {
id: shotButton
width: 200; height: 75
text: "Take Photo"
onClicked: {
localCamera.imageCapture.capture();
} }
Connections {
target: localCamera.imageCapture
onImageSaved: {
photofile= imagePaths.append({"path": path})
listView.positionViewAtEnd(); }
}
Image {
id: photoFromCamera
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: photo
}
Button {
text: "Upload"
onClicked:{
var url="http://cubie.fritz.box";
var user="marco";
var password="rx3715";
img.src=file;
Service.Upload(url,user,password,file)
}
}
}
Tab{
title: "Config"
Rectangle{
id:configBackground
color: "grey"
Text {
text: "Server"
x: 10; y: 10
}
Text {
text: "User"
x: 10; y: 40
}
Text {
text: "Password"
x: 10; y: 70
}
Rectangle{
color: "white"
x: 100; y: 10; width: 150; height: 20;
TextInput {
anchors.fill: parent
id: servername
selectByMouse: true
focus: true
text: "http://"
}
}
Rectangle{
color: "white"
x: 100; y: 40; width: 150; height: 20;
TextInput {
id: username
anchors.fill: parent
selectByMouse: true
}
}
Rectangle{
color: "white"
x: 100; y: 70; width: 150; height: 20;
TextInput {
id: password
anchors.fill: parent
selectByMouse: true
echoMode: TextInput.PasswordEchoOnEdit
// text: "password"
}
}
Button {
x: 100; y: 100; width: 96; height: 20;
text: "Update"
onClicked:{
var serverString="";
var userconfig={server: servername.text, username: username.text, password:password.text};
Service.storeConfig(db,userconfig);
Service.readConfig(db,function(userconfig){print(userconfig.server);Service.getServerConfig(userconfig.server,userconfig.username,userconfig.password, function(obj){
serverString=obj})},"isActive","TRUE");
var serverconfigObject=Qt.createQmlObject(serverString,configBackground,"serverconfigOutput")
}}
Component.onCompleted: {
Service.initDatabase(db);
try {Service.readConfig(db,function(obj){
servername.text=obj.server;
username.text= obj.username;
password.text=obj.password;},"isActive","TRUE")}
catch (e){print(e)}
}
}
}
}

View File

@ -1,20 +0,0 @@
/* File generated by Qt Creator */
import QmlProject 1.1
Project {
mainFile: "test.qml"
/* Include .qml, .js, and image files from current directory and subdirectories */
QmlFiles {
directory: "."
}
JavaScriptFiles {
directory: "."
}
ImageFiles {
directory: "."
}
/* List of plugin directories passed to QML runtime */
// importPaths: [ "../exampleplugin" ]
}

View File

@ -1,146 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2015-11-27T21:09:55. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{4e26e1df-26fd-4b76-8028-2f213523c328}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{e9e69f48-1ef9-4389-91ea-9cc2982eefff}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">-1</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Lokales Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">0</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">QML Scene</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmlProjectManager.QmlRunConfiguration.QmlScene</value>
<value type="QString" key="QmlProjectManager.QmlRunConfiguration.MainScript">CurrentFile</value>
<value type="QString" key="QmlProjectManager.QmlRunConfiguration.QDeclarativeViewerArguments"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>

BIN
v0.001/Friendiqa_v0.001.apk Normal file

Binary file not shown.

BIN
v0.001/friendica32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<manifest package="org.qtproject.friendiqa" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.001" android:versionCode="1" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="Friendiqa" android:icon="@drawable/icon">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="friendiqa"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Splash screen -->
<!--
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
-->
<!-- Splash screen -->
<!-- Background running -->
<!-- Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after
"applicationStateChanged(Qt::ApplicationSuspended)"
signal is sent! -->
<meta-data android:name="android.app.background_running" android:value="false"/>
<!-- Background running -->
</activity>
</application>
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="22"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
</manifest>

View File

@ -0,0 +1,57 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.1.0'
}
}
allprojects {
repositories {
jcenter()
}
}
apply plugin: 'com.android.application'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
android {
/*******************************************************
* The following variables:
* - androidBuildToolsVersion,
* - androidCompileSdkVersion
* - qt5AndroidDir - holds the path to qt android files
* needed to build any Qt application
* on Android.
*
* are defined in gradle.properties file. This file is
* updated by QtCreator and androiddeployqt tools.
* Changing them manually might break the compilation!
*******************************************************/
compileSdkVersion androidCompileSdkVersion.toInteger()
buildToolsVersion androidBuildToolsVersion
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
res.srcDirs = [qt5AndroidDir + '/res', 'res']
resources.srcDirs = ['src']
renderscript.srcDirs = ['src']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
lintOptions {
abortOnError false
}
}

View File

@ -0,0 +1,9 @@
## This file is automatically generated by QtCreator.
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
androidBuildToolsVersion=23.0.2
androidCompileSdkVersion=18
buildDir=.build
qt5AndroidDir=/home/pankraz/bin/Qt5.5.1/5.5/android_armv7/src/android/java

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip

164
v0.001/source-android/android/gradlew vendored Normal file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,6 @@
## This file is automatically generated by QtCreator.
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
sdk.dir=/opt/android-sdk

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,25 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<array name="qt_sources">
<item>https://download.qt-project.org/ministro/android/qt5/qt-5.4</item>
</array>
<!-- The following is handled automatically by the deployment tool. It should
not be edited manually. -->
<array name="bundled_libs">
<!-- %%INSERT_EXTRA_LIBS%% -->
</array>
<array name="qt_libs">
<!-- %%INSERT_QT_LIBS%% -->
</array>
<array name="bundled_in_lib">
<!-- %%INSERT_BUNDLED_IN_LIB%% -->
</array>
<array name="bundled_in_assets">
<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->
</array>
</resources>

View File

@ -0,0 +1,23 @@
<RCC>
<qresource prefix="/">
<file>js/layout.js</file>
<file>js/photoworker.js</file>
<file>js/service.js</file>
<file>js/news.js</file>
<file>js/newsworker.js</file>
<file>js/helper.js</file>
<file>qml/FriendComponent.qml</file>
<file>qml/MessageSend.qml</file>
<file>qml/Newsitem.qml</file>
<file>qml/PhotoComponent.qml</file>
<file>qml/PhotogroupComponent.qml</file>
<file>qml/PhotoPlaceholder.qml</file>
<file>qml/friendiqa.qml</file>
<file>qml/PhotoTab.qml</file>
<file>qml/ConfigTab.qml</file>
<file>qml/FriendsTab.qml</file>
<file>qml/NewsTab.qml</file>
<file>qml/InfoBox.qml</file>
<file>images/defaultcontact.jpg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,19 @@
#include <QApplication>
#include <QtQml/QQmlEngine>
#include <QtQuick>
#include "xhr.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QQuickView view;
XHR* xhr = XHR::instance();
view.rootContext()->setContextProperty("xhr", xhr);
view.setSource(QUrl("qrc:/qml/friendiqa.qml"));
view.show();
view.connect(view.rootContext()->engine(), SIGNAL(quit()), &app, SLOT(quit()));
return app.exec();
}

View File

@ -0,0 +1,90 @@
#include "uploadableimage.h"
#include <QBuffer>
#include <QDebug>
#include <QFileInfo>
#include <QUrl>
void UploadableImage::setSource(const QString &a) {
if (a != m_source) {
m_source = a;
//m_base64 = "";
m_mimetype = "";
m_filename = "";
qDebug() << "UploadableImage::setSource : " << m_source;
if (m_source=="") {
emit sourceChanged();
//emit base64Changed();
emit mimetypeChanged();
emit filenameChanged();
return;
}
QImage fullimage = QImage(QUrl(m_source).toLocalFile());
if (fullimage.width() > 800 || fullimage.height() > 800) {
if (fullimage.width() > fullimage.height()) {
m_image = fullimage.scaledToWidth(800);
} else {
m_image = fullimage.scaledToHeight(800);
}
} else {
m_image = fullimage;
}
qDebug() << "UploadableImage::setSource : " << m_image.width() << "x" << m_image.height();
emit sourceChanged();
QFileInfo fi(m_source);
m_filename = fi.fileName();
emit filenameChanged();
QString filetype = fi.suffix().toUpper();
if (filetype!="PNG" && filetype!="JPG") {
filetype = "JPG";
}
qDebug() << "UploadableImage::setSource : " << "Saving as " << filetype;
m_mimetype = "image/"+filetype.toLower();
emit mimetypeChanged();
/*
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_image.save(&buffer, filetype.toLatin1().constData());
QString b64 = QString::fromLatin1(byteArray.toBase64().data());
for(int k=0; k<b64.length(); k+=76) {
m_base64 += b64.mid(k,76) + "\n";
}
m_base64 = m_base64.trimmed();
emit base64Changed();
*/
}
}
QString UploadableImage::source() const {
return m_source;
}
//QString UploadableImage::base64() const {
// return m_base64;
//}
QString UploadableImage::filename() const {
return m_filename;
}
QString UploadableImage::mimetype() const {
return m_mimetype;
}
QByteArray UploadableImage::bytes() {
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_image.save(&buffer, "PNG");
return byteArray;
}

View File

@ -0,0 +1,40 @@
#ifndef UPLOADABLEIMAGE_H
#define UPLOADABLEIMAGE_H
#include <QObject>
#include <QQuickItem>
#include <QImage>
class UploadableImage : public QObject
{
Q_OBJECT
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
//Q_PROPERTY(QString base64 READ base64 NOTIFY base64Changed)
Q_PROPERTY(QString filename READ filename NOTIFY filenameChanged)
Q_PROPERTY(QString mimetype READ mimetype NOTIFY mimetypeChanged)
Q_PROPERTY(QByteArray bytes READ bytes)
public:
void setSource(const QString &a);
QString source() const;
//QString base64() const;
QString filename() const;
QString mimetype() const;
QByteArray bytes();
signals:
void sourceChanged();
//void base64Changed();
void filenameChanged();
void mimetypeChanged();
private:
QString m_source;
QImage m_image;
//QString m_base64;
QString m_filename;
QString m_mimetype;
};
#endif // UPLOADABLEIMAGE_H

View File

@ -0,0 +1,168 @@
#include "xhr.h"
#include <QHttpPart>
#include <QTextCodec>
#include <QUrlQuery>
#include "uploadableimage.h"
XHR *XHR::instance()
{
static XHR xhr;
return &xhr;
}
XHR::XHR(QObject *parent) : QObject(parent)
{
request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
}
void XHR::setUrl(QString url)
{
if (url!=m_url) {
m_url = url;
emit urlChanged();
}
}
void XHR::setLogin(QString login)
{
if (login!=m_login) {
m_login = login;
emit loginChanged();
}
}
QString XHR::url() const
{
return m_url;
}
QString XHR::login() const
{
return m_login;
}
void XHR::setParam(QString name, QString value)
{
params.insert(name, value);
}
void XHR::setImageFileParam(QString name, QString url)
{
files.insert(name, url);
}
void XHR::clearParams()
{
files.clear();
params.clear();
}
void XHR::get()
{
QUrlQuery query;
QHashIterator<QString, QString> i(params);
while(i.hasNext()) {
i.next();
query.addQueryItem(i.key(), i.value());
}
QUrl requrl(m_url);
requrl.setQuery(query);
QByteArray loginData = m_login.toLocal8Bit().toBase64();
QString headerData = "Basic " + loginData;
request.setRawHeader("Authorization", headerData.toLocal8Bit());
request.setUrl(requrl);
reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &XHR::onReplySuccess);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onReplyError(QNetworkReply::NetworkError)));
connect(reply, &QNetworkReply::readyRead, this, &XHR::onReadyRead);
}
void XHR::post()
{
qDebug() << "start post to " << m_url;
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHashIterator<QString, QString> iparams(params);
while(iparams.hasNext()) {
iparams.next();
qDebug() << "\t add param " << iparams.key() << " : " << iparams.value();
QHttpPart textPart;
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + iparams.key() + "\""));
textPart.setBody(iparams.value().toUtf8());
multiPart->append(textPart);
}
UploadableImage uimg;
QHashIterator<QString, QString> ifiles(files);
while(ifiles.hasNext()) {
ifiles.next();
uimg.setSource(ifiles.value());
qDebug() << "\t image: " << uimg.mimetype() << ", " << ifiles.key();
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(uimg.mimetype()));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + ifiles.key() + "\"; filename=\""+uimg.filename()+"\""));
imagePart.setBody(uimg.bytes());
multiPart->append(imagePart);
}
QByteArray loginData = m_login.toLocal8Bit().toBase64();
QString headerData = "Basic " + loginData;
request.setRawHeader(QByteArray("Authorization"), headerData.toLocal8Bit());
request.setUrl(m_url);
reply = manager.post(request, multiPart);
qDebug() << "\t request sent";
connect(reply, &QNetworkReply::finished, this, &XHR::onReplySuccess);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onReplyError(QNetworkReply::NetworkError)));
connect(reply, &QNetworkReply::readyRead, this, &XHR::onReadyRead);
connect(reply, &QNetworkReply::sslErrors, this, &XHR::onSSLError);
qDebug() << "\t reply signals connected";
}
void XHR::onReplyError(QNetworkReply::NetworkError code)
{
qDebug() << code;
emit this->error( bufferToString(), (int) code);
reply->deleteLater();
}
void XHR::onReplySuccess()
{
qDebug() << "!";
emit this->success( bufferToString() );
reply->deleteLater();
}
void XHR::onReadyRead()
{
qDebug() << ".";
buffer += reply->readAll();
}
void XHR::onSSLError(const QList<QSslError> &errors)
{
qDebug() << "XHR::onSSLError :" ;
QListIterator<QSslError> ierrs(errors);
while(ierrs.hasNext()) {
qDebug() << "\t" << ierrs.next().errorString();
}
}
QString XHR::bufferToString()
{
return QTextCodec::codecForName("utf-8")->toUnicode(buffer);
}

View File

@ -0,0 +1,60 @@
#ifndef XHR_H
#define XHR_H
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QObject>
class XHR : public QObject
{
Q_OBJECT
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QString login READ login WRITE setLogin NOTIFY loginChanged)
public:
static XHR *instance();
explicit XHR(QObject *parent = 0);
void setUrl(QString url);
// void setLogin(QString login);
QString url() const;
QString login() const;
signals:
void urlChanged();
void loginChanged();
void success(QString data);
void error(QString data, int code);
public slots:
void setLogin(QString login);
void setParam(QString name, QString value);
void setImageFileParam(QString name, QString url);
void clearParams();
void post();
void get();
private slots:
void onReplyError(QNetworkReply::NetworkError code);
void onReplySuccess();
void onReadyRead();
void onSSLError(const QList<QSslError> &errors);
private:
QByteArray buffer;
QString m_url;
QString m_login;
QHash<QString, QString> params;
QHash<QString, QString> files;
QNetworkAccessManager manager;
QNetworkRequest request;
QNetworkReply *reply;
QString bufferToString();
};
#endif // XHR_H

View File

@ -0,0 +1,49 @@
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = friendiqa
CONFIG += release
QT += qml quick gui widgets
SOURCES += common/friendiqa.cpp \
common/uploadableimage.cpp \
common/xhr.cpp
RESOURCES = application.qrc
OTHER_FILES += qml/friendiqa.qml \
translations/*.ts \
qml/*.qml
js/*.js
# German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the
# following TRANSLATIONS line. And also do not forget to
# modify the localized app name in the the .desktop file.
TRANSLATIONS += translations/friendiqa-de.ts
HEADERS += \
common/uploadableimage.h \
common/xhr.h
DISTFILES += \
android/AndroidManifest.xml \
android/gradle/wrapper/gradle-wrapper.jar \
android/gradlew \
android/res/values/libs.xml \
android/build.gradle \
android/gradle/wrapper/gradle-wrapper.properties \
android/gradlew.bat
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android

View File

@ -0,0 +1,387 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.1.0, 2016-09-26T21:14:21. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{feb2a9e8-6b42-4908-9ecd-b9e4d47e7412}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Android für armeabi-v7a (GCC 4.9, Qt 5.5.1)</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Android für armeabi-v7a (GCC 4.9, Qt 5.5.1)</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{10172d6f-97b2-4745-a95e-fc1020afb172}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/pankraz/bin</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.2">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Anwendungsdaten kopieren</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidPackageInstallationStep</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.3">
<value type="QString" key="BuildTargetSdk">android-18</value>
<value type="QString" key="KeystoreLocation"></value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Android-APK erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmakeProjectManager.AndroidBuildApkStep</value>
<value type="int" key="Qt4ProjectManager.AndroidDeployQtStep.DeployQtAction">2</value>
<value type="bool" key="UseGradle">false</value>
<value type="bool" key="VerboseOutput">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">4</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/pankraz/ownCloud/clientsync/Friendiqa/v0.001/bin</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.2">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Anwendungsdaten kopieren</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidPackageInstallationStep</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.3">
<value type="QString" key="BuildTargetSdk">android-18</value>
<value type="QString" key="KeystoreLocation">/home/pankraz/ownCloud/clientsync/android_release.keystore</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Android-APK erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmakeProjectManager.AndroidBuildApkStep</value>
<value type="int" key="Qt4ProjectManager.AndroidDeployQtStep.DeployQtAction">2</value>
<value type="bool" key="UseGradle">false</value>
<value type="bool" key="VerboseOutput">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">4</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/pankraz/ownCloud/clientsync/Friendiqa/v0.001/build-friendiqa-Android_f_r_armeabi_v7a_GCC_4_9_Qt_5_5_1-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.2">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Anwendungsdaten kopieren</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidPackageInstallationStep</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.3">
<value type="QString" key="BuildTargetSdk">android-23</value>
<value type="QString" key="KeystoreLocation"></value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Android-APK erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QmakeProjectManager.AndroidBuildApkStep</value>
<value type="int" key="Qt4ProjectManager.AndroidDeployQtStep.DeployQtAction">2</value>
<value type="bool" key="UseGradle">false</value>
<value type="bool" key="VerboseOutput">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">4</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
<value type="QString">-w</value>
<value type="QString">-r</value>
</valuelist>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment auf Android-Gerät</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployQtStep</value>
<value type="bool" key="UninstallPreviousPackage">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment auf Android-Gerät</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deployment auf Android-Gerät</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidDeployConfiguration2</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">friendiqa</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.AndroidRunConfiguration:/home/pankraz/ownCloud/clientsync/Friendiqa/v0.001/source-android/friendiqa.pro</value>
<value type="QString" key="QMakeProjectManager.QmakeAndroidRunConfiguration.ProFile">friendiqa.pro</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,12 @@
WorkerScript.onMessage = function(msg) {
msg.model.clear();
for (var j=0;j<msg.albums.length;j++){
if (msg.albums[j]) {
var albumobject=msg.albums[j];
var data=({"albumobject": albumobject,"foreignPicture": msg.foreignPicture})}
// print("Albums:"+j+msg.albums.length+JSON.stringify(data));
msg.model.append(data);}
if (j==msg.albums.length){
msg.model.sync()
};
}

View File

@ -0,0 +1,80 @@
.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
function friendicaRequest(login,api,rootwindow,callback) {
var xhrequest= new XMLHttpRequest();
xhrequest.onreadystatechange = function() {
if (xhrequest.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
} else if(xhrequest.readyState === XMLHttpRequest.DONE) {
try{ if (xhrequest.responseText!=""){
callback(xhrequest.responseText)
}else{
showMessage("Error",api+" NO RESPONSE",rootwindow)
callback(xhrequest.responseText)
}
}
catch (e){
showMessage("Error", api+" "+e,rootwindow)
}
}
}
xhrequest.open("GET", login.server+api,true,login.username,Qt.atob(login.password));
xhrequest.send();
}
function friendicaWebRequest(url,rootwindow,callback) {
var xhrequest = new XMLHttpRequest();
xhrequest.onreadystatechange = function() {
if (xhrequest.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
} else if(xhrequest.readyState === XMLHttpRequest.DONE) {
try{ callback(xhrequest.responseText);
}
catch (e){
showMessage("Error",url+" "+e, rootwindow)
}
}
}
xhrequest.open("GET", url,true);
xhrequest.send();
}
function readData(database,table,callback,filter,filtervalue) { // reads and applies data from DB
if (filter){
var where = " WHERE "+ filter +" = '" + filtervalue+"'";
} else { var where="";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
// print('select * from '+table+where);
var rsArray=[];
var rs = tx.executeSql('select * from '+table+where);
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i))
}
callback(rsArray);
});
}
function readField(field,database,table, username, callback,filter,filtervalue) { // reads and applies data from DB
if (filter){
var where = " AND "+ filter +" = '" + filtervalue+"'";
} else { var where="";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
// print('... read from database ' + field)
var rsArray=[];
print('select DISTINCT '+field+' from '+table+' WHERE username="'+username+'"'+where+' ORDER BY '+field+' ASC');
var rs = tx.executeSql('select DISTINCT '+field+' from '+table+' WHERE username="'+username+'"'+where+' ORDER BY '+field+' ASC');
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i)[field])
}
callback(rsArray);
});
}
function showMessage(header,message,rootwindow){
var messageString='import QtQuick 2.0; import QtQuick.Dialogs 1.2; MessageDialog{ visible: true; title:"'+header+'";standardButtons: StandardButton.Ok; text:" '+message+'"}';
var messageObject=Qt.createQmlObject(messageString,rootwindow,"messageOutput");
}

View File

@ -0,0 +1,44 @@
function showFriends(db) {
Service.readActiveConfig(db,function(login){
Service.requestFriends(login.url,login.user,login.password,displayFriends);
});
}
function displayFriends(obj){
for (var i=0; i<obj.length; i++){
print(obj[i]);
if (obj[i]) {friendsModel.append({"friendName": obj[i]});
};
}}
function ensureVisibility(c,f)
{
if (f.contentX >= c.x)
f.contentX = c.x;
else if (f.contentX+f.width <= c.x+c.width)
f.contentX = c.x+c.width-f.width;
if (f.contentY >= c.y)
f.contentY = c.y;
else if (f.contentY+f.height <= c.y+c.height)
f.contentY = c.y+c.height-f.height;
}
function createObject(objectQml,qmlParameters,parentitem,callback) {
var component = Qt.createComponent(objectQml);
if (component.status === Component.Ready || component.status === Component.Error)
finishCreation(component,qmlParameters,parentitem,callback);
else
component.statusChanged.connect(finishCreation(qmlParameters));
}
function finishCreation(component,qmlParameters,parentitem,callback) {
if (component.status === Component.Ready) {
var createdObject = component.createObject(parentitem, qmlParameters);
if (createdObject === null)
print("Error creating image"); }
else if (component.status === Component.Error)
print("Error loading component:"+component.errorString());
else {print("created")}
callback(createdObject);
}

View File

@ -0,0 +1,227 @@
.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
.import "qrc:/js/helper.js" as Helperjs
function requestFriends(login,database,rootwindow,callback){
// return array of friends
Helperjs.friendicaRequest(login,"/api/statuses/friends", rootwindow,function (obj){
var friends=JSON.parse(obj);
for (var i=0;i<friends.length;i++){ friends[i].isFriend=1}
callback(friends)
});
}
function requestGroups(login,database,rootwindow,callback){
// retrieve, save and return groups, currently not implemented
Helperjs.friendicaRequest(login,"/api/friendica/group_show",rootwindow, function (obj){
var groups=JSON.parse(obj);
for (var i=0;i<groups.length;i++){
updateGroupInDB(login,database,groups[i])
}
Helperjs.readData(database,"groups",callback)
});}
function getFriendsTimeline(login,database,contacts,rootwindow,callback){// retrieve and return timeline since last news, return contacts which are not friends for update (friends can be updated in Friendstab)
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
var parameter = "";
db.transaction( function(tx) {
var result = tx.executeSql('SELECT status_id from news WHERE username="'+login.username+'" ORDER BY status_id DESC LIMIT 1'); // check for last news id
try{parameter="&since_id="+result.rows.item(0).status_id;}catch(e){};})
var newContacts=[];
Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){
var news=JSON.parse(obj);
for (var i=0;i<news.length;i++){
if(contacts.indexOf(news[i].user.id)==-1 && !(inArray(newContacts,"id",news[i].user.id))){
news[i].user.isFriend=0;
newContacts.push(news[i].user);
}}
callback(news,newContacts)
})}
function storeNews(login,database,news,rootwindow,callback){
// save news after contacts download, call next function
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
for (var i=0;i<news.length;i++){
var ausdruck=news[i];
print('store news data for ' + news[i].id);
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+news[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(news[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=0, text="'+Qt.btoa(news[i].text)+'", truncated="'+news[i].truncated+'", created_at="'+Date.parse(cleanDate(news[i].created_at))+'", in_reply_to_status_id="'+news[i].in_reply_to_status_id+'", source="'+news[i].source+'", status_id="'+news[i].id+'", in_reply_to_user_id="'+news[i].in_reply_to_user_id+'", geo="'+news[i].geo+'", favorited="'+news[i].favorited+'", uid="'+news[i].user.id+'", statusnet_html="'+Qt.btoa(news[i].status_html)+'", statusnet_conversation_id="'+news[i].statusnet_conversation_id+'", attachments="'+news[i].attachments+'" where status_id="'+news[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,0,Qt.btoa(news[i].text),news[i].truncated,Date.parse(cleanDate(news[i].created_at)), news[i].in_reply_to_status_id, news[i].source, news[i].id,news[i].in_reply_to_user_id,news[i].geo,news[i].favorited, news[i].user.id,Qt.btoa(news[i].statusnet_html),news[i].statusnet_conversation_id, news[i].attachments,0,0,0])}})
}
getDirectMessage(login,database,rootwindow,callback)
}
function getDirectMessage(login,database,rootwindow,callback){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
Helperjs.friendicaRequest(login,"/api/direct_messages/all",rootwindow, function (obj){
var messages=JSON.parse(obj);
for (var i=0;i<messages.length;i++){
// print('store message data for '+JSON.stringify(messages[i]));
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+messages[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(messages[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=1, text="'+Qt.btoa(messages[i].text)+'", created_at="'+Date.parse(cleanDate(messages[i].created_at))+'", in_reply_to_status_id="", source="Friendica", status_id="'+messages[i].id+'", in_reply_to_user_id="", geo="", favorited="", uid="'+messages[i].sender.id+'", statusnet_html="'+Qt.btoa(messages[i].text)+'", statusnet_conversation_id="", attachments="'+messages[i].attachments+'" where status_id="'+messages[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,1,Qt.btoa(messages[i].text),0,Date.parse(cleanDate(messages[i].created_at)),, "Friendica", messages[i].id,,,, messages[i].sender.id,Qt.btoa(messages[i].text),,,0,0,0])}
});
}
})
getNotifications(login,database,rootwindow,callback)
}
function getNotifications(login,database,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/friendica/notifications", rootwindow,function (obj){
var messages=JSON.parse(obj);
for (var i=0;i<messages.length;i++){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
//print('store message data for '+JSON.stringify(messages[i]));
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+messages[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(messages[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=1, text="'+Qt.btoa(messages[i].text)+'", truncated="'+messages[i].truncated+'", created_at="'+Date.parse(cleanDate(messages[i].created_at))+'", in_reply_to_status_id="", source="'+messages[i].source+'", status_id="'+messages[i].id+'", in_reply_to_user_id="", geo="'+messages[i].geo+'", favorited="", uid="'+messages[i].sender.id+'", statusnet_html="'+Qt.btoa(messages[i].text)+'", statusnet_conversation_id="", attachments="'+messages[i].attachments+'" where status_id="'+messages[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,2,Qt.btoa(messages[i].msg_html),,Date.parse(cleanDate(messages[i].timestamp)),, messages[i].source, messages[i].id,,,, messages[i].sender.id,Qt.btoa(messages[i].msg_html),, messages[i].attachments],0,0,0)}});
}
})
newsfromdb(database,login.username,callback)
}
function newsfromdb(database,username,callback,contact,stop_time){
// return news before stop_time (used by More button), in brackets of 20 entries, or by specified contact
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
if (!stop_time){var stop="";
try{var rs = tx.executeSql('select created_at from news WHERE username="'+username+'" ORDER BY created_at DESC LIMIT 1');
stop="<="+rs.rows.item(0).created_at}catch(e){stop="<99999999999999"}}
else{var stop="<"+stop_time}
var contactfilter="";if(contact){contactfilter=" AND uid='"+contact+"'"}
var newsrs=tx.executeSql('select * from news WHERE username="'+username+'" AND created_at'+stop+contactfilter+' ORDER BY created_at DESC LIMIT 20');
var newsArray=[];
for(var i = 0; i < newsrs.rows.length; i++) {
newsArray.push(newsrs.rows.item(i));
Helperjs.readData(database,"contacts",function(userdata){
newsArray[i].user=userdata[0];
},"id",newsArray[i].uid);
if(newsArray[i].in_reply_to_user_id){
Helperjs.readData(database,"contacts",function(replytodata){
newsArray[i].reply_user=replytodata[0];
},"id",newsArray[i].in_reply_to_user_id)
}
}
callback(newsArray)});
}
function deleteNews(login,database,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/statuses/destroy?id="+newsid, rootwindow,function (obj){
var news=JSON.parse(obj);
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('delete news data for ' + newsid);
db.transaction( function(tx) {var result = tx.executeSql('DELETE from news where status_id ='+newsid); // delete news id
Helperjs.showMessage("Delete",result,rootwindow)});
})}
function retweetNews(login,database,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/statuses/retweet?id="+newsid, rootwindow,function (obj){
var answer=JSON.parse(obj);
Helperjs.showMessage("Repost",answer,rootwindow);
})}
function favorite(login,favorite,newsid,rootwindow){
// toggle favorites
if(favorite){ Helperjs.friendicaRequest(login,"/api/favorites/create?id="+newsid, rootwindow,function (obj){
var news=JSON.parse(obj);
})}
else {Helperjs.friendicaRequest(login,"/api/favorites/destroy?id="+newsid, rootwindow,function (obj){
var news=JSON.parse(obj);
})}
}
function likerequest(login,database,toggle,verb,newsid,rootwindow,callback){ // not tested
Helperjs.friendicaRequest(login,"/api/friendica/activity/"+verb+"?id="+newsid, rootwindow,function (obj){
var likeReturn=JSON.parse(obj);
if (likeReturn=="OK"){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {var result = tx.executeSql('UPDATE news SET '+verb+'d ='+toggle+' where status_id ='+newsid);
callback();
})}})
}
function like(login,database,toggle,verb,newsid,rootwindow,callback){
if(verb=="like"&& toggle==1){
likerequest(login,database,1,"like",newsid,rootwindow,callback);
likerequest(login,database,0,"undislike",newsid,rootwindow);}
if(verb=="dislike"&& toggle==1){
likerequest(login,database,1,"dislike",newsid,rootwindow,callback);
likerequest(login,database,0,"unlike",newsid,rootwindow);}
if(toggle==0){
likerequest(login,database,0,"un"+verb,newsid,rootwindow,callback);}
}
function attend(login,database,attend,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/friendica/activity/attend"+attend+"?id="+newsid, rootwindow,function (obj){
var attendReturn=JSON.parse(obj);
// print("attend: "+obj);
//if (attendReturn=="OK")
{
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {var result = tx.executeSql('UPDATE news SET attend="+attend+" where status_id ='+newsid);
callback();
})}})}
function requestConversation(login,database,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/conversation/show?id="+newsid,rootwindow, function (obj){
print(obj+JSON.stringify(obj));
var news=JSON.parse(obj);
for (var i=0;i<news.length;i++){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('store news data for ' + news[i].id);
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+news[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(news[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=0, text="'+Qt.btoa(news[i].text)+'", truncated="'+news[i].truncated+'", created_at="'+Date.parse(cleanDate(news[i].created_at))+'", in_reply_to_status_id="'+news[i].in_reply_to_status_id+'", source="'+news[i].source+'", status_id="'+news[i].id+'", in_reply_to_user_id="'+news[i].in_reply_to_user_id+'", geo="'+news[i].geo+'", favorited="'+news[i].favorited+'", uid="'+news[i].user.id+'", statusnet_html="'+Qt.btoa(news[i].status_html)+'", statusnet_conversation_id="'+news[i].statusnet_conversation_id+'", attachments="'+news[i].attachments+'" where status_id="'+news[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,0,Qt.btoa(news[i].text),news[i].truncated,Date.parse(cleanDate(news[i].created_at)), news[i].in_reply_to_status_id, news[i].source, news[i].id,news[i].in_reply_to_user_id,news[i].geo,news[i].favorited, news[i].user.id,Qt.btoa(news[i].statusnet_html),news[i].statusnet_conversation_id, news[i].attachments,0,0,0]);
}});
if(news[i].user.following!=true){
updateContactInDB(login,database,rootwindow,news[i].user)}
}
callback();
}
);}
function conversationfromdb(database,user,conversationId,callback){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
print('select * from news WHERE statusnet_conversation_id='+conversationId+' ORDER BY status_id DESC');
var newsrs=tx.executeSql('select * from news WHERE statusnet_conversation_id='+conversationId+' ORDER BY status_id DESC');
var newsArray=[];
for(var i = 0; i < newsrs.rows.length; i++) {
newsArray.push(newsrs.rows.item(i))
Helperjs.readData(database,"contacts",function(userdata){
newsArray[i].user=userdata[0];
},"id",newsArray[i].uid);
}
callback(newsArray);
});}
function inArray(list, prop, val) {
if (list.length > 0 ) {
for (var i in list) { if (list[i][prop] === val) {
return true;
}
}
} return false;
}
function cleanDate(date){
var cleanedDate= date.slice(0,3)+", "+date.slice(8,11)+date.slice(4,7)+date.slice(25,30)+date.slice(10,25);
return cleanedDate
}

View File

@ -0,0 +1,24 @@
WorkerScript.onMessage = function(msg) {
if(msg.appendnews!==true){ msg.model.clear()};
for (var j=0;j<msg.news.length;j++){
if (msg.news[j]) {
var newsitemobject=msg.news[j];
var seconds=(msg.currentTime-newsitemobject.created_at)/1000;
var timestring="";
if (seconds<60) {timestring=seconds+" "+qsTr("seconds") +" "+qsTr("ago");}
else if (seconds<90){timestring=Math.round(seconds/60)+" "+qsTr("minute") +" "+qsTr("ago");}
else if (seconds<3600){timestring=Math.round(seconds/60)+" "+qsTr("minutes") +" "+qsTr("ago");}
else if (seconds<5400){timestring=Math.round(seconds/3600)+" "+qsTr("hour") +" "+qsTr("ago");}
else if (seconds<86400){timestring=Math.round(seconds/3600)+" "+qsTr("hours") +" "+qsTr("ago");}
else if (seconds<129600){timestring=Math.round(seconds/86400)+" "+qsTr("day") +" "+qsTr("ago");}
else if (seconds<3888000){timestring=Math.round(seconds/86400)+" "+qsTr("days") +" "+qsTr("ago");}
else if (seconds<5832000){timestring=Math.round(seconds/3888000)+" "+qsTr("month") +" "+qsTr("ago");}
else if (seconds<69984000){timestring=Math.round(seconds/3888000)+" "+qsTr("months") +" "+qsTr("ago");}
else {timestring=Math.round(seconds/69984000)+" "+qsTr("years") +" "+qsTr("ago");}
var data=({"newsitemobject": newsitemobject,"dateDiff":timestring})}
// print("News:"+j+msg.news.length+JSON.stringify(data));
msg.model.append(data);}
if (j==msg.news.length){
msg.model.sync()
};
}

View File

@ -0,0 +1,15 @@
WorkerScript.onMessage = function(msg) {
if (msg.firstalbum==0){msg.model.clear();}
var limit=0; if (msg.albums.length-msg.firstalbum<20){limit=msg.albums.length} else{limit=msg.firstalbum+20}
for (var j=msg.firstalbum;j<limit;j++){
if (msg.albums[msg.firstalbum]) {
// print("album"+msg.albums[j].name);
if(msg.foreignPicture){
var albumname=msg.albums[j].name.trim();var albumlink=msg.albums[j].link
}else{
var albumname=msg.albums[j].toString();var albumlink=""}
msg.model.append({"albumlink":albumlink,"foreignPicture":msg.foreignPicture,"albumname":albumname});
msg.model.sync()
};
}
}

View File

@ -0,0 +1,223 @@
//.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
.import "qrc:/js/helper.js" as Helperjs
.import "qrc:/js/news.js" as Newsjs
// IMAGE FUNCTIONS
function requestList(login,database,rootwindow,callback) {
//get list of own images and call download function
Helperjs.friendicaRequest(login,"/api/friendica/photos/list", rootwindow,function (helperobject){
// print("return"+helperobject);
var obj=JSON.parse(helperobject);
Helperjs.readField("resourceID",database,"imageData",login.username,function(AllStoredImages){
for(var i=0;i< AllStoredImages.length;i++){
obj.splice(obj.indexOf(AllStoredImages[i]),1);
}
});
callback(obj);
})}
function dataRequest(login,photoID,database,rootwindow) {
// check if image exist and call download function
Helperjs.friendicaRequest(login,"/api/friendica/photo?photo_id="+photoID, rootwindow, function (obj){
try{ if(obj==""){currentImageNo=currentImageNo+1}else{
var image = JSON.parse(obj);
storeData(image,database,login)}}
catch (e){print("Data retrieval failure! "+ e+obj);}
});
}
function storeData(obj,database,login) { // store image data to DB
print('storeData() for ' + obj.filename)
try{sprite.destroy();}catch(e){}
if (obj.data==""){currentImageNo=currentImageNo+1}
else{
var filename=obj.filename;
// check if text name has valid image format ending, otherwise append appropriate ending
if(["jpg","png"].indexOf(filename.substring(filename.lastIndexOf(".")+1,filename.length))==-1){
// print("falscheEndung: "+filename.substring(filename.lastIndexOf(".")+1,filename.length));
{ if (obj.type=="image/jpeg") {obj["filename"]=filename+".jpg"}
if (obj.type=="image/png") {obj["filename"]=filename+".png"} }
print("Filename: "+obj.filename+filename)
}
if (filename==""){
if (obj.type=="image/jpeg") {obj["filename"]=obj["resource-id"]+".jpg"}
if (obj.type=="image/png") {obj["filename"]=obj["resource-id"]+".png"} }
print("Name for savebase64image: "+ obj.filename+" ResourceID: "+ obj["resource-id"]+obj.type)
// call image download function
saveBase64Image(obj,login.imagestore,function(obj,sprite){
//sprite.destroy(500);
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
print('... check if a object exists: '+obj["resource-id"])
var result = tx.executeSql('SELECT * from imageData where resourceID = "'+obj["resource-id"]+'"');
if(result.rows.length === 1) {// use update
print(obj["resource-id"] +' exists, update it')
result = tx.executeSql('UPDATE imageData SET username ="' +login.username+ '",id="'+obj.id+'", uid="'+obj.uid+'", contact_id="'+obj.contact_id+'", guid="'+obj.guid+'", created="'+obj.created+'", edited="'+obj.edited+'", datasize="'+obj.datasize+'", scale="'+obj.scale+'", profile="'+obj.profile+'", allow_cid="'+obj.allow_cid+'", allow_gid="'+obj.allow_gid+'", deny_cid="'+obj.deny_cid+'", deny_gid="'+obj.deny_gid+'", filename="'+obj.filename+'",title="'+obj.title+'", desc="'+obj.desc+'", type="'+obj.type+'", width="'+obj.width+'", height="'+obj.height+'", album="'+obj.album+'", location="file://'+login.imagestore+'", data="", where resourceID="'+obj["resource-id"]+'"');
} else {// use insert print('... does not exists, create it')
result = tx.executeSql('INSERT INTO imageData VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,obj.id,obj.uid,obj.contact_id,obj.guid, obj["resource-id"], obj.created,obj.edited, obj.title, obj.desc, obj.album, obj.filename, obj.type, obj.height, obj.width, obj.datasize, ,obj.scale, obj.profile,obj.allow_cid,obj.allow_gid,obj.deny_cid,obj.deny_gid,'file://'+login.imagestore]);
print("Inserted");}
});
})}}
function saveBase64Image(obj,storagedirectory,callback) {
// create image component from base64 code and save it
print("Storing "+storagedirectory+obj.filename+obj.width+"x"+obj.height);
var maxSize=Math.max(fotostab.width,fotostab.height);
var helpwidth=(obj.width<maxSize)?obj.width:maxSize;
var helpheight=(obj.height<maxSize)?obj.height:maxSize;
if (obj.width>obj.height){ //landscape
helpheight=helpwidth*obj.height/obj.width
} else { //portrait
helpwidth=helpheight*obj.width/obj.height
}
var component=Qt.createComponent("qrc:/qml/PhotoPlaceholder.qml");
var sprite = component.createObject(fotostab, {"x":0,"y":0,"imageName":storagedirectory+obj.filename ,"width":helpwidth,"height":helpheight,"source": "data:image/jpeg;base64,"+obj.data,"downloadtype":"picture"});
// print("sprite: "+sprite);
callback(obj,sprite)
}
function deleteImageData(database,user,field,selection,callback) { // does nothing useful at the moment
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print(' delete Image Data() for ' + field +"="+selection)
db.transaction( function(tx) {
result = tx.executeSql('UPDATE imageData SET data="" where '+ field +'="'+selection+'"');
callback(result)})
}
function requestFriendsAlbumPictures(friend,rootwindow,callback){
// screenscraping of albums page of contact without user and password
Helperjs.friendicaWebRequest(friend.url.replace("profile","photos"),rootwindow,function(photohtml){
var photoarray=[];
var arr = photohtml.split("sidebar-photos-albums-li");
for (var i=2;i<arr.length;i++){
var albumlink = arr[i].substring(arr[i].indexOf('http'),arr[i].indexOf('class')-2);
var albumname=arr[i].substring(arr[i].indexOf('/span')+6,arr[i].indexOf('</a>')-1);
var album={'link':albumlink,'name':albumname}
photoarray.push(album);
}
//print("Album"+JSON.stringify(photoarray));
callback(photoarray)
})
}
function requestFriendsPictures(link,rootwindow,callback){
// screenscraping of pictures page for given album
Helperjs.friendicaWebRequest(link,rootwindow,function(photohtml){
var photoarray=[];
var basehtml=photohtml.substring(photohtml.indexOf('<base')+12,photohtml.indexOf('/>',photohtml.indexOf('<base'))-2);
// old theme
if (photohtml.indexOf("photo-album-image-wrapper-end")>-1){ //theme 1
var arr = photohtml.split("photo-album-image-wrapper-end");}
// other themes
if (photohtml.indexOf("photo-album-wrapper")>-1){ //theme 2
var photoarea=photohtml.substring(photohtml.indexOf("photo-album-wrapper"),photohtml.indexOf("photo-album-end"))
var arr = photoarea.split("</a>");}
for (var i=0;i<arr.length-1;i++){
var photoname=arr[i].substring(arr[i].lastIndexOf('alt')+5,arr[i].lastIndexOf('title')-2);
var thumblink=arr[i].substring(arr[i].lastIndexOf('<img')+10,arr[i].lastIndexOf('alt')-2);
var imagetype=thumblink.substring(thumblink.lastIndexOf("."));
var photolink=thumblink.substring(0,thumblink.length-imagetype.length-2)+"-0"+imagetype
if(thumblink.substring(0,4)!=="http"){thumblink=basehtml+thumblink}
if(photolink.substring(0,4)!=="http"){photolink=basehtml+photolink}
var photo={'link':photolink,'name':photoname,'thumb':thumblink}
photoarray.push(photo);
}
callback(photoarray)
})
}
// CONFIG FUNCTIONS
function initDatabase(database) { // initialize the database object
var db =Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('initDatabase()'+database[0]+database[1]+database[2]+database[3])
db.transaction( function(tx) {
print('... create table')
tx.executeSql('CREATE TABLE IF NOT EXISTS imageData(username TEXT,id INT, uid INT, contact_id INT, guid TEXT, resourceID TEXT, created TEXT,edited TEXT, title TEXT, desc TEXT, album TEXT,filename TEXT, type TEXT, height INT, width INT, datasize INT, data BLOB, scale INT, profile INT, allow_cid TEXT, allow_gid TEXT, deny_cid TEXT, deny_gid TEXT,location TEXT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS config(server TEXT, username TEXT, password TEXT, imagestore TEXT, maxnews INT, timerInterval INT, newsViewType TEXT,isActive INT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS news(username TEXT, messagetype INT, text TEXT, truncated 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,attachments TEXT, liked INT, disliked INT, attend TEXT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS contacts(username TEXT, id INT, name TEXT, screen_name TEXT, location TEXT,description TEXT, profile_image BLOB, url TEXT, protected TEXT, followers_count INT, friends_count INT, created_at TEXT, favourites_count TEXT, utc_offset TEXT, time_zone TEXT, statuses_count INT, following TEXT, verified TEXT, statusnet_blocking TEXT, notifications TEXT, statusnet_profile_url TEXT, cid INT, network TEXT, isFriend INT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS groups(username TEXT, groupname TEXT, gid INT, members TEXT)');
})}
function storeConfig(database,obj) { // stores config to DB
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('storeConfig() for ' + obj.username)
print('database: ' + database[0]);
db.transaction( function(tx) {
print('... check if a object exists: '+obj.username)
var result = tx.executeSql('SELECT * from config WHERE username="'+obj.username+'"');
if(result.rows.length === 1) {// use update
print(obj.username +' exists, update it');
var result2 = tx.executeSql('UPDATE config SET server="'+obj.server+'",password="'+obj.password+'", imagestore="'+obj.imagestore+'", maxnews="+obj.maxnews+", isActive=0 WHERE username="'+obj.username +'"');
var result3 = tx.executeSql('UPDATE config SET isActive=1 WHERE username !="'+obj.username +'"');
var result4 = tx.executeSql('UPDATE config SET maxnews='+obj.maxnews);
} else {// use insert print('... does not exists, create it')
var result2 = tx.executeSql('INSERT INTO config VALUES (?,?,?,?,?,?,?,?)', [obj.server, obj.username, obj.password, obj.imagestore, obj.maxnews, 0,"list",0]);
var result3 = tx.executeSql('UPDATE config SET isActive=1 WHERE username !="'+obj.username +'"');
var result4 = tx.executeSql('UPDATE config SET maxnews='+obj.maxnews);
print("Inserted");}
});}
function getServerConfig(login,rootwindow,callback){
// check server with given credentials
try {Helperjs.friendicaRequest(login,"/api/statusnet/config",rootwindow, function (obj){
var serverconfig = JSON.parse(obj);
var serverconfigString="import QtQuick 2.0; import QtQuick.Dialogs 1.2; MessageDialog{ visible: true; title:'Server';standardButtons: StandardButton.Ok;text: 'SUCCESS! \nName: "+serverconfig.site.name+"\nLanguage: "+serverconfig.site.language+
"\nEmail: "+serverconfig.site.email+"\nTimezone: "+serverconfig.site.timezone+"\nClosed: "+serverconfig.site.closed+
"\nText limit: "+serverconfig.site.textlimit+"\nShort Url length: "+serverconfig.site.shorturllength+
"\nFriendica version: "+serverconfig.site.friendica.FRIENDICA_VERSION+"\nDFRN version: "+serverconfig.site.friendica.DFRN_PROTOCOL_VERSION +
"\nDB Update version: "+serverconfig.site.friendica.DB_UPDATE_VERSION+"'}";
callback(serverconfigString);
})}
catch (e){callback (e);
}}
function readConfig(database,callback,filter,filtervalue) { // reads config
print('readConfig()')
if (filter){var where = " WHERE "+ filter +" = '" + filtervalue+"'";} else { var where="";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3],initDatabase(database));
db.transaction( function(tx) {
var tables = tx.executeSql("SELECT * FROM sqlite_master WHERE type='table'");
if (tables.rows.length==0){print("no database");callback("")} else {
print('... read from database '+where)
var rs = tx.executeSql('select * from config'+where);
var rsArray=[];
if (rs.rows.length>0){
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i))
}
var rsObject={server:rsArray[0].server,username:rsArray[0].username, password:rsArray[0].password,imagestore:rsArray[0].imagestore,maxnews:rsArray[0].maxnews,isActive:rsArray[0].isActive};
} else {
var rsObject=""
}
callback(rsObject);}}
);
}
function readActiveConfig(database){
var obj;
readConfig(database,function(config){
obj=config},"isActive", 0);
return obj;
}
function deleteConfig(database,userobj,callback) { // delete user data from DB
print('deleteConfig()')
if (userobj){var where = " WHERE username='"+ userobj.username+"' and server='"+userobj.server+"'";} else { return "no user selected!";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
print('... read from database '+where)
var rs = tx.executeSql('delete * from config'+where);
print(rs.toString);
callback(rs);
});
}

View File

@ -0,0 +1,251 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import "qrc:/js/service.js" as Service
import "qrc:/js/layout.js" as Layoutjs
import "qrc:/js/helper.js" as Helperjs
import "qrc:/qml"
StackView{
id: configStack
anchors.fill:parent
focus: true
Keys.onReleased: if (event.key === Qt.Key_Back && stackView.depth > 1) {
stackView.pop(); event.accepted = true;
}
initialItem: Flickable{
width:root.width-5*mm
height:root.height-12*mm
contentHeight: configBackground.height
boundsBehavior: Flickable.StopAtBounds
Rectangle{
id:configBackground
color: "grey"
width:parent.width
height:Math.max(80*mm,root.height-12*mm)
focus: true
ComboBox{
y:mm
width: root.width/2
model: ListModel{
id: usermodel
}
onCurrentIndexChanged:{
try {Service.readConfig(db,function(obj){
servername.text=obj.server;
username.text= obj.username;
password.text=Qt.atob(obj.password);
imagestore.text=obj.imagestore;
maxNewsText.text=obj.maxnews;
if( obj.isActive==0){isActiveField.text=qsTr("yes")} else {isActiveField.text=qsTr("no")}
},"username",currentText)}
catch (e){print(e)}
}
}
Text {
text: "Server"
x: 4*mm; y: 10*mm
}
Text {
text: "User"
x: 4*mm; y: 20*mm
}
Text {
text: "Password"
x: 4*mm; y: 30*mm
}
Text {
text: "Image dir."
x: 4*mm; y: 40*mm
}
Text {
text: "Max. News"
x: 4*mm; y: 50*mm
}
Text {
text: "is Active"
x: 4*mm; y: 60*mm
}
Rectangle{color: "white"; x: 25*mm; y: 10*mm; width: root.width/2; height: 5*mm;}
Flickable {
id: servernameFlickable
x: 25*mm; y: 10*mm; width: root.width/2; height: 5*mm;
contentWidth: servername.paintedWidth
contentHeight: servername.paintedHeight
clip: true
TextEdit {
id: servername
width: servernameFlickable.width
height: servernameFlickable.height
focus: true
text:"https://..."
//wrapMode: TextEdit.NoWrap
//validator: RegExpValidator { regExp: /^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$/}
// onEditingFinished:{}
onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,servernameFlickable)
}
}
Rectangle{
color: "white"
x: 25*mm; y: 20*mm; width: root.width/2; height: 5*mm;
TextInput {
id: username
anchors.fill: parent
selectByMouse: true
}
}
Rectangle{
color: "white"
x: 25*mm; y: 30*mm; width: root.width/2; height: 5*mm;
TextInput {
id: password
anchors.fill: parent
selectByMouse: true
echoMode: TextInput.PasswordEchoOnEdit
}
}
Rectangle{color: "white"; x: 25*mm; y: 40*mm; width: root.width/2-9*mm; height: 5*mm;}
Flickable {
id: imagestoreFlickable
x: 25*mm; y: 40*mm; width: root.width/2-9*mm; height: 5*mm;
clip: true
TextInput {
id: imagestore
width: imagestoreFlickable.width
height: imagestoreFlickable.height
wrapMode: TextEdit.NoWrap
onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,imagestoreFlickable)
}
}
Slider{ id: maxNews
x:37*mm; y: 50*mm;width: root.width/6;height:5*mm
minimumValue: 0;maximumValue:100000; stepSize: 1000
}
Rectangle{color: "white"; x: 25*mm; y: 50*mm; width: 9*mm; height: 5*mm;
TextEdit{id:maxNewsText;
anchors.fill: parent
verticalAlignment:TextEdit.AlignRight
text:maxNews.value
focus: true
selectByMouse: true
}
}
Rectangle{
x: 25*mm; y: 60*mm; width: root.width/2; height: 5*mm;
Text{
id: isActiveField
anchors.fill: parent
}
}
FileDialog {
id: imagestoreDialog
title: "Please choose a directory"
folder: shortcuts.pictures
selectFolder: true
onAccepted: {
var imagestoreString=imagestoreDialog.folder.toString(); imagestoreString=imagestoreString.replace(/^(file:\/{2})/,"")+"/"
imagestore.text=imagestoreString;
console.log("You chose: " + imagestoreDialog.folder)
}
onRejected: {
console.log("Canceled")
}
}
Button {
x: root.width/2+18*mm; y: 40*mm; width: 7*mm; height: 5*mm;
text: "..."
onClicked:
{imagestoreDialog.open()}
}
Button {
x: 25*mm; y: 70*mm; width: implicitWidth; height: implicitHeight;
text: "Update"
onClicked:{
var userconfig={server: servername.text, username: username.text, password:Qt.btoa(password.text), imagestore:imagestore.text,maxnews:maxNewsText.text};
var errormessage="";
if (servername.text==""){errormessage=qsTr("No server given! ")}
//if (!servername.acceptableInput){errormessage+=qsTr("Server name not valid! ")}
else if (username.text==""){errormessage+=qsTr("No username given! ")}
else if (password.text=="") {errormessage+=qsTr("No password given! ")}
else if (imagestore.text=="") {errormessage+=qsTr("No image directory given!")}
else if (maxNewsText.text=="") {errormessage+=qsTr("No maximum news number given!")}
else {errormessage=""}
if (errormessage=="") {Service.storeConfig(db,userconfig);
Service.readConfig(db,function(userconfig){Service.getServerConfig(userconfig,configBackground, function(obj){
var serverString=obj;
var serverconfigObject=Qt.createQmlObject(serverString,configBackground,"serverconfigOutput");
usermodel.append({text:username.text});
//reset values
root.login=userconfig;
root.contactlist=[];
root.news=[]
root.newContacts=[]
root.currentContact= 0
root.contactLoadType= ""
root.currentIndex=0;
newstab.active=true;
})},"isActive",0);
//try {newstab.newsModel.clear();
//friendstab.friendsModel.clear();
//photostab.photogroupModel.clear();} catch(e){}
}
else {Helperjs.show("Error", errormessage,root)}
}}
Button {
x: root.width/2+2*mm; y: mm; width: 5*mm; height: 5*mm;
text: "-"
onClicked:{
var userconfig={server: servername.text, username: username.text, password: Qt.btoa(password.text)};
Service.deleteConfig(db,userconfig);
}}
Button {
x: root.width/2+8*mm; y: mm; width: 5*mm; height: 5*mm;
text: "+"
onClicked:{
servername.text="https://..."
username.text=""
password.text=""
imagestore.text=""
maxNews.value=1000
isActiveField.text=""
}
}
Button {
x: root.width/2+14*mm; y: mm; width: 5*mm; height: 5*mm;
text: "?"
onClicked:{
configStack.push({item:"qrc:/qml/InfoBox.qml"});
}
}
Component.onCompleted: {
try{Helperjs.readData(db,"config",function(users){
users.sort(function(obj1, obj2) {
return obj1.isActive - obj2.isActive;
});
for (var i=0; i<users.length;i++){
if (users[i]) {usermodel.append({text:users[i].username});};
};})}
catch (e){print(e)}
}
}
}
}

View File

@ -0,0 +1,128 @@
import QtQuick 2.0
import QtQuick.Controls 1.3
import "qrc:/js/service.js" as Service
import "qrc:/js/layout.js" as Layoutjs
Item {
id: friendComponent
property date createdAtDate: new Date(friend.created_at)
Rectangle {
id: wrapper
width: 16*mm
height: 15*mm
border.color: "grey"
color:"white"
Image {
id: photoImage
x:1
y:1
width: 10*mm
height:10*mm
source:"file://"+ friend.profile_image
}
Label {
id: namelabel
x: 1
width: wrapper.width-2
elide: Text.ElideRight
height: 3*mm
text: friend.screen_name
anchors.topMargin: 0
anchors.left: photoImage.left
color: "#303030"
font.pixelSize: 3*mm
anchors.top: photoImage.bottom
}
Button{
id:infobutton
width: 5*mm
height: 5*mm
text:"?"
anchors.left: photoImage.right
anchors.leftMargin: 3
anchors.topMargin: 3
anchors.top: parent.top
onClicked:{
print("State: "+ friendComponent.state+friendsView.contentY);
friendComponent.state="large"}
}
Rectangle{
id: detailsrectangle
anchors.top: namelabel.bottom
anchors.topMargin: 2*mm
opacity: 0
Text{
id:namelabeltext
anchors.top: parent.top
width: root.width-10*mm
height: namelabeltext.implicitHeight
font.pixelSize: 3*mm
textFormat:Text.RichText
wrapMode: Text.Wrap
text:"<b>"+qsTr("Description")+": </b> "+Qt.atob(friend.description)+"<br> <b>"+qsTr("Server Type")+":</b> "+friend.location+"<br> <b>"+qsTr("Posts")+":</b> "+friend.statuses_count+
"<br> <b>"+qsTr("URL")+":</b> <a href='"+ friend.url+"'>"+friend.url+"</a><br> <b>"+
qsTr("Created at")+":</b> "+createdAtDate.toLocaleString(Qt.locale())
onLinkActivated: {
Qt.openUrlExternally(link)}
}
Row{
anchors.top: namelabeltext.bottom
anchors.topMargin: 2*mm
spacing:4
Button{
id:photobutton
text:"Photos"
visible:friend.location=="Friendica"? 1:0
onClicked:{root.currentIndex=2;
fotostab.active=true;
root.fotoSignal(friend) ;
}
}
Button{
id:messagebutton
text:"Messages"
onClicked:{root.currentIndex=0;
newstab.active=true;
root.messageSignal(friend.id) ;
}
}
Button{id:dmbutton
visible: friend.following=="true"?true:false
text: "DM"
onClicked:{root.currentIndex=0;
newstab.active=true;
root.directmessageSignal(friend.screen_name);
}
}
Button{
id: closeButton
text: "close"
onClicked:{friendComponent.state=""}
}
}
}
}
states: [
State {
name: "large"
PropertyChanges { target: namelabel; font.pixelSize: 4*mm; width:friendsView.width; text:Qt.atob(friend.name)+" (@"+friend.screen_name+")"}
PropertyChanges { target: friendComponent; z: 2 }
PropertyChanges { target: wrapper; width:friendsView.width;height:friendsView.height -2*mm-1}
PropertyChanges { target: photoImage; width:15*mm;height:15*mm }
PropertyChanges { target:friendComponent.GridView.view ;contentY:friendComponent.y;contentX:friendComponent.x;interactive:false}
PropertyChanges { target: detailsrectangle; opacity:1 }
}
]
}

View File

@ -0,0 +1,66 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import "qrc:/js/service.js" as Service
import "qrc:/js/helper.js" as Helperjs
import "qrc:/js/news.js" as Newsjs
import "qrc:/qml"
Rectangle {
function showFriends(username){try {friendsModel.clear()} catch(e){print(e)};
Helperjs.readData(db, "contacts",function(friendsobject){
for (var j=0;j<friendsobject.length;j++){
friendsModel.append({"friend":friendsobject[j]});
}},"username", username)
}
color: "white"
Button {
id: updateFriendsButton
text: qsTr("Update")
anchors.top: parent.top
anchors.right: parent.right
onClicked: {
try {friendsModel.clear()} catch(e){print(e)};
root.contactLoadType="friends";
Newsjs.requestFriends(root.login,db,root,function(nc){
root.newContacts=nc
})}
}
ProgressBar{
id: newContactsProgress
width: 15*mm
height: updateFriendsButton.height
anchors.top: parent.top
anchors.right:updateFriendsButton.left
anchors.rightMargin:mm
visible: (root.currentContact!=root.newContacts.length)?true:false
value: root.currentContact/root.newContacts.length
}
Rectangle{
x: 2*mm; y:updateFriendsButton.height+2*mm
width:root.width-5*mm
height:root.height-5*mm
GridView {
id: friendsView
anchors.fill: parent
anchors.bottomMargin: 12*mm
clip: true
cellHeight: 16*mm
cellWidth: 17*mm
add: Transition {
NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
}
model: friendsModel
delegate: FriendComponent { }
}
}
ListModel{
id: friendsModel
}
Component.onCompleted: {
root.friendsSignal.connect(showFriends);
showFriends(login.username)
}
}

View File

@ -0,0 +1,22 @@
import QtQuick 2.0
import QtQuick.Controls 1.2
Rectangle{
color:"white"
width:infoBoxText.contentWidth
height:infoBoxText.contentHeight
Text{id:infoBoxText
textFormat: Text.RichText
wrapMode: Text.Wrap
text: "<b>Friendiqa v0.001 </b><br>Licensed under GPL 3<br> "+
"Sourcecode: <a href='https://github.com/LubuWest/Friendiqa'>https://github.com/LubuWest/Friendica</a><br>"+
"C++ code by <a href='https://kirgroup.com/profile/fabrixxm'>Fabio</a><br>"+
"QML and Javascript code by <a href='https://freunde.ma-nic.de/profile/marco'>Marco</a>"
onLinkActivated:{
Qt.openUrlExternally(link)}
}
Button{
text:qsTr("Close")
onClicked:{configStack.pop()}
anchors.top:infoBoxText.bottom
}
}

View File

@ -0,0 +1,132 @@
// message.qml
// message with buttons
import QtQuick 2.0
import QtQml 2.2
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
import QtQuick.LocalStorage 2.0
//import "../qml"
import "qrc:/js/service.js" as Service
Item{
id:messageSend
property var login
property string parentId: ""
property string reply_to_user:""
property string attachImageURL: "";
property int directmessage: 0;
property var contacts: []
// title: parentId !== "" ? qsTr("Reply to "+reply_to_user) : qsTr("New post")
function statusUpdate(title,status,in_reply_to_status_id,attachImageURL) {
xhr.url= login.server + "/api/statuses/update.xml";
xhr.setLogin(login.username+":"+Qt.atob(login.password));
print("login: "+login.username+":"+Qt.atob(login.password));
xhr.clearParams();
xhr.setParam("source", "Friendiqa");
xhr.setParam("status", status);
if (parentId!="") {xhr.setParam("in_reply_to_status_id", parentid)};
if (title!=="") {xhr.setParam("title", title)};
if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )};
xhr.post();
}
function dmUpdate(title,text,replyto,screen_name,attachImageURL) {
xhr.url= login.server + "/api/direct_messages/new.xml";
xhr.setLogin(login.username+":"+Qt.atob(login.password));
xhr.clearParams();
xhr.setParam("text", text);
xhr.setParam("screen_name", screen_name);
if (parentId!="") {xhr.setParam("replyto", replyto)};
if (title!=="") {xhr.setParam("title", title)};
if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )};
xhr.post();
}
Column {
id:messageColumn
spacing: 2
TextField {
id: titleField
width: parent.width
placeholderText: qsTr("Title (optional)")
visible: messageSend.parentId === ""
}
TextArea {
id: bodyField
width: parent.width
height: 30*mm
wrapMode: TextEdit.Wrap
}
CheckBox{
id:dmCheckbox
text:"DM"
enabled: false
checked: (directmessage==1)?true:false
onClicked:{
if(dmCheckbox.checkedState==Qt.Checked){directmessage=1}
else if(dmCheckbox.checkedState==Qt.Unchecked){directmessage=0}
}
}
Row{
spacing:2
Button {
id: cancelButton
text: qsTr("Cancel")
onClicked: {newsStack.pop()}
}
Button {
id: attachButton
text: qsTr("Attach")
onClicked: {imageAttachmentDialog.open()}
}
Button{
id:contactButton
text:qsTr("cc")
visible:(directmessage==0)
onClicked:{
var contactitems="";
for (var i=0;i<contacts.length;i++){
contactitems=contactitems+"MenuItem{text:'"+contacts[i]+"'; onTriggered: bodyField.append(' @"+contacts[i]+"')}"
}
var menuString="import QtQuick.Controls 1.4; Menu {"+contactitems+"}";
// print(menuString);
var contactlistObject=Qt.createQmlObject(menuString,messageSend,"contactmenuOutput")
contactlistObject.popup() }
}
Button {
id: sendButton
text: qsTr("Send")
onClicked: {
print("login: "+login.server+login.username);
if (directmessage==0){
statusUpdate(titleField.text,bodyField.text,messageSend.parentId,attachImageURL.toString());}
else {dmUpdate( titleField.text,bodyField.text,"",messageSend.reply_to_user) }
newsStack.pop()
}
}
}
}
FileDialog {
id: imageAttachmentDialog
title: "Please choose a picture"
folder: shortcuts.pictures
selectFolder: false
onAccepted: {
attachImageURL=imageAttachmentDialog.fileUrl;
var imageAttachementObject=Qt.createQmlObject('import QtQuick 2.0; Image {source:"'+attachImageURL.toString()+'"; width: 30*mm; height: 30*mm;fillMode: Image.PreserveAspectFit}',messageColumn,"attachedImage");
console.log("You chose: " + attachImageURL)
}
onRejected: {
console.log("Canceled")
}
}
}

View File

@ -0,0 +1,154 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import QtQuick.LocalStorage 2.0 as Sql
import "qrc:/js/news.js" as Newsjs
import "qrc:/js/helper.js" as Helperjs
Item {
property string newstabStatus:"news"
function showNews(newsToShow){
newsBusy.running=false;
var currentTime= new Date();
var msg = {'currentTime': currentTime, 'model': newsModel,'news':newsToShow};
newsWorker.sendMessage(msg);
}
function onFriendsMessages(friend){print(" Friend "+friend);
newstabStatus="friendmessage";
Newsjs.newsfromdb(db,root.login.username, function(dbnews){showNews(dbnews)},friend)
}
function onDirectMessage(friend){
newsStack.push({item:"qrc:/qml/MessageSend.qml",properties:{"reply_to_user": friend,"directmessage":1,"login":root.login}});
}
function cleanNews(database){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
var maxnewsrs = tx.executeSql("SELECT DISTINCT maxnews FROM config");
var maxnews=maxnewsrs.rows.item(0);
var newscountrs = tx.executeSql('SELECT COUNT(*) from news');
var newscount = newscountrs.rows.item(0);
if (newscount>maxnews){var lastvalidtimers= tx.executeSql('select created_at from news ORDER BY created_at DESC LIMIT ' +(newscount-maxnews));
var lastvalidtime=lastvalidtimers.rows.item(-1);
var deleters = tx.executeSql('DELETE from news WHERE created_at<'+lastvalidtime)}
});
Qt.quit()
}
StackView{
id: newsStack
anchors.fill:parent
focus: true
Keys.onReleased: if (event.key === Qt.Key_Back && stackView.depth > 1) {
stackView.pop(); event.accepted = true;
}
initialItem:Rectangle {
color: "white"
width:root.width-2*mm
height:root.height-8*mm
Button {
id: newMessageButton
text: qsTr("+")
anchors.top: parent.top
anchors.right: parent.right
onClicked: {
Helperjs.readField("screen_name",root.db,"contacts",root.login.username,function(friends){
newsStack.push({item:"qrc:/qml/MessageSend.qml",properties:{"contacts": friends,"login":root.login}})
},"isFriend",1);
}
}
Button {
id: quitButton
text: qsTr("Quit")
anchors.top: parent.top
anchors.right: newMessageButton.left
onClicked: {cleanNews(root.db)}
}
Component { id:footerComponent
Rectangle{
border.color: "#EEEEEE"
border.width: 1
width:parent.width
height:6*mm
Text{
font.pixelSize: 1.5*mm
anchors.centerIn: parent
text:qsTr("More")
}
MouseArea{anchors.fill:parent
onClicked:{
var currentTime= new Date();
if(newstabStatus=="news"){
var lastnews_id=newsModel.get(newsModel.count-1).newsitemobject.created_at;
Newsjs.newsfromdb(root.db,root.login.username, function(news){
var msg = {'currentTime': currentTime, 'model': newsModel,'news':news,'appendnews':true};
newsWorker.sendMessage(msg);
},false,lastnews_id)}
else if(newstabStatus=="friendmessage"){
Newsjs.newsfromdb(root.db,root.login.username, function(news){
var msg = {'currentTime': currentTime, 'model': newsModel,'news':news,'appendnews':true};
newsWorker.sendMessage(msg);
},newsModel.get(newsModel.count-1).newsitemobject.uid,newsModel.get(newsModel.count-1).newsitemobject.created_at)}
}}
}
}
ListView {
id: newsView
anchors.fill: parent
anchors.topMargin: 8*root.mm
anchors.leftMargin: 3*root.mm; anchors.rightMargin: root.mm
anchors.bottomMargin: 1*root.mm
clip: true
spacing: 0
footer: footerComponent
model: newsModel
delegate: Newsitem{}
}
ListModel{id: newsModel}
WorkerScript {
id: newsWorker
source: "qrc:/js/newsworker.js"
}
Button {
id: update
anchors.top: parent.top
anchors.right: quitButton.left
text: "Update"
onClicked: { //try{newsModel.clear()} catch(e){}
newsBusy.running=true;
root.contactLoadType="news";
Newsjs.getFriendsTimeline(login,db,contactlist,newstab,function(ns,nc){
root.news=ns;root.newContacts=nc;root.currentContact=0;
if (ns.length==0){
Newsjs.getDirectMessage(root.login,root.db,root,function(dbnews){showNews(dbnews)});
newsBusy.running=false}
})}
}
BusyIndicator{
id: newsBusy
anchors.centerIn:update
//anchors.right: update.left
//anchors.top:parent.top
width:7*mm
height: 7*mm
}
Component.onCompleted: {
root.messageSignal.connect(onFriendsMessages);
root.directmessageSignal.connect(onDirectMessage);
root.newsSignal.connect(showNews);
try{newsModel.clear()} catch(e){}
Newsjs.newsfromdb(root.db,root.login.username, function(dbnews){
showNews(dbnews)
})
}
}
}
}

View File

@ -0,0 +1,261 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "qrc:/js/news.js" as Newsjs
import "qrc:/js/layout.js" as Layoutjs
Item {
id: newsitem
width: newsView.width
height:Math.max((itemMessage.height+createdAtLabel.height+4*mm),profileImage.height+user_name.height+mm)
property bool show_full: false
property string conversation_id: ""
property string attachments:""
property string attending: ""
onAttendingChanged: {attendLabel.visible=true;
attendLabel.text= qsTr("attending: ")+ qsTr(attending)}
signal replyto(string parent_id)
Rectangle{width:newsitem.width; height: 1; anchors.bottom: newsitem.bottom; color:"light grey"}
Rectangle{
width:newsitem.width
height:newsitem.height-1
color: (newsitemobject.directmessage)?"#ffe6e6" : "white"
Column {
id: authorcolumn
width: 8*mm
Image {
id:profileImage
source: "file://"+newsitemobject.user.profile_image
x:1
width: 7*mm
height: 7*mm
MouseArea{
anchors.fill: parent
onPressAndHold: { newsmenu.popup()}
}
onStatusChanged: if (profileImage.status == Image.Error) {source="qrc:/images/defaultcontact.jpg"}
}
Label {
id:user_name
color: "grey"
//height:3.5*mm
width:parent.width
font.pixelSize: 1.5*mm
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: Qt.atob(newsitemobject.user.name)
}
}
Column {
id:newscolumn
anchors.left: authorcolumn.right
Row{
spacing: 5
Label {
color: "grey"
text: if (newsitemobject.messagetype==0){qsTr("Source: ")+newsitemobject.source
} else if (newsitemobject.messagetype==1){ qsTr("Direct Message")} else {" Notification"}
font.pixelSize: 1.5*mm
}
Label {
id:createdAtLabel
color: "grey"
height:3.5*mm
font.pixelSize: 1.5*mm
horizontalAlignment: Label.AlignRight
text: dateDiff
}
CheckBox {
id:favoritedCheckbox
style: CheckBoxStyle {
background: Rectangle {
implicitWidth: 6*mm
implicitHeight:2*mm
color:"white"
}
indicator:
Rectangle{x:3*mm
width: 3*mm
implicitHeight:2*mm
Text{
anchors.centerIn: parent
color:control.checked?"black":"grey"
text:"\u2605"
}}
}
checked:(newsitemobject.favorited>0)
Text{
anchors.left: parent.right
color: "grey"
font.pixelSize: 1.5*mm
text: (newsitemobject.favorited>0)? newsitemobject.favorited+qsTr(" Favorites"):""
}
onClicked:{
if(favoritedCheckbox.checkedState==Qt.Checked)
{Newsjs.favorite(login,true,newsitemobject.status_id,root)}
else
if(favoritedCheckbox.checkedState==Qt.Unchecked)
{Newsjs.favorite(login,false,newsitemobject.status_id,root)}
}
}
}
Text {
color: "#404040"
linkColor: "light green"
id: itemMessage
textFormat: Text.RichText
text: Qt.atob(newsitemobject.statusnet_html)
width: newsitem.width-8*mm-2
height: implicitHeight
wrapMode: Text.Wrap
onLinkActivated:{ print("link "+link);
Qt.openUrlExternally(link)}
}
Row {
CheckBox{id:likeCheckbox
height:3*mm
width:8*mm
style: CheckBoxStyle {
background: Rectangle {
implicitWidth: 7*mm
implicitHeight: 3*mm
color:"white"
}
indicator:
Rectangle{
implicitWidth: 3*mm
implicitHeight:3*mm
color:control.checked?"yellow":"white"
x: 5*mm
Text{
font.pixelSize: 1.5*mm
color:"grey"
text:":-)"
}}
}
onClicked: {
if(likeCheckbox.checked==true){Newsjs.like(root.login,root.db,1,"like",newsitemobject.status_id,root);dislikeCheckbox.checked=false}
else{Newsjs.like(root.login,root.db,0,"like",newsitemobject.status_id,root)}}
}
CheckBox{id: dislikeCheckbox
height:3*mm
width:8*mm
style: CheckBoxStyle {
background: Rectangle {
implicitWidth: 7*mm
implicitHeight:3*mm
color:"white"
}
indicator:
Rectangle{
implicitWidth: 3*mm
implicitHeight:3*mm
color:control.checked?"yellow":"white"
x:5*mm
Text{
font.pixelSize: 1.5*mm
color:"grey"
text:":-("
}}
}
onClicked: {
if (dislikeCheckbox.checked==true){Newsjs.like(root.login,root.db,1,"dislike",newsitemobject.status_id);likeCheckbox.checked=false}
else {Newsjs.like(root.login,root.db,0,"dislike",newsitemobject.status_id,root)}}
}
Label {
id:replytoLabel
color: "grey"
height:3.5*mm
font.pixelSize: 1.5*mm
horizontalAlignment: Label.AlignRight
text: try {qsTr("In reply to ")+newsitemobject.reply_user.screen_name
}catch(e){" "}
}
Label {
id:attendLabel
visible: false
color: "grey"
height:3.5*mm
font.pixelSize: 1.5*mm
horizontalAlignment: Label.AlignRight
text: qsTr("attending: ")+ qsTr(attending)
}
}
}
Menu {
id:newsmenu
MenuItem {
text: qsTr("Reply")
onTriggered: {
newsStack.push({item:"qrc:/qml/MessageSend.qml",properties:{"reply_to_user": newsitemobject.user.screen_name,"parentId":newsitemobject.status_id}});
}
}
MenuItem {
text: qsTr("DM")
onTriggered: {
root.directmessageSignal(newsitemobject.user.screen_name);
}
}
MenuItem {
text: qsTr("Repost")
onTriggered: {
Newsjs.retweetNews(root.login,db,newsitemobject.status_id,root,function(reply){
print(reply);
})
}
}
MenuItem {
text: qsTr("Conversation")
onTriggered: {
Newsjs.requestConversation(root.login,db,newsitemobject.status_id,root,function(){
var currentTime= new Date();
Newsjs.conversationfromdb(db,root.login.username,newsitemobject.statusnet_conversation_id, function(newsarray){
newsModel.clear();
var msg = {'currentTime': currentTime, 'model': newsModel,'news':newsarray,'latestmessage':0};
newsWorker.sendMessage(msg);
});
}
)}
}
Menu{
title: qsTr("Attending")
MenuItem{text:qsTr("yes")
onTriggered: {Newsjs.attend(root.login,db,"yes",newsitemobject.status_id,root,function(){
newsitem.attending="yes";
attendLabel.visible=true})}
}
MenuItem{text:qsTr("maybe")
onTriggered: {Newsjs.attend(root.login,db,"maybe",newsitemobject.status_id,root,function(){
newsitem.attending="maybe"})}
}
MenuItem{text:qsTr("no")
onTriggered: {Newsjs.attend(root.login,db,"no",newsitemobject.status_id,root,function(){
newsitem.attending="no"})}
}
}
MenuItem {
text: qsTr("Delete")
onTriggered: {
Newsjs.deleteNews(root.login,db,newsitemobject.status_id,root,function(reply){
print(JSON.stringify(reply));
newsModel.remove(index);
})
}
}
}
}}

View File

@ -0,0 +1,100 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Controls 1.2
Package {
Item { id: stackItem; Package.name: 'stack'; z: stackItem.PathView.z;width:16.5*mm;height:16.5*mm}
Item { id: listItem; Package.name: 'list'; width: root.width-1*mm; height: root.height-8*mm; }
Item { id: gridItem; Package.name: 'grid';}
Item {
id: photoWrapper
width: 16.5*mm; height: 16.5*mm
z: stackItem.PathView.z
property string hqphotolink: photoLink
Rectangle {
id: placeHolder
color: 'lightblue'; antialiasing: true
anchors.fill:parent
//width: parent.width; height: parent.height;
}
BusyIndicator { anchors.centerIn: parent; running: realImage.status != Image.Ready }
Image {
id: realImage;
// property string hqphotolink: photoLink
width: photoWrapper.width; height: photoWrapper.height
antialiasing: true;
asynchronous: true
cache: false
fillMode: Image.PreserveAspectFit;
source: imageLocation
// onStatusChanged: if (realImage.status == Image.Ready) print(realImage.paintedHeight+"x"+realImage.paintedWidth)
}
Rectangle{
id:phototextRectangle
color:"black"
z:3
opacity: 0.5
width:phototext.contentWidth
height: phototext.contentHeight
anchors.bottom: photoWrapper.bottom
}
Text {
id:phototext
z:4
text: photoDescription.trim()
width:15*mm
anchors.bottom: photoWrapper.bottom
color: "white"
font.pixelSize: 2*mm
wrapMode:Text.Wrap
}
MouseArea {
width: realImage.paintedWidth; height: realImage.paintedHeight; anchors.centerIn: realImage
onClicked: {
if (albumWrapper.state == 'inGrid') {
gridItem.GridView.view.currentIndex = index;
//print("photoLink"+realImage.photoLink)
albumWrapper.state = 'fullscreen'
} else {
gridItem.GridView.view.currentIndex = index;
albumWrapper.state = 'inGrid'
}
}
}
states: [
State {
name: 'stacked'; when: albumWrapper.state == ''
ParentChange { target: photoWrapper; parent: stackItem; }//x: 1*mm; y: 1*mm }
PropertyChanges { target: photoWrapper; opacity: stackItem.PathView.onPath ? 1.0 : 0.0 }
PropertyChanges { target: phototext; opacity: 0.0 }
PropertyChanges { target: phototextRectangle; opacity: 0.0 }
},
State {
name: 'inGrid'; when: albumWrapper.state == 'inGrid'
ParentChange { target: photoWrapper; parent: gridItem; x: 1*mm; y: 1*mm;}
PropertyChanges { target: phototext; opacity: 1.0 }
PropertyChanges { target: phototextRectangle; opacity: 0.5 }
PropertyChanges { target: placeHolder; opacity: 1.0 }
},
State {
name: 'fullscreen'; when: albumWrapper.state == 'fullscreen'
ParentChange {
target: photoWrapper; parent: listItem; x: 1; y: 1;
width: root.width-mm; height: root.heigh-8*mm
}
PropertyChanges { target: placeHolder; opacity: 0.0 }
PropertyChanges { target: realImage; source: photoWrapper.hqphotolink}
PropertyChanges { target: phototext; anchors.bottom: realImage.bottom}
PropertyChanges { target: phototext; width:realImage.width }
PropertyChanges { target: phototextRectangle; anchors.bottom: realImage.bottom }
PropertyChanges { target: realImage; width: Math.min(listItem.width,sourceSize.width);height: Math.min(listItem.height,sourceSize.height) }
}
]
}
}

View File

@ -0,0 +1,26 @@
import QtQuick 2.0
import "qrc:/js/helper.js" as Helperjs
Image {
id:photoPlaceholder
property string imageName:"x.jpg"
property string downloadtype:""
fillMode: Image.PreserveAspectFit
onStatusChanged: {
if (photoPlaceholder.status == Image.Ready) {
//print("Photo width"+width+" height"+height+" Ratio "+ fillMode);
var saveprocess=photoPlaceholder.grabToImage(function(result){
var saveresult=result.saveToFile(imageName.toString());
if (saveresult){
if ((downloadtype=="picture")&&(newImages.length>0)){
photoPlaceholder.destroy();
currentImageNo=currentImageNo+1
}
else if ((downloadtype=="contact")&&(root.newContacts.length>0))
{
photoPlaceholder.destroy(100);
root.currentContact=root.currentContact+1
}
}});
}}}

View File

@ -0,0 +1,135 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
import QtQml.Models 2.1
import "qrc:/js/service.js" as Service
import "qrc:/js/helper.js" as Helperjs
import "qrc:/qml"
Rectangle {
id:fotorectangle
width:root.width-mm
height:root.height-5*mm
color: '#fff'
property var newImages:[]
property int currentImageNo: 0
//onLoginChanged:{var msg = {'model': photogroupModel,'albums':[],'firstalbum':0,'foreignPicture':false};
// photoWorker.sendMessage(msg);
//}
onNewImagesChanged:{if(newImages.length>0){ Service.dataRequest(root.login,newImages[currentImageNo],root.db,fotorectangle);newImagesProgress.visible=true //download first image
} }
onCurrentImageNoChanged:{ if(currentImageNo<newImages.length){Service.dataRequest(root.login,newImages[currentImageNo],root.db,fotorectangle)};
if(currentImageNo==newImages.length){newImagesProgress.visible=false;showOwnFotos();
newImages=[];currentImageNo=0}
// download next image if photoplaceholder is finished saving
}
ProgressBar{
id: newImagesProgress
width: 15*mm
height: updatePhotolist.height
anchors.top: parent.top
anchors.right:updatePhotolist.left
anchors.rightMargin:mm
visible: false
value: currentImageNo/newImages.length
}
Button{
id: updatePhotolist
anchors.top: parent.top
anchors.right:showFotos.left
anchors.rightMargin:mm
text: qsTr("Update")
onClicked: {
Service.requestList(root.login,root.db, fotostab,function(obj){
newImages=obj;
})}}
Button{
id: showFotos
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin:2*mm
text: qsTr("Show")
onClicked: {showOwnFotos()}
}
DelegateModel{
id: visualphotoModel
delegate: PhotogroupComponent{}
model: photogroupModel
}
ListModel{
id: photogroupModel
}
GridView {
id: albumgridview
cellWidth: 17*mm
cellHeight: 17*mm
x: mm;y:8*mm
width: parent.width-2*mm; height: parent.height-9*mm
clip: true
model: visualphotoModel.parts.album
footer:
Rectangle{
border.color: "#EEEEEE"
border.width: 1
width:12*mm
height:6*mm
Text{
font.pixelSize: 1.5*mm
anchors.centerIn: parent
text:qsTr("More")
}
MouseArea{anchors.fill:parent
onClicked:{
var lastalbum_id=photogroupModel.get(photogroupModel.count-1);
if(photogroupModel.get(photogroupModel.count-1).foreignPictures==false){Service.requestFriendsAlbumPictures(friend,fotostab,function(albums){
var msg = {'model': photogroupModel,'albums':albums,'firstalbum':lastalbum_id+1,'foreignPicture':true};
photoWorker.sendMessage(msg); })}
else { Helperjs.readField("album",root.db, "imageData",root.login.username,function(albums){
var msg = { 'model': photogroupModel,'albums':albums,'foreignPicture': false,'firstalbum':lastalbum_id+1};
photoWorker.sendMessage(msg)})}
}}}
}
Rectangle { id: photoBackground; color: 'light grey'; width: parent.width; height: parent.height; opacity: 0; visible: opacity != 0.0 }
ListView { anchors.fill: parent; model: visualphotoModel.parts.browser; interactive: false }
Button {
id: backButton
text: qsTr("Back")
x: parent.width - backButton.width - 3*mm
y: -backButton.height - 4*mm
onClicked: {photoBackground.opacity=0}
// visible: Qt.platform.os !== "android"
}
ListView {anchors.fill: parent; model: visualphotoModel.parts.fullscreen; interactive: false }
WorkerScript{id: photoWorker;source: "qrc:/js/photoworker.js"}
function showOwnFotos(){
try {photogroupModel.clear()}catch (e){print(e)}
Helperjs.readField("album",root.db, "imageData",root.login.username,function(albums){
if (albums[0]) {
var msg = { 'model': photogroupModel,'albums':albums,'firstalbum':0,'foreignPicture': false};
photoWorker.sendMessage(msg);
};
})
}
function onFriendsFotos(friend){print("Friend "+friend.url);
try {photogroupModel.clear()}catch (e){print(e)}
Service.requestFriendsAlbumPictures(friend,fotostab,function(albums){
var msg = {'model': photogroupModel,'albums':albums,'firstalbum':0,'foreignPicture':true};
photoWorker.sendMessage(msg);
})
}
Component.onCompleted: { root.fotoSignal.connect(onFriendsFotos);}
}

View File

@ -0,0 +1,119 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Controls 1.3
import QtQml.Models 2.1
import "qrc:/js/service.js" as Service
import "qrc:/js/helper.js" as Helperjs
Package {
Item {
Package.name: 'browser'
GridView {
id: photosGridView; model: visualModel.parts.grid; width: albumgridview.width; height: albumgridview.height
cellWidth: 16.5*mm; cellHeight: 16.5*mm; interactive: false;anchors.margins:2*mm
onCurrentIndexChanged: photosListView.positionViewAtIndex(currentIndex, ListView.Contain)
}
}
Item {
Package.name: 'fullscreen'
ListView {
id: photosListView; model: visualModel.parts.list; orientation: Qt.Horizontal
width: parent.width; height: parent.height; interactive: false
onCurrentIndexChanged: photosGridView.positionViewAtIndex(currentIndex, GridView.Contain)
highlightRangeMode: ListView.StrictlyEnforceRange; snapMode: ListView.SnapOneItem
}
}
Item {
Package.name: 'album'
id: albumWrapper; width: 16.5*mm; height: 16.5*mm //-albumtext.contentHeight
DelegateModel {
id: visualModel; delegate: PhotoComponent { }
model: photoModel
}
PathView {
id: photosPathView;
model: visualModel.parts.stack;
pathItemCount: 1
anchors.centerIn: parent;
path: Path {
PathAttribute { name: 'z'; value: 9999.0 }
PathLine { x: 1; y: 1 }
PathAttribute { name: 'z'; value: 0.0 }
}
}
Rectangle{
color:"black"
opacity: 0.5
width:albumtext.contentWidth
height: albumtext.contentHeight
anchors.bottom: albumWrapper.bottom
}
Text {
id:albumtext
text: albumname //foreignPicture ? album.name.trim() : album
width:albumWrapper.width-1*mm
height: albumtext.contentHeight
wrapMode:Text.Wrap
color: "white"
font.family: "Monospace"
font.pixelSize: 2*mm
anchors.bottom: albumWrapper.bottom
}
ListModel{
id: photoModel
}
Component.onCompleted:{
try {photoModel.clear()}catch (e){print(e)}
if(foreignPicture){
//print("Albumlink"+album.link);
Service.requestFriendsPictures(albumlink,fotostab,function(obj){
if (obj) {
for (var k=0;k<obj.length;k++){
//print("Photomodel:"+obj[k].thumb+obj[k].name+obj[k].link);
photoModel.append({"imageLocation": obj[k].thumb,"photoDescription":obj[k].name,"photoLink":obj[k].link})
};
}
})}
else{
Helperjs.readData(db,"imageData",function(obj){
// obj.sort(function(obj1,obj2){return obj1.data-obj2.data});
if (obj) {
for (var k=0;k<obj.length;k++){
// print("Photomodel:"+obj[k].location+obj[k].filename);
photoModel.append({"imageLocation": obj[k].location+obj[k].filename,"photoDescription":obj[k].filename,"photoLink":obj[k].location+obj[k].filename})
};
}
},"album",albumname)}
}
MouseArea {
anchors.fill: parent
onClicked: albumWrapper.state = 'inGrid'
}
states: [
State {
name: 'inGrid'
PropertyChanges { target: photosGridView; interactive: true }
PropertyChanges { target: photoBackground; opacity: 1 }
PropertyChanges { target: backButton; onClicked: albumWrapper.state = ''; y: 6 }
},
State {
name: 'fullscreen'; extend: 'inGrid'
PropertyChanges { target: photosGridView; interactive: false }
PropertyChanges { target: photosListView; interactive: true }
PropertyChanges { target: photoBackground; opacity: 1 }
PropertyChanges { target: backButton; y: -backButton.height - 8 }
}
]
} //album Ende
} //Package Ende
//item Ende

View File

@ -0,0 +1,111 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Window 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import QtQml.Models 2.1
import "qrc:/js/news.js" as Newsjs
import "qrc:/js/service.js" as Service
import "qrc:/js/layout.js" as Layoutjs
import "qrc:/js/helper.js" as Helperjs
import "qrc:/qml"
TabView{
id:root
tabPosition: Qt.BottomEdge
width: Screen.desktopAvailableWidth
height: Screen.desktopAvailableHeight
property var db: ["Photos", "1.0", "Stores Friendica data", 100000000]
property var login: Service.readActiveConfig(db)
property var contactlist: []
property real mm: Screen.pixelDensity
signal messageSignal(var friend)
signal fotoSignal(var friend)
signal directmessageSignal(var friend)
signal newsSignal(var news)
signal friendsSignal(var username)
currentIndex: (login=="")? 3:0
property var news:[]
property var newContacts:[]
property int currentContact: 0
property string contactLoadType: ""
onLoginChanged:{Newsjs.newsfromdb( db,login.username, function(dbnews){
newsSignal(dbnews)
})}
onNewContactsChanged:{if(newContacts.length>0){// download first contact image and update db
//print("newcontact"+JSON.stringify(newContacts[0]));
updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])}
}
onCurrentContactChanged:{// download next contact image after photoplaceholder is finished saving and update db
if(currentContact<newContacts.length){
updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])}
else if(currentContact==newContacts.length){//newImagesProgress.visible=false;
if (newContacts.length==0) {}
else if (contactLoadType=="news"){
Newsjs.storeNews(login,db,news,root,function(dbnews){
root.newsSignal(dbnews);
root.newContacts=[];
root.currentContact=0;
root.news=[]
})// show news
}
else if (contactLoadType=="friends"){
root.friendsSignal(login.username);
// show friends
Helperjs.readField("id",db,"contacts",login.username,function(contacts){contactlist=contacts;
root.newContacts=[];
root.currentContact=0},"isFriend",1) }
}
}
function updateContactInDB(login,database,isFriend,contact){// for newstab and friendstab
var imagename=login.imagestore+contact.screen_name+".jpg";
var component=Qt.createComponent("qrc:/qml/PhotoPlaceholder.qml");
var sprite = component.createObject(root, {"fillMode": "Image.PreserveAspectFit","x":root.width,"y":50,"imageName":imagename,"source": contact.profile_image_url,"downloadtype":"contact"});
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
var result;
db.transaction( function(tx) {
result = tx.executeSql('SELECT * from contacts where id = '+contact.id); // check for news id
if(result.rows.length === 1) {// use update
result = tx.executeSql('UPDATE contacts SET username="'+login.username+'", id='+contact.id+', name="'+Qt.btoa(contact.name)+'", screen_name="'+contact.screen_name+'", location="'+contact.location+'",description="'+Qt.btoa(contact.description)+'", profile_image="'+imagename+'", url="'+contact.url+'" , protected="'+contact.protected+'", followers_count='+contact.followers_count+', friends_count='+contact.friends_count+', created_at="'+ Newsjs.cleanDate(contact.created_at)+'", favourites_count="'+contact.favorites_count+'", utc_offset="'+contact.utc_offset+'", time_zone="'+contact.time_zone+'", statuses_count='+contact.statuses_count+', following="'+contact.following+'", verified ="'+contact.verified+'", statusnet_blocking="'+contact.statusnet_blocking+'", notifications="'+contact.notifictions+'", statusnet_profile_url="'+contact.statusnet_profile_url+'", cid='+contact.cid+', network="'+contact.network+'", isFriend='+isFriend+' where id='+contact.id);
} else {// use insert
result = tx.executeSql('INSERT INTO contacts VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,contact.id,Qt.btoa(contact.name),contact.screen_name,contact.location,Qt.btoa(contact.description),imagename,contact.url,contact.protected,contact.followers_count, contact.friends_count,Newsjs.cleanDate(contact.created_at),contact.favorites_count,contact.utc_offset,contact.time_zone,contact.statuses_count,contact.following,contact.verfied,contact.statusnet_blocking,contact.notifications,contact.statusnet_profile_url,contact.cid,contact.network,isFriend]);}
});
}
Component.onCompleted: {
if (login==""){Service.initDatabase(db);
}
Helperjs.readField("id",db,"contacts",login.username,function(contacts){contactlist=contacts},"isFriend",1)
}
Tab{
title: qsTr("News")
id: newstab
property string newstabStatus:"news"
source: "qrc:/qml/NewsTab.qml"
}
Tab{
title: qsTr("Friends")
id: friendstab
source: "qrc:/qml/FriendsTab.qml"
}
Tab{
title: qsTr("Photos")
id: fotostab
source: "qrc:/qml/PhotoTab.qml"
}
Tab{
title: qsTr("Config")
source: "qrc:/qml/ConfigTab.qml"
}
}

View File

@ -0,0 +1,23 @@
<RCC>
<qresource prefix="/">
<file>js/layout.js</file>
<file>js/photoworker.js</file>
<file>js/service.js</file>
<file>qml/FriendComponent.qml</file>
<file>qml/MessageSend.qml</file>
<file>qml/Newsitem.qml</file>
<file>qml/PhotoComponent.qml</file>
<file>qml/PhotogroupComponent.qml</file>
<file>qml/PhotoPlaceholder.qml</file>
<file>qml/friendiqa.qml</file>
<file>qml/PhotoTab.qml</file>
<file>qml/ConfigTab.qml</file>
<file>qml/FriendsTab.qml</file>
<file>qml/NewsTab.qml</file>
<file>js/news.js</file>
<file>js/newsworker.js</file>
<file>js/helper.js</file>
<file>images/defaultcontact.jpg</file>
<file>qml/InfoBox.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,19 @@
#include <QApplication>
#include <QtQml/QQmlEngine>
#include <QtQuick>
#include "xhr.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QQuickView view;
XHR* xhr = XHR::instance();
view.rootContext()->setContextProperty("xhr", xhr);
view.setSource(QUrl("qrc:/qml/friendiqa.qml"));
view.show();
view.connect(view.rootContext()->engine(), SIGNAL(quit()), &app, SLOT(quit()));
return app.exec();
}

View File

@ -0,0 +1,90 @@
#include "uploadableimage.h"
#include <QBuffer>
#include <QDebug>
#include <QFileInfo>
#include <QUrl>
void UploadableImage::setSource(const QString &a) {
if (a != m_source) {
m_source = a;
//m_base64 = "";
m_mimetype = "";
m_filename = "";
qDebug() << "UploadableImage::setSource : " << m_source;
if (m_source=="") {
emit sourceChanged();
//emit base64Changed();
emit mimetypeChanged();
emit filenameChanged();
return;
}
QImage fullimage = QImage(QUrl(m_source).toLocalFile());
if (fullimage.width() > 800 || fullimage.height() > 800) {
if (fullimage.width() > fullimage.height()) {
m_image = fullimage.scaledToWidth(800);
} else {
m_image = fullimage.scaledToHeight(800);
}
} else {
m_image = fullimage;
}
qDebug() << "UploadableImage::setSource : " << m_image.width() << "x" << m_image.height();
emit sourceChanged();
QFileInfo fi(m_source);
m_filename = fi.fileName();
emit filenameChanged();
QString filetype = fi.suffix().toUpper();
if (filetype!="PNG" && filetype!="JPG") {
filetype = "JPG";
}
qDebug() << "UploadableImage::setSource : " << "Saving as " << filetype;
m_mimetype = "image/"+filetype.toLower();
emit mimetypeChanged();
/*
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_image.save(&buffer, filetype.toLatin1().constData());
QString b64 = QString::fromLatin1(byteArray.toBase64().data());
for(int k=0; k<b64.length(); k+=76) {
m_base64 += b64.mid(k,76) + "\n";
}
m_base64 = m_base64.trimmed();
emit base64Changed();
*/
}
}
QString UploadableImage::source() const {
return m_source;
}
//QString UploadableImage::base64() const {
// return m_base64;
//}
QString UploadableImage::filename() const {
return m_filename;
}
QString UploadableImage::mimetype() const {
return m_mimetype;
}
QByteArray UploadableImage::bytes() {
QByteArray byteArray;
QBuffer buffer(&byteArray);
m_image.save(&buffer, "PNG");
return byteArray;
}

View File

@ -0,0 +1,40 @@
#ifndef UPLOADABLEIMAGE_H
#define UPLOADABLEIMAGE_H
#include <QObject>
#include <QQuickItem>
#include <QImage>
class UploadableImage : public QObject
{
Q_OBJECT
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
//Q_PROPERTY(QString base64 READ base64 NOTIFY base64Changed)
Q_PROPERTY(QString filename READ filename NOTIFY filenameChanged)
Q_PROPERTY(QString mimetype READ mimetype NOTIFY mimetypeChanged)
Q_PROPERTY(QByteArray bytes READ bytes)
public:
void setSource(const QString &a);
QString source() const;
//QString base64() const;
QString filename() const;
QString mimetype() const;
QByteArray bytes();
signals:
void sourceChanged();
//void base64Changed();
void filenameChanged();
void mimetypeChanged();
private:
QString m_source;
QImage m_image;
//QString m_base64;
QString m_filename;
QString m_mimetype;
};
#endif // UPLOADABLEIMAGE_H

View File

@ -0,0 +1,168 @@
#include "xhr.h"
#include <QHttpPart>
#include <QTextCodec>
#include <QUrlQuery>
#include "uploadableimage.h"
XHR *XHR::instance()
{
static XHR xhr;
return &xhr;
}
XHR::XHR(QObject *parent) : QObject(parent)
{
request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
}
void XHR::setUrl(QString url)
{
if (url!=m_url) {
m_url = url;
emit urlChanged();
}
}
void XHR::setLogin(QString login)
{
if (login!=m_login) {
m_login = login;
emit loginChanged();
}
}
QString XHR::url() const
{
return m_url;
}
QString XHR::login() const
{
return m_login;
}
void XHR::setParam(QString name, QString value)
{
params.insert(name, value);
}
void XHR::setImageFileParam(QString name, QString url)
{
files.insert(name, url);
}
void XHR::clearParams()
{
files.clear();
params.clear();
}
void XHR::get()
{
QUrlQuery query;
QHashIterator<QString, QString> i(params);
while(i.hasNext()) {
i.next();
query.addQueryItem(i.key(), i.value());
}
QUrl requrl(m_url);
requrl.setQuery(query);
QByteArray loginData = m_login.toLocal8Bit().toBase64();
QString headerData = "Basic " + loginData;
request.setRawHeader("Authorization", headerData.toLocal8Bit());
request.setUrl(requrl);
reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &XHR::onReplySuccess);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onReplyError(QNetworkReply::NetworkError)));
connect(reply, &QNetworkReply::readyRead, this, &XHR::onReadyRead);
}
void XHR::post()
{
qDebug() << "start post to " << m_url;
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHashIterator<QString, QString> iparams(params);
while(iparams.hasNext()) {
iparams.next();
qDebug() << "\t add param " << iparams.key() << " : " << iparams.value();
QHttpPart textPart;
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + iparams.key() + "\""));
textPart.setBody(iparams.value().toUtf8());
multiPart->append(textPart);
}
UploadableImage uimg;
QHashIterator<QString, QString> ifiles(files);
while(ifiles.hasNext()) {
ifiles.next();
uimg.setSource(ifiles.value());
qDebug() << "\t image: " << uimg.mimetype() << ", " << ifiles.key();
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(uimg.mimetype()));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + ifiles.key() + "\"; filename=\""+uimg.filename()+"\""));
imagePart.setBody(uimg.bytes());
multiPart->append(imagePart);
}
QByteArray loginData = m_login.toLocal8Bit().toBase64();
QString headerData = "Basic " + loginData;
request.setRawHeader(QByteArray("Authorization"), headerData.toLocal8Bit());
request.setUrl(m_url);
reply = manager.post(request, multiPart);
qDebug() << "\t request sent";
connect(reply, &QNetworkReply::finished, this, &XHR::onReplySuccess);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onReplyError(QNetworkReply::NetworkError)));
connect(reply, &QNetworkReply::readyRead, this, &XHR::onReadyRead);
connect(reply, &QNetworkReply::sslErrors, this, &XHR::onSSLError);
qDebug() << "\t reply signals connected";
}
void XHR::onReplyError(QNetworkReply::NetworkError code)
{
qDebug() << code;
emit this->error( bufferToString(), (int) code);
reply->deleteLater();
}
void XHR::onReplySuccess()
{
qDebug() << "!";
emit this->success( bufferToString() );
reply->deleteLater();
}
void XHR::onReadyRead()
{
qDebug() << ".";
buffer += reply->readAll();
}
void XHR::onSSLError(const QList<QSslError> &errors)
{
qDebug() << "XHR::onSSLError :" ;
QListIterator<QSslError> ierrs(errors);
while(ierrs.hasNext()) {
qDebug() << "\t" << ierrs.next().errorString();
}
}
QString XHR::bufferToString()
{
return QTextCodec::codecForName("utf-8")->toUnicode(buffer);
}

View File

@ -0,0 +1,60 @@
#ifndef XHR_H
#define XHR_H
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QObject>
class XHR : public QObject
{
Q_OBJECT
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QString login READ login WRITE setLogin NOTIFY loginChanged)
public:
static XHR *instance();
explicit XHR(QObject *parent = 0);
void setUrl(QString url);
// void setLogin(QString login);
QString url() const;
QString login() const;
signals:
void urlChanged();
void loginChanged();
void success(QString data);
void error(QString data, int code);
public slots:
void setLogin(QString login);
void setParam(QString name, QString value);
void setImageFileParam(QString name, QString url);
void clearParams();
void post();
void get();
private slots:
void onReplyError(QNetworkReply::NetworkError code);
void onReplySuccess();
void onReadyRead();
void onSSLError(const QList<QSslError> &errors);
private:
QByteArray buffer;
QString m_url;
QString m_login;
QHash<QString, QString> params;
QHash<QString, QString> files;
QNetworkAccessManager manager;
QNetworkRequest request;
QNetworkReply *reply;
QString bufferToString();
};
#endif // XHR_H

View File

@ -0,0 +1,38 @@
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = friendiqa
CONFIG += debug
QT += qml quick gui widgets
SOURCES += common/friendiqa.cpp \
common/uploadableimage.cpp \
common/xhr.cpp
RESOURCES = application.qrc
OTHER_FILES += qml/friendiqa.qml \
translations/*.ts \
qml/*.qml
js/*.js
# German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the
# following TRANSLATIONS line. And also do not forget to
# modify the localized app name in the the .desktop file.
TRANSLATIONS += translations/friendiqa-de.ts
HEADERS += \
common/uploadableimage.h \
common/xhr.h

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,12 @@
WorkerScript.onMessage = function(msg) {
msg.model.clear();
for (var j=0;j<msg.albums.length;j++){
if (msg.albums[j]) {
var albumobject=msg.albums[j];
var data=({"albumobject": albumobject,"foreignPicture": msg.foreignPicture})}
// print("Albums:"+j+msg.albums.length+JSON.stringify(data));
msg.model.append(data);}
if (j==msg.albums.length){
msg.model.sync()
};
}

View File

@ -0,0 +1,80 @@
.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
function friendicaRequest(login,api,rootwindow,callback) {
var xhrequest= new XMLHttpRequest();
xhrequest.onreadystatechange = function() {
if (xhrequest.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
} else if(xhrequest.readyState === XMLHttpRequest.DONE) {
try{ if (xhrequest.responseText!=""){
callback(xhrequest.responseText)
}else{
showMessage("Error",api+" NO RESPONSE",rootwindow)
callback(xhrequest.responseText)
}
}
catch (e){
showMessage("Error", api+" "+e,rootwindow)
}
}
}
xhrequest.open("GET", login.server+api,true,login.username,Qt.atob(login.password));
xhrequest.send();
}
function friendicaWebRequest(url,rootwindow,callback) {
var xhrequest = new XMLHttpRequest();
xhrequest.onreadystatechange = function() {
if (xhrequest.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
} else if(xhrequest.readyState === XMLHttpRequest.DONE) {
try{ callback(xhrequest.responseText);
}
catch (e){
showMessage("Error",url+" "+e, rootwindow)
}
}
}
xhrequest.open("GET", url,true);
xhrequest.send();
}
function readData(database,table,callback,filter,filtervalue) { // reads and applies data from DB
if (filter){
var where = " WHERE "+ filter +" = '" + filtervalue+"'";
} else { var where="";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
// print('select * from '+table+where);
var rsArray=[];
var rs = tx.executeSql('select * from '+table+where);
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i))
}
callback(rsArray);
});
}
function readField(field,database,table, username, callback,filter,filtervalue) { // reads and applies data from DB
if (filter){
var where = " AND "+ filter +" = '" + filtervalue+"'";
} else { var where="";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
// print('... read from database ' + field)
var rsArray=[];
print('select DISTINCT '+field+' from '+table+' WHERE username="'+username+'"'+where+' ORDER BY '+field+' ASC');
var rs = tx.executeSql('select DISTINCT '+field+' from '+table+' WHERE username="'+username+'"'+where+' ORDER BY '+field+' ASC');
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i)[field])
}
callback(rsArray);
});
}
function showMessage(header,message,rootwindow){
var messageString='import QtQuick 2.0; import QtQuick.Dialogs 1.2; MessageDialog{ visible: true; title:"'+header+'";standardButtons: StandardButton.Ok; text:" '+message+'"}';
var messageObject=Qt.createQmlObject(messageString,rootwindow,"messageOutput");
}

View File

@ -0,0 +1,44 @@
function showFriends(db) {
Service.readActiveConfig(db,function(login){
Service.requestFriends(login.url,login.user,login.password,displayFriends);
});
}
function displayFriends(obj){
for (var i=0; i<obj.length; i++){
print(obj[i]);
if (obj[i]) {friendsModel.append({"friendName": obj[i]});
};
}}
function ensureVisibility(c,f)
{
if (f.contentX >= c.x)
f.contentX = c.x;
else if (f.contentX+f.width <= c.x+c.width)
f.contentX = c.x+c.width-f.width;
if (f.contentY >= c.y)
f.contentY = c.y;
else if (f.contentY+f.height <= c.y+c.height)
f.contentY = c.y+c.height-f.height;
}
function createObject(objectQml,qmlParameters,parentitem,callback) {
var component = Qt.createComponent(objectQml);
if (component.status === Component.Ready || component.status === Component.Error)
finishCreation(component,qmlParameters,parentitem,callback);
else
component.statusChanged.connect(finishCreation(qmlParameters));
}
function finishCreation(component,qmlParameters,parentitem,callback) {
if (component.status === Component.Ready) {
var createdObject = component.createObject(parentitem, qmlParameters);
if (createdObject === null)
print("Error creating image"); }
else if (component.status === Component.Error)
print("Error loading component:"+component.errorString());
else {print("created")}
callback(createdObject);
}

View File

@ -0,0 +1,227 @@
.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
.import "qrc:/js/helper.js" as Helperjs
function requestFriends(login,database,rootwindow,callback){
// return array of friends
Helperjs.friendicaRequest(login,"/api/statuses/friends", rootwindow,function (obj){
var friends=JSON.parse(obj);
for (var i=0;i<friends.length;i++){ friends[i].isFriend=1}
callback(friends)
});
}
function requestGroups(login,database,rootwindow,callback){
// retrieve, save and return groups, currently not implemented
Helperjs.friendicaRequest(login,"/api/friendica/group_show",rootwindow, function (obj){
var groups=JSON.parse(obj);
for (var i=0;i<groups.length;i++){
updateGroupInDB(login,database,groups[i])
}
Helperjs.readData(database,"groups",callback)
});}
function getFriendsTimeline(login,database,contacts,rootwindow,callback){// retrieve and return timeline since last news, return contacts which are not friends for update (friends can be updated in Friendstab)
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
var parameter = "";
db.transaction( function(tx) {
var result = tx.executeSql('SELECT status_id from news WHERE username="'+login.username+'" ORDER BY status_id DESC LIMIT 1'); // check for last news id
try{parameter="&since_id="+result.rows.item(0).status_id;}catch(e){};})
var newContacts=[];
Helperjs.friendicaRequest(login,"/api/statuses/friends_timeline"+parameter, rootwindow,function (obj){
var news=JSON.parse(obj);
for (var i=0;i<news.length;i++){
if(contacts.indexOf(news[i].user.id)==-1 && !(inArray(newContacts,"id",news[i].user.id))){
news[i].user.isFriend=0;
newContacts.push(news[i].user);
}}
callback(news,newContacts)
})}
function storeNews(login,database,news,rootwindow,callback){
// save news after contacts download, call next function
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
for (var i=0;i<news.length;i++){
var ausdruck=news[i];
print('store news data for ' + news[i].id);
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+news[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(news[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=0, text="'+Qt.btoa(news[i].text)+'", truncated="'+news[i].truncated+'", created_at="'+Date.parse(cleanDate(news[i].created_at))+'", in_reply_to_status_id="'+news[i].in_reply_to_status_id+'", source="'+news[i].source+'", status_id="'+news[i].id+'", in_reply_to_user_id="'+news[i].in_reply_to_user_id+'", geo="'+news[i].geo+'", favorited="'+news[i].favorited+'", uid="'+news[i].user.id+'", statusnet_html="'+Qt.btoa(news[i].status_html)+'", statusnet_conversation_id="'+news[i].statusnet_conversation_id+'", attachments="'+news[i].attachments+'" where status_id="'+news[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,0,Qt.btoa(news[i].text),news[i].truncated,Date.parse(cleanDate(news[i].created_at)), news[i].in_reply_to_status_id, news[i].source, news[i].id,news[i].in_reply_to_user_id,news[i].geo,news[i].favorited, news[i].user.id,Qt.btoa(news[i].statusnet_html),news[i].statusnet_conversation_id, news[i].attachments,0,0,0])}})
}
getDirectMessage(login,database,rootwindow,callback)
}
function getDirectMessage(login,database,rootwindow,callback){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
Helperjs.friendicaRequest(login,"/api/direct_messages/all",rootwindow, function (obj){
var messages=JSON.parse(obj);
for (var i=0;i<messages.length;i++){
// print('store message data for '+JSON.stringify(messages[i]));
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+messages[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(messages[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=1, text="'+Qt.btoa(messages[i].text)+'", created_at="'+Date.parse(cleanDate(messages[i].created_at))+'", in_reply_to_status_id="", source="Friendica", status_id="'+messages[i].id+'", in_reply_to_user_id="", geo="", favorited="", uid="'+messages[i].sender.id+'", statusnet_html="'+Qt.btoa(messages[i].text)+'", statusnet_conversation_id="", attachments="'+messages[i].attachments+'" where status_id="'+messages[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,1,Qt.btoa(messages[i].text),0,Date.parse(cleanDate(messages[i].created_at)),, "Friendica", messages[i].id,,,, messages[i].sender.id,Qt.btoa(messages[i].text),,,0,0,0])}
});
}
})
getNotifications(login,database,rootwindow,callback)
}
function getNotifications(login,database,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/friendica/notifications", rootwindow,function (obj){
var messages=JSON.parse(obj);
for (var i=0;i<messages.length;i++){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
//print('store message data for '+JSON.stringify(messages[i]));
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+messages[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(messages[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=1, text="'+Qt.btoa(messages[i].text)+'", truncated="'+messages[i].truncated+'", created_at="'+Date.parse(cleanDate(messages[i].created_at))+'", in_reply_to_status_id="", source="'+messages[i].source+'", status_id="'+messages[i].id+'", in_reply_to_user_id="", geo="'+messages[i].geo+'", favorited="", uid="'+messages[i].sender.id+'", statusnet_html="'+Qt.btoa(messages[i].text)+'", statusnet_conversation_id="", attachments="'+messages[i].attachments+'" where status_id="'+messages[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,2,Qt.btoa(messages[i].msg_html),,Date.parse(cleanDate(messages[i].timestamp)),, messages[i].source, messages[i].id,,,, messages[i].sender.id,Qt.btoa(messages[i].msg_html),, messages[i].attachments],0,0,0)}});
}
})
newsfromdb(database,login.username,callback)
}
function newsfromdb(database,username,callback,contact,stop_time){
// return news before stop_time (used by More button), in brackets of 20 entries, or by specified contact
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
if (!stop_time){var stop="";
try{var rs = tx.executeSql('select created_at from news WHERE username="'+username+'" ORDER BY created_at DESC LIMIT 1');
stop="<="+rs.rows.item(0).created_at}catch(e){stop="<99999999999999"}}
else{var stop="<"+stop_time}
var contactfilter="";if(contact){contactfilter=" AND uid='"+contact+"'"}
var newsrs=tx.executeSql('select * from news WHERE username="'+username+'" AND created_at'+stop+contactfilter+' ORDER BY created_at DESC LIMIT 20');
var newsArray=[];
for(var i = 0; i < newsrs.rows.length; i++) {
newsArray.push(newsrs.rows.item(i));
Helperjs.readData(database,"contacts",function(userdata){
newsArray[i].user=userdata[0];
},"id",newsArray[i].uid);
if(newsArray[i].in_reply_to_user_id){
Helperjs.readData(database,"contacts",function(replytodata){
newsArray[i].reply_user=replytodata[0];
},"id",newsArray[i].in_reply_to_user_id)
}
}
callback(newsArray)});
}
function deleteNews(login,database,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/statuses/destroy?id="+newsid, rootwindow,function (obj){
var news=JSON.parse(obj);
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('delete news data for ' + newsid);
db.transaction( function(tx) {var result = tx.executeSql('DELETE from news where status_id ='+newsid); // delete news id
Helperjs.showMessage("Delete",result,rootwindow)});
})}
function retweetNews(login,database,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/statuses/retweet?id="+newsid, rootwindow,function (obj){
var answer=JSON.parse(obj);
Helperjs.showMessage("Repost",answer,rootwindow);
})}
function favorite(login,favorite,newsid,rootwindow){
// toggle favorites
if(favorite){ Helperjs.friendicaRequest(login,"/api/favorites/create?id="+newsid, rootwindow,function (obj){
var news=JSON.parse(obj);
})}
else {Helperjs.friendicaRequest(login,"/api/favorites/destroy?id="+newsid, rootwindow,function (obj){
var news=JSON.parse(obj);
})}
}
function likerequest(login,database,toggle,verb,newsid,rootwindow,callback){ // not tested
Helperjs.friendicaRequest(login,"/api/friendica/activity/"+verb+"?id="+newsid, rootwindow,function (obj){
var likeReturn=JSON.parse(obj);
if (likeReturn=="OK"){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {var result = tx.executeSql('UPDATE news SET '+verb+'d ='+toggle+' where status_id ='+newsid);
callback();
})}})
}
function like(login,database,toggle,verb,newsid,rootwindow,callback){
if(verb=="like"&& toggle==1){
likerequest(login,database,1,"like",newsid,rootwindow,callback);
likerequest(login,database,0,"undislike",newsid,rootwindow);}
if(verb=="dislike"&& toggle==1){
likerequest(login,database,1,"dislike",newsid,rootwindow,callback);
likerequest(login,database,0,"unlike",newsid,rootwindow);}
if(toggle==0){
likerequest(login,database,0,"un"+verb,newsid,rootwindow,callback);}
}
function attend(login,database,attend,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/friendica/activity/attend"+attend+"?id="+newsid, rootwindow,function (obj){
var attendReturn=JSON.parse(obj);
// print("attend: "+obj);
//if (attendReturn=="OK")
{
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {var result = tx.executeSql('UPDATE news SET attend="+attend+" where status_id ='+newsid);
callback();
})}})}
function requestConversation(login,database,newsid,rootwindow,callback){
Helperjs.friendicaRequest(login,"/api/conversation/show?id="+newsid,rootwindow, function (obj){
print(obj+JSON.stringify(obj));
var news=JSON.parse(obj);
for (var i=0;i<news.length;i++){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('store news data for ' + news[i].id);
db.transaction( function(tx) {
var result = tx.executeSql('SELECT * from news where status_id = "'+news[i].id+'"'); // check for news id
if(result.rows.length === 1) {// use update
print(news[i].id +' exists, update it')
result = tx.executeSql('UPDATE news SET username="'+login.username+'", messagetype=0, text="'+Qt.btoa(news[i].text)+'", truncated="'+news[i].truncated+'", created_at="'+Date.parse(cleanDate(news[i].created_at))+'", in_reply_to_status_id="'+news[i].in_reply_to_status_id+'", source="'+news[i].source+'", status_id="'+news[i].id+'", in_reply_to_user_id="'+news[i].in_reply_to_user_id+'", geo="'+news[i].geo+'", favorited="'+news[i].favorited+'", uid="'+news[i].user.id+'", statusnet_html="'+Qt.btoa(news[i].status_html)+'", statusnet_conversation_id="'+news[i].statusnet_conversation_id+'", attachments="'+news[i].attachments+'" where status_id="'+news[i].status_id+'"');
} else {// use insert
result = tx.executeSql('INSERT INTO news VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,0,Qt.btoa(news[i].text),news[i].truncated,Date.parse(cleanDate(news[i].created_at)), news[i].in_reply_to_status_id, news[i].source, news[i].id,news[i].in_reply_to_user_id,news[i].geo,news[i].favorited, news[i].user.id,Qt.btoa(news[i].statusnet_html),news[i].statusnet_conversation_id, news[i].attachments,0,0,0]);
}});
if(news[i].user.following!=true){
updateContactInDB(login,database,rootwindow,news[i].user)}
}
callback();
}
);}
function conversationfromdb(database,user,conversationId,callback){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
print('select * from news WHERE statusnet_conversation_id='+conversationId+' ORDER BY status_id DESC');
var newsrs=tx.executeSql('select * from news WHERE statusnet_conversation_id='+conversationId+' ORDER BY status_id DESC');
var newsArray=[];
for(var i = 0; i < newsrs.rows.length; i++) {
newsArray.push(newsrs.rows.item(i))
Helperjs.readData(database,"contacts",function(userdata){
newsArray[i].user=userdata[0];
},"id",newsArray[i].uid);
}
callback(newsArray);
});}
function inArray(list, prop, val) {
if (list.length > 0 ) {
for (var i in list) { if (list[i][prop] === val) {
return true;
}
}
} return false;
}
function cleanDate(date){
var cleanedDate= date.slice(0,3)+", "+date.slice(8,11)+date.slice(4,7)+date.slice(25,30)+date.slice(10,25);
return cleanedDate
}

View File

@ -0,0 +1,24 @@
WorkerScript.onMessage = function(msg) {
if(msg.appendnews!==true){ msg.model.clear()};
for (var j=0;j<msg.news.length;j++){
if (msg.news[j]) {
var newsitemobject=msg.news[j];
var seconds=(msg.currentTime-newsitemobject.created_at)/1000;
var timestring="";
if (seconds<60) {timestring=seconds+" "+qsTr("seconds") +" "+qsTr("ago");}
else if (seconds<90){timestring=Math.round(seconds/60)+" "+qsTr("minute") +" "+qsTr("ago");}
else if (seconds<3600){timestring=Math.round(seconds/60)+" "+qsTr("minutes") +" "+qsTr("ago");}
else if (seconds<5400){timestring=Math.round(seconds/3600)+" "+qsTr("hour") +" "+qsTr("ago");}
else if (seconds<86400){timestring=Math.round(seconds/3600)+" "+qsTr("hours") +" "+qsTr("ago");}
else if (seconds<129600){timestring=Math.round(seconds/86400)+" "+qsTr("day") +" "+qsTr("ago");}
else if (seconds<3888000){timestring=Math.round(seconds/86400)+" "+qsTr("days") +" "+qsTr("ago");}
else if (seconds<5832000){timestring=Math.round(seconds/3888000)+" "+qsTr("month") +" "+qsTr("ago");}
else if (seconds<69984000){timestring=Math.round(seconds/3888000)+" "+qsTr("months") +" "+qsTr("ago");}
else {timestring=Math.round(seconds/69984000)+" "+qsTr("years") +" "+qsTr("ago");}
var data=({"newsitemobject": newsitemobject,"dateDiff":timestring})}
// print("News:"+j+msg.news.length+JSON.stringify(data));
msg.model.append(data);}
if (j==msg.news.length){
msg.model.sync()
};
}

View File

@ -0,0 +1,15 @@
WorkerScript.onMessage = function(msg) {
if (msg.firstalbum==0){msg.model.clear();}
var limit=0; if (msg.albums.length-msg.firstalbum<20){limit=msg.albums.length} else{limit=msg.firstalbum+20}
for (var j=msg.firstalbum;j<limit;j++){
if (msg.albums[msg.firstalbum]) {
// print("album"+msg.albums[j].name);
if(msg.foreignPicture){
var albumname=msg.albums[j].name.trim();var albumlink=msg.albums[j].link
}else{
var albumname=msg.albums[j].toString();var albumlink=""}
msg.model.append({"albumlink":albumlink,"foreignPicture":msg.foreignPicture,"albumname":albumname});
msg.model.sync()
};
}
}

View File

@ -0,0 +1,223 @@
//.pragma library
.import QtQuick.LocalStorage 2.0 as Sql
.import "qrc:/js/helper.js" as Helperjs
.import "qrc:/js/news.js" as Newsjs
// IMAGE FUNCTIONS
function requestList(login,database,rootwindow,callback) {
//get list of own images and call download function
Helperjs.friendicaRequest(login,"/api/friendica/photos/list", rootwindow,function (helperobject){
// print("return"+helperobject);
var obj=JSON.parse(helperobject);
Helperjs.readField("resourceID",database,"imageData",login.username,function(AllStoredImages){
for(var i=0;i< AllStoredImages.length;i++){
obj.splice(obj.indexOf(AllStoredImages[i]),1);
}
});
callback(obj);
})}
function dataRequest(login,photoID,database,rootwindow) {
// check if image exist and call download function
Helperjs.friendicaRequest(login,"/api/friendica/photo?photo_id="+photoID, rootwindow, function (obj){
try{ if(obj==""){currentImageNo=currentImageNo+1}else{
var image = JSON.parse(obj);
storeData(image,database,login)}}
catch (e){print("Data retrieval failure! "+ e+obj);}
});
}
function storeData(obj,database,login) { // store image data to DB
print('storeData() for ' + obj.filename)
try{sprite.destroy();}catch(e){}
if (obj.data==""){currentImageNo=currentImageNo+1}
else{
var filename=obj.filename;
// check if text name has valid image format ending, otherwise append appropriate ending
if(["jpg","png"].indexOf(filename.substring(filename.lastIndexOf(".")+1,filename.length))==-1){
// print("falscheEndung: "+filename.substring(filename.lastIndexOf(".")+1,filename.length));
{ if (obj.type=="image/jpeg") {obj["filename"]=filename+".jpg"}
if (obj.type=="image/png") {obj["filename"]=filename+".png"} }
print("Filename: "+obj.filename+filename)
}
if (filename==""){
if (obj.type=="image/jpeg") {obj["filename"]=obj["resource-id"]+".jpg"}
if (obj.type=="image/png") {obj["filename"]=obj["resource-id"]+".png"} }
print("Name for savebase64image: "+ obj.filename+" ResourceID: "+ obj["resource-id"]+obj.type)
// call image download function
saveBase64Image(obj,login.imagestore,function(obj,sprite){
//sprite.destroy(500);
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
print('... check if a object exists: '+obj["resource-id"])
var result = tx.executeSql('SELECT * from imageData where resourceID = "'+obj["resource-id"]+'"');
if(result.rows.length === 1) {// use update
print(obj["resource-id"] +' exists, update it')
result = tx.executeSql('UPDATE imageData SET username ="' +login.username+ '",id="'+obj.id+'", uid="'+obj.uid+'", contact_id="'+obj.contact_id+'", guid="'+obj.guid+'", created="'+obj.created+'", edited="'+obj.edited+'", datasize="'+obj.datasize+'", scale="'+obj.scale+'", profile="'+obj.profile+'", allow_cid="'+obj.allow_cid+'", allow_gid="'+obj.allow_gid+'", deny_cid="'+obj.deny_cid+'", deny_gid="'+obj.deny_gid+'", filename="'+obj.filename+'",title="'+obj.title+'", desc="'+obj.desc+'", type="'+obj.type+'", width="'+obj.width+'", height="'+obj.height+'", album="'+obj.album+'", location="file://'+login.imagestore+'", data="", where resourceID="'+obj["resource-id"]+'"');
} else {// use insert print('... does not exists, create it')
result = tx.executeSql('INSERT INTO imageData VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,obj.id,obj.uid,obj.contact_id,obj.guid, obj["resource-id"], obj.created,obj.edited, obj.title, obj.desc, obj.album, obj.filename, obj.type, obj.height, obj.width, obj.datasize, ,obj.scale, obj.profile,obj.allow_cid,obj.allow_gid,obj.deny_cid,obj.deny_gid,'file://'+login.imagestore]);
print("Inserted");}
});
})}}
function saveBase64Image(obj,storagedirectory,callback) {
// create image component from base64 code and save it
print("Storing "+storagedirectory+obj.filename+obj.width+"x"+obj.height);
var maxSize=Math.max(fotostab.width,fotostab.height);
var helpwidth=(obj.width<maxSize)?obj.width:maxSize;
var helpheight=(obj.height<maxSize)?obj.height:maxSize;
if (obj.width>obj.height){ //landscape
helpheight=helpwidth*obj.height/obj.width
} else { //portrait
helpwidth=helpheight*obj.width/obj.height
}
var component=Qt.createComponent("qrc:/qml/PhotoPlaceholder.qml");
var sprite = component.createObject(fotostab, {"x":0,"y":0,"imageName":storagedirectory+obj.filename ,"width":helpwidth,"height":helpheight,"source": "data:image/jpeg;base64,"+obj.data,"downloadtype":"picture"});
// print("sprite: "+sprite);
callback(obj,sprite)
}
function deleteImageData(database,user,field,selection,callback) { // does nothing useful at the moment
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print(' delete Image Data() for ' + field +"="+selection)
db.transaction( function(tx) {
result = tx.executeSql('UPDATE imageData SET data="" where '+ field +'="'+selection+'"');
callback(result)})
}
function requestFriendsAlbumPictures(friend,rootwindow,callback){
// screenscraping of albums page of contact without user and password
Helperjs.friendicaWebRequest(friend.url.replace("profile","photos"),rootwindow,function(photohtml){
var photoarray=[];
var arr = photohtml.split("sidebar-photos-albums-li");
for (var i=2;i<arr.length;i++){
var albumlink = arr[i].substring(arr[i].indexOf('http'),arr[i].indexOf('class')-2);
var albumname=arr[i].substring(arr[i].indexOf('/span')+6,arr[i].indexOf('</a>')-1);
var album={'link':albumlink,'name':albumname}
photoarray.push(album);
}
//print("Album"+JSON.stringify(photoarray));
callback(photoarray)
})
}
function requestFriendsPictures(link,rootwindow,callback){
// screenscraping of pictures page for given album
Helperjs.friendicaWebRequest(link,rootwindow,function(photohtml){
var photoarray=[];
var basehtml=photohtml.substring(photohtml.indexOf('<base')+12,photohtml.indexOf('/>',photohtml.indexOf('<base'))-2);
// old theme
if (photohtml.indexOf("photo-album-image-wrapper-end")>-1){ //theme 1
var arr = photohtml.split("photo-album-image-wrapper-end");}
// other themes
if (photohtml.indexOf("photo-album-wrapper")>-1){ //theme 2
var photoarea=photohtml.substring(photohtml.indexOf("photo-album-wrapper"),photohtml.indexOf("photo-album-end"))
var arr = photoarea.split("</a>");}
for (var i=0;i<arr.length-1;i++){
var photoname=arr[i].substring(arr[i].lastIndexOf('alt')+5,arr[i].lastIndexOf('title')-2);
var thumblink=arr[i].substring(arr[i].lastIndexOf('<img')+10,arr[i].lastIndexOf('alt')-2);
var imagetype=thumblink.substring(thumblink.lastIndexOf("."));
var photolink=thumblink.substring(0,thumblink.length-imagetype.length-2)+"-0"+imagetype
if(thumblink.substring(0,4)!=="http"){thumblink=basehtml+thumblink}
if(photolink.substring(0,4)!=="http"){photolink=basehtml+photolink}
var photo={'link':photolink,'name':photoname,'thumb':thumblink}
photoarray.push(photo);
}
callback(photoarray)
})
}
// CONFIG FUNCTIONS
function initDatabase(database) { // initialize the database object
var db =Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('initDatabase()'+database[0]+database[1]+database[2]+database[3])
db.transaction( function(tx) {
print('... create table')
tx.executeSql('CREATE TABLE IF NOT EXISTS imageData(username TEXT,id INT, uid INT, contact_id INT, guid TEXT, resourceID TEXT, created TEXT,edited TEXT, title TEXT, desc TEXT, album TEXT,filename TEXT, type TEXT, height INT, width INT, datasize INT, data BLOB, scale INT, profile INT, allow_cid TEXT, allow_gid TEXT, deny_cid TEXT, deny_gid TEXT,location TEXT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS config(server TEXT, username TEXT, password TEXT, imagestore TEXT, maxnews INT, timerInterval INT, newsViewType TEXT,isActive INT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS news(username TEXT, messagetype INT, text TEXT, truncated 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,attachments TEXT, liked INT, disliked INT, attend TEXT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS contacts(username TEXT, id INT, name TEXT, screen_name TEXT, location TEXT,description TEXT, profile_image BLOB, url TEXT, protected TEXT, followers_count INT, friends_count INT, created_at TEXT, favourites_count TEXT, utc_offset TEXT, time_zone TEXT, statuses_count INT, following TEXT, verified TEXT, statusnet_blocking TEXT, notifications TEXT, statusnet_profile_url TEXT, cid INT, network TEXT, isFriend INT)');
tx.executeSql('CREATE TABLE IF NOT EXISTS groups(username TEXT, groupname TEXT, gid INT, members TEXT)');
})}
function storeConfig(database,obj) { // stores config to DB
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
print('storeConfig() for ' + obj.username)
print('database: ' + database[0]);
db.transaction( function(tx) {
print('... check if a object exists: '+obj.username)
var result = tx.executeSql('SELECT * from config WHERE username="'+obj.username+'"');
if(result.rows.length === 1) {// use update
print(obj.username +' exists, update it');
var result2 = tx.executeSql('UPDATE config SET server="'+obj.server+'",password="'+obj.password+'", imagestore="'+obj.imagestore+'", maxnews="+obj.maxnews+", isActive=0 WHERE username="'+obj.username +'"');
var result3 = tx.executeSql('UPDATE config SET isActive=1 WHERE username !="'+obj.username +'"');
var result4 = tx.executeSql('UPDATE config SET maxnews='+obj.maxnews);
} else {// use insert print('... does not exists, create it')
var result2 = tx.executeSql('INSERT INTO config VALUES (?,?,?,?,?,?,?,?)', [obj.server, obj.username, obj.password, obj.imagestore, obj.maxnews, 0,"list",0]);
var result3 = tx.executeSql('UPDATE config SET isActive=1 WHERE username !="'+obj.username +'"');
var result4 = tx.executeSql('UPDATE config SET maxnews='+obj.maxnews);
print("Inserted");}
});}
function getServerConfig(login,rootwindow,callback){
// check server with given credentials
try {Helperjs.friendicaRequest(login,"/api/statusnet/config",rootwindow, function (obj){
var serverconfig = JSON.parse(obj);
var serverconfigString="import QtQuick 2.0; import QtQuick.Dialogs 1.2; MessageDialog{ visible: true; title:'Server';standardButtons: StandardButton.Ok;text: 'SUCCESS! \nName: "+serverconfig.site.name+"\nLanguage: "+serverconfig.site.language+
"\nEmail: "+serverconfig.site.email+"\nTimezone: "+serverconfig.site.timezone+"\nClosed: "+serverconfig.site.closed+
"\nText limit: "+serverconfig.site.textlimit+"\nShort Url length: "+serverconfig.site.shorturllength+
"\nFriendica version: "+serverconfig.site.friendica.FRIENDICA_VERSION+"\nDFRN version: "+serverconfig.site.friendica.DFRN_PROTOCOL_VERSION +
"\nDB Update version: "+serverconfig.site.friendica.DB_UPDATE_VERSION+"'}";
callback(serverconfigString);
})}
catch (e){callback (e);
}}
function readConfig(database,callback,filter,filtervalue) { // reads config
print('readConfig()')
if (filter){var where = " WHERE "+ filter +" = '" + filtervalue+"'";} else { var where="";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3],initDatabase(database));
db.transaction( function(tx) {
var tables = tx.executeSql("SELECT * FROM sqlite_master WHERE type='table'");
if (tables.rows.length==0){print("no database");callback("")} else {
print('... read from database '+where)
var rs = tx.executeSql('select * from config'+where);
var rsArray=[];
if (rs.rows.length>0){
for(var i = 0; i < rs.rows.length; i++) {
rsArray.push(rs.rows.item(i))
}
var rsObject={server:rsArray[0].server,username:rsArray[0].username, password:rsArray[0].password,imagestore:rsArray[0].imagestore,maxnews:rsArray[0].maxnews,isActive:rsArray[0].isActive};
} else {
var rsObject=""
}
callback(rsObject);}}
);
}
function readActiveConfig(database){
var obj;
readConfig(database,function(config){
obj=config},"isActive", 0);
return obj;
}
function deleteConfig(database,userobj,callback) { // delete user data from DB
print('deleteConfig()')
if (userobj){var where = " WHERE username='"+ userobj.username+"' and server='"+userobj.server+"'";} else { return "no user selected!";}
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
if(!db) { return; }
db.transaction( function(tx) {
print('... read from database '+where)
var rs = tx.executeSql('delete * from config'+where);
print(rs.toString);
callback(rs);
});
}

View File

@ -0,0 +1,251 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import "qrc:/js/service.js" as Service
import "qrc:/js/layout.js" as Layoutjs
import "qrc:/js/helper.js" as Helperjs
import "qrc:/qml"
StackView{
id: configStack
anchors.fill:parent
focus: true
Keys.onReleased: if (event.key === Qt.Key_Back && stackView.depth > 1) {
stackView.pop(); event.accepted = true;
}
initialItem: Flickable{
width:root.width-5*mm
height:root.height-12*mm
contentHeight: configBackground.height
boundsBehavior: Flickable.StopAtBounds
Rectangle{
id:configBackground
color: "grey"
width:parent.width
height:Math.max(80*mm,root.height-12*mm)
focus: true
ComboBox{
y:mm
width: root.width/2
model: ListModel{
id: usermodel
}
onCurrentIndexChanged:{
try {Service.readConfig(db,function(obj){
servername.text=obj.server;
username.text= obj.username;
password.text=Qt.atob(obj.password);
imagestore.text=obj.imagestore;
maxNewsText.text=obj.maxnews;
if( obj.isActive==0){isActiveField.text=qsTr("yes")} else {isActiveField.text=qsTr("no")}
},"username",currentText)}
catch (e){print(e)}
}
}
Text {
text: "Server"
x: 4*mm; y: 10*mm
}
Text {
text: "User"
x: 4*mm; y: 20*mm
}
Text {
text: "Password"
x: 4*mm; y: 30*mm
}
Text {
text: "Image dir."
x: 4*mm; y: 40*mm
}
Text {
text: "Max. News"
x: 4*mm; y: 50*mm
}
Text {
text: "is Active"
x: 4*mm; y: 60*mm
}
Rectangle{color: "white"; x: 25*mm; y: 10*mm; width: root.width/2; height: 5*mm;}
Flickable {
id: servernameFlickable
x: 25*mm; y: 10*mm; width: root.width/2; height: 5*mm;
contentWidth: servername.paintedWidth
contentHeight: servername.paintedHeight
clip: true
TextEdit {
id: servername
width: servernameFlickable.width
height: servernameFlickable.height
focus: true
text:"https://..."
//wrapMode: TextEdit.NoWrap
//validator: RegExpValidator { regExp: /^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$/}
// onEditingFinished:{}
onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,servernameFlickable)
}
}
Rectangle{
color: "white"
x: 25*mm; y: 20*mm; width: root.width/2; height: 5*mm;
TextInput {
id: username
anchors.fill: parent
selectByMouse: true
}
}
Rectangle{
color: "white"
x: 25*mm; y: 30*mm; width: root.width/2; height: 5*mm;
TextInput {
id: password
anchors.fill: parent
selectByMouse: true
echoMode: TextInput.PasswordEchoOnEdit
}
}
Rectangle{color: "white"; x: 25*mm; y: 40*mm; width: root.width/2-9*mm; height: 5*mm;}
Flickable {
id: imagestoreFlickable
x: 25*mm; y: 40*mm; width: root.width/2-9*mm; height: 5*mm;
clip: true
TextInput {
id: imagestore
width: imagestoreFlickable.width
height: imagestoreFlickable.height
wrapMode: TextEdit.NoWrap
onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,imagestoreFlickable)
}
}
Slider{ id: maxNews
x:37*mm; y: 50*mm;width: root.width/6;height:5*mm
minimumValue: 0;maximumValue:100000; stepSize: 1000
}
Rectangle{color: "white"; x: 25*mm; y: 50*mm; width: 9*mm; height: 5*mm;
TextEdit{id:maxNewsText;
anchors.fill: parent
verticalAlignment:TextEdit.AlignRight
text:maxNews.value
focus: true
selectByMouse: true
}
}
Rectangle{
x: 25*mm; y: 60*mm; width: root.width/2; height: 5*mm;
Text{
id: isActiveField
anchors.fill: parent
}
}
FileDialog {
id: imagestoreDialog
title: "Please choose a directory"
folder: shortcuts.pictures
selectFolder: true
onAccepted: {
var imagestoreString=imagestoreDialog.folder.toString(); imagestoreString=imagestoreString.replace(/^(file:\/{2})/,"")+"/"
imagestore.text=imagestoreString;
console.log("You chose: " + imagestoreDialog.folder)
}
onRejected: {
console.log("Canceled")
}
}
Button {
x: root.width/2+18*mm; y: 40*mm; width: 7*mm; height: 5*mm;
text: "..."
onClicked:
{imagestoreDialog.open()}
}
Button {
x: 25*mm; y: 70*mm; width: implicitWidth; height: implicitHeight;
text: "Update"
onClicked:{
var userconfig={server: servername.text, username: username.text, password:Qt.btoa(password.text), imagestore:imagestore.text,maxnews:maxNewsText.text};
var errormessage="";
if (servername.text==""){errormessage=qsTr("No server given! ")}
//if (!servername.acceptableInput){errormessage+=qsTr("Server name not valid! ")}
else if (username.text==""){errormessage+=qsTr("No username given! ")}
else if (password.text=="") {errormessage+=qsTr("No password given! ")}
else if (imagestore.text=="") {errormessage+=qsTr("No image directory given!")}
else if (maxNewsText.text=="") {errormessage+=qsTr("No maximum news number given!")}
else {errormessage=""}
if (errormessage=="") {Service.storeConfig(db,userconfig);
Service.readConfig(db,function(userconfig){Service.getServerConfig(userconfig,configBackground, function(obj){
var serverString=obj;
var serverconfigObject=Qt.createQmlObject(serverString,configBackground,"serverconfigOutput");
usermodel.append({text:username.text});
//reset values
root.login=userconfig;
root.contactlist=[];
root.news=[]
root.newContacts=[]
root.currentContact= 0
root.contactLoadType= ""
root.currentIndex=0;
newstab.active=true;
})},"isActive",0);
//try {newstab.newsModel.clear();
//friendstab.friendsModel.clear();
//photostab.photogroupModel.clear();} catch(e){}
}
else {Helperjs.show("Error", errormessage,root)}
}}
Button {
x: root.width/2+2*mm; y: mm; width: 5*mm; height: 5*mm;
text: "-"
onClicked:{
var userconfig={server: servername.text, username: username.text, password: Qt.btoa(password.text)};
Service.deleteConfig(db,userconfig);
}}
Button {
x: root.width/2+8*mm; y: mm; width: 5*mm; height: 5*mm;
text: "+"
onClicked:{
servername.text="https://..."
username.text=""
password.text=""
imagestore.text=""
maxNews.value=1000
isActiveField.text=""
}
}
Button {
x: root.width/2+14*mm; y: mm; width: 5*mm; height: 5*mm;
text: "?"
onClicked:{
configStack.push({item:"qrc:/qml/InfoBox.qml"});
}
}
Component.onCompleted: {
try{Helperjs.readData(db,"config",function(users){
users.sort(function(obj1, obj2) {
return obj1.isActive - obj2.isActive;
});
for (var i=0; i<users.length;i++){
if (users[i]) {usermodel.append({text:users[i].username});};
};})}
catch (e){print(e)}
}
}
}
}

View File

@ -0,0 +1,128 @@
import QtQuick 2.0
import QtQuick.Controls 1.3
import "qrc:/js/service.js" as Service
import "qrc:/js/layout.js" as Layoutjs
Item {
id: friendComponent
property date createdAtDate: new Date(friend.created_at)
Rectangle {
id: wrapper
width: 16*mm
height: 15*mm
border.color: "grey"
color:"white"
Image {
id: photoImage
x:1
y:1
width: 10*mm
height:10*mm
source:"file://"+ friend.profile_image
}
Label {
id: namelabel
x: 1
width: wrapper.width-2
elide: Text.ElideRight
height: 3*mm
text: friend.screen_name
anchors.topMargin: 0
anchors.left: photoImage.left
color: "#303030"
font.pixelSize: 3*mm
anchors.top: photoImage.bottom
}
Button{
id:infobutton
width: 5*mm
height: 5*mm
text:"?"
anchors.left: photoImage.right
anchors.leftMargin: 3
anchors.topMargin: 3
anchors.top: parent.top
onClicked:{
print("State: "+ friendComponent.state+friendsView.contentY);
friendComponent.state="large"}
}
Rectangle{
id: detailsrectangle
anchors.top: namelabel.bottom
anchors.topMargin: 2*mm
opacity: 0
Text{
id:namelabeltext
anchors.top: parent.top
width: root.width-10*mm
height: namelabeltext.implicitHeight
font.pixelSize: 3*mm
textFormat:Text.RichText
wrapMode: Text.Wrap
text:"<b>"+qsTr("Description")+": </b> "+Qt.atob(friend.description)+"<br> <b>"+qsTr("Server Type")+":</b> "+friend.location+"<br> <b>"+qsTr("Posts")+":</b> "+friend.statuses_count+
"<br> <b>"+qsTr("URL")+":</b> <a href='"+ friend.url+"'>"+friend.url+"</a><br> <b>"+
qsTr("Created at")+":</b> "+createdAtDate.toLocaleString(Qt.locale())
onLinkActivated: {
Qt.openUrlExternally(link)}
}
Row{
anchors.top: namelabeltext.bottom
anchors.topMargin: 2*mm
spacing:4
Button{
id:photobutton
text:"Photos"
visible:friend.location=="Friendica"? 1:0
onClicked:{root.currentIndex=2;
fotostab.active=true;
root.fotoSignal(friend) ;
}
}
Button{
id:messagebutton
text:"Messages"
onClicked:{root.currentIndex=0;
newstab.active=true;
root.messageSignal(friend.id) ;
}
}
Button{id:dmbutton
visible: friend.following=="true"?true:false
text: "DM"
onClicked:{root.currentIndex=0;
newstab.active=true;
root.directmessageSignal(friend.screen_name);
}
}
Button{
id: closeButton
text: "close"
onClicked:{friendComponent.state=""}
}
}
}
}
states: [
State {
name: "large"
PropertyChanges { target: namelabel; font.pixelSize: 4*mm; width:friendsView.width; text:Qt.atob(friend.name)+" (@"+friend.screen_name+")"}
PropertyChanges { target: friendComponent; z: 2 }
PropertyChanges { target: wrapper; width:friendsView.width;height:friendsView.height -2*mm-1}
PropertyChanges { target: photoImage; width:15*mm;height:15*mm }
PropertyChanges { target:friendComponent.GridView.view ;contentY:friendComponent.y;contentX:friendComponent.x;interactive:false}
PropertyChanges { target: detailsrectangle; opacity:1 }
}
]
}

View File

@ -0,0 +1,66 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import "qrc:/js/service.js" as Service
import "qrc:/js/helper.js" as Helperjs
import "qrc:/js/news.js" as Newsjs
import "qrc:/qml"
Rectangle {
function showFriends(username){try {friendsModel.clear()} catch(e){print(e)};
Helperjs.readData(db, "contacts",function(friendsobject){
for (var j=0;j<friendsobject.length;j++){
friendsModel.append({"friend":friendsobject[j]});
}},"username", username)
}
color: "white"
Button {
id: updateFriendsButton
text: qsTr("Update")
anchors.top: parent.top
anchors.right: parent.right
onClicked: {
try {friendsModel.clear()} catch(e){print(e)};
root.contactLoadType="friends";
Newsjs.requestFriends(root.login,db,root,function(nc){
root.newContacts=nc
})}
}
ProgressBar{
id: newContactsProgress
width: 15*mm
height: updateFriendsButton.height
anchors.top: parent.top
anchors.right:updateFriendsButton.left
anchors.rightMargin:mm
visible: (root.currentContact!=root.newContacts.length)?true:false
value: root.currentContact/root.newContacts.length
}
Rectangle{
x: 2*mm; y:updateFriendsButton.height+2*mm
width:root.width-5*mm
height:root.height-5*mm
GridView {
id: friendsView
anchors.fill: parent
anchors.bottomMargin: 12*mm
clip: true
cellHeight: 16*mm
cellWidth: 17*mm
add: Transition {
NumberAnimation { properties: "x,y"; from: 300; duration: 1000 }
}
model: friendsModel
delegate: FriendComponent { }
}
}
ListModel{
id: friendsModel
}
Component.onCompleted: {
root.friendsSignal.connect(showFriends);
showFriends(login.username)
}
}

View File

@ -0,0 +1,22 @@
import QtQuick 2.0
import QtQuick.Controls 1.2
Rectangle{
color:"white"
width:infoBoxText.contentWidth
height:infoBoxText.contentHeight
Text{id:infoBoxText
textFormat: Text.RichText
wrapMode: Text.Wrap
text: "<b>Friendiqa v0.001 </b><br>Licensed under GPL 3<br> "+
"Sourcecode: <a href='https://github.com/LubuWest/Friendiqa'>https://github.com/LubuWest/Friendica</a><br>"+
"C++ code by <a href='https://kirgroup.com/profile/fabrixxm'>Fabio</a><br>"+
"QML and Javascript code by <a href='https://freunde.ma-nic.de/profile/marco'>Marco</a>"
onLinkActivated:{
Qt.openUrlExternally(link)}
}
Button{
text:qsTr("Close")
onClicked:{configStack.pop()}
anchors.top:infoBoxText.bottom
}
}

View File

@ -0,0 +1,132 @@
// message.qml
// message with buttons
import QtQuick 2.0
import QtQml 2.2
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
import QtQuick.LocalStorage 2.0
//import "../qml"
import "qrc:/js/service.js" as Service
Item{
id:messageSend
property var login
property string parentId: ""
property string reply_to_user:""
property string attachImageURL: "";
property int directmessage: 0;
property var contacts: []
// title: parentId !== "" ? qsTr("Reply to "+reply_to_user) : qsTr("New post")
function statusUpdate(title,status,in_reply_to_status_id,attachImageURL) {
xhr.url= login.server + "/api/statuses/update.xml";
xhr.setLogin(login.username+":"+Qt.atob(login.password));
print("login: "+login.username+":"+Qt.atob(login.password));
xhr.clearParams();
xhr.setParam("source", "Friendiqa");
xhr.setParam("status", status);
if (parentId!="") {xhr.setParam("in_reply_to_status_id", parentid)};
if (title!=="") {xhr.setParam("title", title)};
if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )};
xhr.post();
}
function dmUpdate(title,text,replyto,screen_name,attachImageURL) {
xhr.url= login.server + "/api/direct_messages/new.xml";
xhr.setLogin(login.username+":"+Qt.atob(login.password));
xhr.clearParams();
xhr.setParam("text", text);
xhr.setParam("screen_name", screen_name);
if (parentId!="") {xhr.setParam("replyto", replyto)};
if (title!=="") {xhr.setParam("title", title)};
if (attachImageURL!=="") {xhr.setImageFileParam("media", attachImageURL )};
xhr.post();
}
Column {
id:messageColumn
spacing: 2
TextField {
id: titleField
width: parent.width
placeholderText: qsTr("Title (optional)")
visible: messageSend.parentId === ""
}
TextArea {
id: bodyField
width: parent.width
height: 30*mm
wrapMode: TextEdit.Wrap
}
CheckBox{
id:dmCheckbox
text:"DM"
enabled: false
checked: (directmessage==1)?true:false
onClicked:{
if(dmCheckbox.checkedState==Qt.Checked){directmessage=1}
else if(dmCheckbox.checkedState==Qt.Unchecked){directmessage=0}
}
}
Row{
spacing:2
Button {
id: cancelButton
text: qsTr("Cancel")
onClicked: {newsStack.pop()}
}
Button {
id: attachButton
text: qsTr("Attach")
onClicked: {imageAttachmentDialog.open()}
}
Button{
id:contactButton
text:qsTr("cc")
visible:(directmessage==0)
onClicked:{
var contactitems="";
for (var i=0;i<contacts.length;i++){
contactitems=contactitems+"MenuItem{text:'"+contacts[i]+"'; onTriggered: bodyField.append(' @"+contacts[i]+"')}"
}
var menuString="import QtQuick.Controls 1.4; Menu {"+contactitems+"}";
// print(menuString);
var contactlistObject=Qt.createQmlObject(menuString,messageSend,"contactmenuOutput")
contactlistObject.popup() }
}
Button {
id: sendButton
text: qsTr("Send")
onClicked: {
print("login: "+login.server+login.username);
if (directmessage==0){
statusUpdate(titleField.text,bodyField.text,messageSend.parentId,attachImageURL.toString());}
else {dmUpdate( titleField.text,bodyField.text,"",messageSend.reply_to_user) }
newsStack.pop()
}
}
}
}
FileDialog {
id: imageAttachmentDialog
title: "Please choose a picture"
folder: shortcuts.pictures
selectFolder: false
onAccepted: {
attachImageURL=imageAttachmentDialog.fileUrl;
var imageAttachementObject=Qt.createQmlObject('import QtQuick 2.0; Image {source:"'+attachImageURL.toString()+'"; width: 30*mm; height: 30*mm;fillMode: Image.PreserveAspectFit}',messageColumn,"attachedImage");
console.log("You chose: " + attachImageURL)
}
onRejected: {
console.log("Canceled")
}
}
}

View File

@ -0,0 +1,154 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import QtQuick.LocalStorage 2.0 as Sql
import "qrc:/js/news.js" as Newsjs
import "qrc:/js/helper.js" as Helperjs
Item {
property string newstabStatus:"news"
function showNews(newsToShow){
newsBusy.running=false;
var currentTime= new Date();
var msg = {'currentTime': currentTime, 'model': newsModel,'news':newsToShow};
newsWorker.sendMessage(msg);
}
function onFriendsMessages(friend){print(" Friend "+friend);
newstabStatus="friendmessage";
Newsjs.newsfromdb(db,root.login.username, function(dbnews){showNews(dbnews)},friend)
}
function onDirectMessage(friend){
newsStack.push({item:"qrc:/qml/MessageSend.qml",properties:{"reply_to_user": friend,"directmessage":1,"login":root.login}});
}
function cleanNews(database){
var db=Sql.LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
db.transaction( function(tx) {
var maxnewsrs = tx.executeSql("SELECT DISTINCT maxnews FROM config");
var maxnews=maxnewsrs.rows.item(0);
var newscountrs = tx.executeSql('SELECT COUNT(*) from news');
var newscount = newscountrs.rows.item(0);
if (newscount>maxnews){var lastvalidtimers= tx.executeSql('select created_at from news ORDER BY created_at DESC LIMIT ' +(newscount-maxnews));
var lastvalidtime=lastvalidtimers.rows.item(-1);
var deleters = tx.executeSql('DELETE from news WHERE created_at<'+lastvalidtime)}
});
Qt.quit()
}
StackView{
id: newsStack
anchors.fill:parent
focus: true
Keys.onReleased: if (event.key === Qt.Key_Back && stackView.depth > 1) {
stackView.pop(); event.accepted = true;
}
initialItem:Rectangle {
color: "white"
width:root.width-2*mm
height:root.height-8*mm
Button {
id: newMessageButton
text: qsTr("+")
anchors.top: parent.top
anchors.right: parent.right
onClicked: {
Helperjs.readField("screen_name",root.db,"contacts",root.login.username,function(friends){
newsStack.push({item:"qrc:/qml/MessageSend.qml",properties:{"contacts": friends,"login":root.login}})
},"isFriend",1);
}
}
Button {
id: quitButton
text: qsTr("Quit")
anchors.top: parent.top
anchors.right: newMessageButton.left
onClicked: {cleanNews(root.db)}
}
Component { id:footerComponent
Rectangle{
border.color: "#EEEEEE"
border.width: 1
width:parent.width
height:6*mm
Text{
font.pixelSize: 1.5*mm
anchors.centerIn: parent
text:qsTr("More")
}
MouseArea{anchors.fill:parent
onClicked:{
var currentTime= new Date();
if(newstabStatus=="news"){
var lastnews_id=newsModel.get(newsModel.count-1).newsitemobject.created_at;
Newsjs.newsfromdb(root.db,root.login.username, function(news){
var msg = {'currentTime': currentTime, 'model': newsModel,'news':news,'appendnews':true};
newsWorker.sendMessage(msg);
},false,lastnews_id)}
else if(newstabStatus=="friendmessage"){
Newsjs.newsfromdb(root.db,root.login.username, function(news){
var msg = {'currentTime': currentTime, 'model': newsModel,'news':news,'appendnews':true};
newsWorker.sendMessage(msg);
},newsModel.get(newsModel.count-1).newsitemobject.uid,newsModel.get(newsModel.count-1).newsitemobject.created_at)}
}}
}
}
ListView {
id: newsView
anchors.fill: parent
anchors.topMargin: 8*root.mm
anchors.leftMargin: 3*root.mm; anchors.rightMargin: root.mm
anchors.bottomMargin: 1*root.mm
clip: true
spacing: 0
footer: footerComponent
model: newsModel
delegate: Newsitem{}
}
ListModel{id: newsModel}
WorkerScript {
id: newsWorker
source: "qrc:/js/newsworker.js"
}
Button {
id: update
anchors.top: parent.top
anchors.right: quitButton.left
text: "Update"
onClicked: { //try{newsModel.clear()} catch(e){}
newsBusy.running=true;
root.contactLoadType="news";
Newsjs.getFriendsTimeline(login,db,contactlist,newstab,function(ns,nc){
root.news=ns;root.newContacts=nc;root.currentContact=0;
if (ns.length==0){
Newsjs.getDirectMessage(root.login,root.db,root,function(dbnews){showNews(dbnews)});
newsBusy.running=false}
})}
}
BusyIndicator{
id: newsBusy
anchors.centerIn:update
//anchors.right: update.left
//anchors.top:parent.top
width:7*mm
height: 7*mm
}
Component.onCompleted: {
root.messageSignal.connect(onFriendsMessages);
root.directmessageSignal.connect(onDirectMessage);
root.newsSignal.connect(showNews);
try{newsModel.clear()} catch(e){}
Newsjs.newsfromdb(root.db,root.login.username, function(dbnews){
showNews(dbnews)
})
}
}
}
}

View File

@ -0,0 +1,261 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import "qrc:/js/news.js" as Newsjs
import "qrc:/js/layout.js" as Layoutjs
Item {
id: newsitem
width: newsView.width
height:Math.max((itemMessage.height+createdAtLabel.height+4*mm),profileImage.height+user_name.height+mm)
property bool show_full: false
property string conversation_id: ""
property string attachments:""
property string attending: ""
onAttendingChanged: {attendLabel.visible=true;
attendLabel.text= qsTr("attending: ")+ qsTr(attending)}
signal replyto(string parent_id)
Rectangle{width:newsitem.width; height: 1; anchors.bottom: newsitem.bottom; color:"light grey"}
Rectangle{
width:newsitem.width
height:newsitem.height-1
color: (newsitemobject.directmessage)?"#ffe6e6" : "white"
Column {
id: authorcolumn
width: 8*mm
Image {
id:profileImage
source: "file://"+newsitemobject.user.profile_image
x:1
width: 7*mm
height: 7*mm
MouseArea{
anchors.fill: parent
onPressAndHold: { newsmenu.popup()}
}
onStatusChanged: if (profileImage.status == Image.Error) {source="qrc:/images/defaultcontact.jpg"}
}
Label {
id:user_name
color: "grey"
//height:3.5*mm
width:parent.width
font.pixelSize: 1.5*mm
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: Qt.atob(newsitemobject.user.name)
}
}
Column {
id:newscolumn
anchors.left: authorcolumn.right
Row{
spacing: 5
Label {
color: "grey"
text: if (newsitemobject.messagetype==0){qsTr("Source: ")+newsitemobject.source
} else if (newsitemobject.messagetype==1){ qsTr("Direct Message")} else {" Notification"}
font.pixelSize: 1.5*mm
}
Label {
id:createdAtLabel
color: "grey"
height:3.5*mm
font.pixelSize: 1.5*mm
horizontalAlignment: Label.AlignRight
text: dateDiff
}
CheckBox {
id:favoritedCheckbox
style: CheckBoxStyle {
background: Rectangle {
implicitWidth: 6*mm
implicitHeight:2*mm
color:"white"
}
indicator:
Rectangle{x:3*mm
width: 3*mm
implicitHeight:2*mm
Text{
anchors.centerIn: parent
color:control.checked?"black":"grey"
text:"\u2605"
}}
}
checked:(newsitemobject.favorited>0)
Text{
anchors.left: parent.right
color: "grey"
font.pixelSize: 1.5*mm
text: (newsitemobject.favorited>0)? newsitemobject.favorited+qsTr(" Favorites"):""
}
onClicked:{
if(favoritedCheckbox.checkedState==Qt.Checked)
{Newsjs.favorite(login,true,newsitemobject.status_id,root)}
else
if(favoritedCheckbox.checkedState==Qt.Unchecked)
{Newsjs.favorite(login,false,newsitemobject.status_id,root)}
}
}
}
Text {
color: "#404040"
linkColor: "light green"
id: itemMessage
textFormat: Text.RichText
text: Qt.atob(newsitemobject.statusnet_html)
width: newsitem.width-8*mm-2
height: implicitHeight
wrapMode: Text.Wrap
onLinkActivated:{ print("link "+link);
Qt.openUrlExternally(link)}
}
Row {
CheckBox{id:likeCheckbox
height:3*mm
width:8*mm
style: CheckBoxStyle {
background: Rectangle {
implicitWidth: 7*mm
implicitHeight: 3*mm
color:"white"
}
indicator:
Rectangle{
implicitWidth: 3*mm
implicitHeight:3*mm
color:control.checked?"yellow":"white"
x: 5*mm
Text{
font.pixelSize: 1.5*mm
color:"grey"
text:":-)"
}}
}
onClicked: {
if(likeCheckbox.checked==true){Newsjs.like(root.login,root.db,1,"like",newsitemobject.status_id,root);dislikeCheckbox.checked=false}
else{Newsjs.like(root.login,root.db,0,"like",newsitemobject.status_id,root)}}
}
CheckBox{id: dislikeCheckbox
height:3*mm
width:8*mm
style: CheckBoxStyle {
background: Rectangle {
implicitWidth: 7*mm
implicitHeight:3*mm
color:"white"
}
indicator:
Rectangle{
implicitWidth: 3*mm
implicitHeight:3*mm
color:control.checked?"yellow":"white"
x:5*mm
Text{
font.pixelSize: 1.5*mm
color:"grey"
text:":-("
}}
}
onClicked: {
if (dislikeCheckbox.checked==true){Newsjs.like(root.login,root.db,1,"dislike",newsitemobject.status_id);likeCheckbox.checked=false}
else {Newsjs.like(root.login,root.db,0,"dislike",newsitemobject.status_id,root)}}
}
Label {
id:replytoLabel
color: "grey"
height:3.5*mm
font.pixelSize: 1.5*mm
horizontalAlignment: Label.AlignRight
text: try {qsTr("In reply to ")+newsitemobject.reply_user.screen_name
}catch(e){" "}
}
Label {
id:attendLabel
visible: false
color: "grey"
height:3.5*mm
font.pixelSize: 1.5*mm
horizontalAlignment: Label.AlignRight
text: qsTr("attending: ")+ qsTr(attending)
}
}
}
Menu {
id:newsmenu
MenuItem {
text: qsTr("Reply")
onTriggered: {
newsStack.push({item:"qrc:/qml/MessageSend.qml",properties:{"reply_to_user": newsitemobject.user.screen_name,"parentId":newsitemobject.status_id}});
}
}
MenuItem {
text: qsTr("DM")
onTriggered: {
root.directmessageSignal(newsitemobject.user.screen_name);
}
}
MenuItem {
text: qsTr("Repost")
onTriggered: {
Newsjs.retweetNews(root.login,db,newsitemobject.status_id,root,function(reply){
print(reply);
})
}
}
MenuItem {
text: qsTr("Conversation")
onTriggered: {
Newsjs.requestConversation(root.login,db,newsitemobject.status_id,root,function(){
var currentTime= new Date();
Newsjs.conversationfromdb(db,root.login.username,newsitemobject.statusnet_conversation_id, function(newsarray){
newsModel.clear();
var msg = {'currentTime': currentTime, 'model': newsModel,'news':newsarray,'latestmessage':0};
newsWorker.sendMessage(msg);
});
}
)}
}
Menu{
title: qsTr("Attending")
MenuItem{text:qsTr("yes")
onTriggered: {Newsjs.attend(root.login,db,"yes",newsitemobject.status_id,root,function(){
newsitem.attending="yes";
attendLabel.visible=true})}
}
MenuItem{text:qsTr("maybe")
onTriggered: {Newsjs.attend(root.login,db,"maybe",newsitemobject.status_id,root,function(){
newsitem.attending="maybe"})}
}
MenuItem{text:qsTr("no")
onTriggered: {Newsjs.attend(root.login,db,"no",newsitemobject.status_id,root,function(){
newsitem.attending="no"})}
}
}
MenuItem {
text: qsTr("Delete")
onTriggered: {
Newsjs.deleteNews(root.login,db,newsitemobject.status_id,root,function(reply){
print(JSON.stringify(reply));
newsModel.remove(index);
})
}
}
}
}}

View File

@ -0,0 +1,100 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Controls 1.2
Package {
Item { id: stackItem; Package.name: 'stack'; z: stackItem.PathView.z;width:16.5*mm;height:16.5*mm}
Item { id: listItem; Package.name: 'list'; width: root.width-1*mm; height: root.height-8*mm; }
Item { id: gridItem; Package.name: 'grid';}
Item {
id: photoWrapper
width: 16.5*mm; height: 16.5*mm
z: stackItem.PathView.z
property string hqphotolink: photoLink
Rectangle {
id: placeHolder
color: 'lightblue'; antialiasing: true
anchors.fill:parent
//width: parent.width; height: parent.height;
}
BusyIndicator { anchors.centerIn: parent; running: realImage.status != Image.Ready }
Image {
id: realImage;
// property string hqphotolink: photoLink
width: photoWrapper.width; height: photoWrapper.height
antialiasing: true;
asynchronous: true
cache: false
fillMode: Image.PreserveAspectFit;
source: imageLocation
// onStatusChanged: if (realImage.status == Image.Ready) print(realImage.paintedHeight+"x"+realImage.paintedWidth)
}
Rectangle{
id:phototextRectangle
color:"black"
z:3
opacity: 0.5
width:phototext.contentWidth
height: phototext.contentHeight
anchors.bottom: photoWrapper.bottom
}
Text {
id:phototext
z:4
text: photoDescription.trim()
width:15*mm
anchors.bottom: photoWrapper.bottom
color: "white"
font.pixelSize: 2*mm
wrapMode:Text.Wrap
}
MouseArea {
width: realImage.paintedWidth; height: realImage.paintedHeight; anchors.centerIn: realImage
onClicked: {
if (albumWrapper.state == 'inGrid') {
gridItem.GridView.view.currentIndex = index;
//print("photoLink"+realImage.photoLink)
albumWrapper.state = 'fullscreen'
} else {
gridItem.GridView.view.currentIndex = index;
albumWrapper.state = 'inGrid'
}
}
}
states: [
State {
name: 'stacked'; when: albumWrapper.state == ''
ParentChange { target: photoWrapper; parent: stackItem; }//x: 1*mm; y: 1*mm }
PropertyChanges { target: photoWrapper; opacity: stackItem.PathView.onPath ? 1.0 : 0.0 }
PropertyChanges { target: phototext; opacity: 0.0 }
PropertyChanges { target: phototextRectangle; opacity: 0.0 }
},
State {
name: 'inGrid'; when: albumWrapper.state == 'inGrid'
ParentChange { target: photoWrapper; parent: gridItem; x: 1*mm; y: 1*mm;}
PropertyChanges { target: phototext; opacity: 1.0 }
PropertyChanges { target: phototextRectangle; opacity: 0.5 }
PropertyChanges { target: placeHolder; opacity: 1.0 }
},
State {
name: 'fullscreen'; when: albumWrapper.state == 'fullscreen'
ParentChange {
target: photoWrapper; parent: listItem; x: 1; y: 1;
width: root.width-mm; height: root.heigh-8*mm
}
PropertyChanges { target: placeHolder; opacity: 0.0 }
PropertyChanges { target: realImage; source: photoWrapper.hqphotolink}
PropertyChanges { target: phototext; anchors.bottom: realImage.bottom}
PropertyChanges { target: phototext; width:realImage.width }
PropertyChanges { target: phototextRectangle; anchors.bottom: realImage.bottom }
PropertyChanges { target: realImage; width: Math.min(listItem.width,sourceSize.width);height: Math.min(listItem.height,sourceSize.height) }
}
]
}
}

View File

@ -0,0 +1,26 @@
import QtQuick 2.0
import "qrc:/js/helper.js" as Helperjs
Image {
id:photoPlaceholder
property string imageName:"x.jpg"
property string downloadtype:""
fillMode: Image.PreserveAspectFit
onStatusChanged: {
if (photoPlaceholder.status == Image.Ready) {
//print("Photo width"+width+" height"+height+" Ratio "+ fillMode);
var saveprocess=photoPlaceholder.grabToImage(function(result){
var saveresult=result.saveToFile(imageName.toString());
if (saveresult){
if ((downloadtype=="picture")&&(newImages.length>0)){
photoPlaceholder.destroy();
currentImageNo=currentImageNo+1
}
else if ((downloadtype=="contact")&&(root.newContacts.length>0))
{
photoPlaceholder.destroy(100);
root.currentContact=root.currentContact+1
}
}});
}}}

View File

@ -0,0 +1,135 @@
import QtQuick 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
import QtQml.Models 2.1
import "qrc:/js/service.js" as Service
import "qrc:/js/helper.js" as Helperjs
import "qrc:/qml"
Rectangle {
id:fotorectangle
width:root.width-mm
height:root.height-5*mm
color: '#fff'
property var newImages:[]
property int currentImageNo: 0
//onLoginChanged:{var msg = {'model': photogroupModel,'albums':[],'firstalbum':0,'foreignPicture':false};
// photoWorker.sendMessage(msg);
//}
onNewImagesChanged:{if(newImages.length>0){ Service.dataRequest(root.login,newImages[currentImageNo],root.db,fotorectangle);newImagesProgress.visible=true //download first image
} }
onCurrentImageNoChanged:{ if(currentImageNo<newImages.length){Service.dataRequest(root.login,newImages[currentImageNo],root.db,fotorectangle)};
if(currentImageNo==newImages.length){newImagesProgress.visible=false;showOwnFotos();
newImages=[];currentImageNo=0}
// download next image if photoplaceholder is finished saving
}
ProgressBar{
id: newImagesProgress
width: 15*mm
height: updatePhotolist.height
anchors.top: parent.top
anchors.right:updatePhotolist.left
anchors.rightMargin:mm
visible: false
value: currentImageNo/newImages.length
}
Button{
id: updatePhotolist
anchors.top: parent.top
anchors.right:showFotos.left
anchors.rightMargin:mm
text: qsTr("Update")
onClicked: {
Service.requestList(root.login,root.db, fotostab,function(obj){
newImages=obj;
})}}
Button{
id: showFotos
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin:2*mm
text: qsTr("Show")
onClicked: {showOwnFotos()}
}
DelegateModel{
id: visualphotoModel
delegate: PhotogroupComponent{}
model: photogroupModel
}
ListModel{
id: photogroupModel
}
GridView {
id: albumgridview
cellWidth: 17*mm
cellHeight: 17*mm
x: mm;y:8*mm
width: parent.width-2*mm; height: parent.height-9*mm
clip: true
model: visualphotoModel.parts.album
footer:
Rectangle{
border.color: "#EEEEEE"
border.width: 1
width:12*mm
height:6*mm
Text{
font.pixelSize: 1.5*mm
anchors.centerIn: parent
text:qsTr("More")
}
MouseArea{anchors.fill:parent
onClicked:{
var lastalbum_id=photogroupModel.get(photogroupModel.count-1);
if(photogroupModel.get(photogroupModel.count-1).foreignPictures==false){Service.requestFriendsAlbumPictures(friend,fotostab,function(albums){
var msg = {'model': photogroupModel,'albums':albums,'firstalbum':lastalbum_id+1,'foreignPicture':true};
photoWorker.sendMessage(msg); })}
else { Helperjs.readField("album",root.db, "imageData",root.login.username,function(albums){
var msg = { 'model': photogroupModel,'albums':albums,'foreignPicture': false,'firstalbum':lastalbum_id+1};
photoWorker.sendMessage(msg)})}
}}}
}
Rectangle { id: photoBackground; color: 'light grey'; width: parent.width; height: parent.height; opacity: 0; visible: opacity != 0.0 }
ListView { anchors.fill: parent; model: visualphotoModel.parts.browser; interactive: false }
Button {
id: backButton
text: qsTr("Back")
x: parent.width - backButton.width - 3*mm
y: -backButton.height - 4*mm
onClicked: {photoBackground.opacity=0}
// visible: Qt.platform.os !== "android"
}
ListView {anchors.fill: parent; model: visualphotoModel.parts.fullscreen; interactive: false }
WorkerScript{id: photoWorker;source: "qrc:/js/photoworker.js"}
function showOwnFotos(){
try {photogroupModel.clear()}catch (e){print(e)}
Helperjs.readField("album",root.db, "imageData",root.login.username,function(albums){
if (albums[0]) {
var msg = { 'model': photogroupModel,'albums':albums,'firstalbum':0,'foreignPicture': false};
photoWorker.sendMessage(msg);
};
})
}
function onFriendsFotos(friend){print("Friend "+friend.url);
try {photogroupModel.clear()}catch (e){print(e)}
Service.requestFriendsAlbumPictures(friend,fotostab,function(albums){
var msg = {'model': photogroupModel,'albums':albums,'firstalbum':0,'foreignPicture':true};
photoWorker.sendMessage(msg);
})
}
Component.onCompleted: { root.fotoSignal.connect(onFriendsFotos);}
}

View File

@ -0,0 +1,119 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Controls 1.3
import QtQml.Models 2.1
import "qrc:/js/service.js" as Service
import "qrc:/js/helper.js" as Helperjs
Package {
Item {
Package.name: 'browser'
GridView {
id: photosGridView; model: visualModel.parts.grid; width: albumgridview.width; height: albumgridview.height
cellWidth: 16.5*mm; cellHeight: 16.5*mm; interactive: false;anchors.margins:2*mm
onCurrentIndexChanged: photosListView.positionViewAtIndex(currentIndex, ListView.Contain)
}
}
Item {
Package.name: 'fullscreen'
ListView {
id: photosListView; model: visualModel.parts.list; orientation: Qt.Horizontal
width: parent.width; height: parent.height; interactive: false
onCurrentIndexChanged: photosGridView.positionViewAtIndex(currentIndex, GridView.Contain)
highlightRangeMode: ListView.StrictlyEnforceRange; snapMode: ListView.SnapOneItem
}
}
Item {
Package.name: 'album'
id: albumWrapper; width: 16.5*mm; height: 16.5*mm //-albumtext.contentHeight
DelegateModel {
id: visualModel; delegate: PhotoComponent { }
model: photoModel
}
PathView {
id: photosPathView;
model: visualModel.parts.stack;
pathItemCount: 1
anchors.centerIn: parent;
path: Path {
PathAttribute { name: 'z'; value: 9999.0 }
PathLine { x: 1; y: 1 }
PathAttribute { name: 'z'; value: 0.0 }
}
}
Rectangle{
color:"black"
opacity: 0.5
width:albumtext.contentWidth
height: albumtext.contentHeight
anchors.bottom: albumWrapper.bottom
}
Text {
id:albumtext
text: albumname //foreignPicture ? album.name.trim() : album
width:albumWrapper.width-1*mm
height: albumtext.contentHeight
wrapMode:Text.Wrap
color: "white"
font.family: "Monospace"
font.pixelSize: 2*mm
anchors.bottom: albumWrapper.bottom
}
ListModel{
id: photoModel
}
Component.onCompleted:{
try {photoModel.clear()}catch (e){print(e)}
if(foreignPicture){
//print("Albumlink"+album.link);
Service.requestFriendsPictures(albumlink,fotostab,function(obj){
if (obj) {
for (var k=0;k<obj.length;k++){
//print("Photomodel:"+obj[k].thumb+obj[k].name+obj[k].link);
photoModel.append({"imageLocation": obj[k].thumb,"photoDescription":obj[k].name,"photoLink":obj[k].link})
};
}
})}
else{
Helperjs.readData(db,"imageData",function(obj){
// obj.sort(function(obj1,obj2){return obj1.data-obj2.data});
if (obj) {
for (var k=0;k<obj.length;k++){
// print("Photomodel:"+obj[k].location+obj[k].filename);
photoModel.append({"imageLocation": obj[k].location+obj[k].filename,"photoDescription":obj[k].filename,"photoLink":obj[k].location+obj[k].filename})
};
}
},"album",albumname)}
}
MouseArea {
anchors.fill: parent
onClicked: albumWrapper.state = 'inGrid'
}
states: [
State {
name: 'inGrid'
PropertyChanges { target: photosGridView; interactive: true }
PropertyChanges { target: photoBackground; opacity: 1 }
PropertyChanges { target: backButton; onClicked: albumWrapper.state = ''; y: 6 }
},
State {
name: 'fullscreen'; extend: 'inGrid'
PropertyChanges { target: photosGridView; interactive: false }
PropertyChanges { target: photosListView; interactive: true }
PropertyChanges { target: photoBackground; opacity: 1 }
PropertyChanges { target: backButton; y: -backButton.height - 8 }
}
]
} //album Ende
} //Package Ende
//item Ende

View File

@ -0,0 +1,111 @@
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import QtQuick.Window 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.2
import QtQml.Models 2.1
import "qrc:/js/news.js" as Newsjs
import "qrc:/js/service.js" as Service
import "qrc:/js/layout.js" as Layoutjs
import "qrc:/js/helper.js" as Helperjs
import "qrc:/qml"
TabView{
id:root
tabPosition: Qt.BottomEdge
width: 400//Screen.desktopAvailableWidth
height: 400// Screen.desktopAvailableHeight
property var db: ["Photos", "1.0", "Stores Friendica data", 100000000]
property var login: Service.readActiveConfig(db)
property var contactlist: []
property real mm: Screen.pixelDensity
signal messageSignal(var friend)
signal fotoSignal(var friend)
signal directmessageSignal(var friend)
signal newsSignal(var news)
signal friendsSignal(var username)
currentIndex: (login=="")? 3:0
property var news:[]
property var newContacts:[]
property int currentContact: 0
property string contactLoadType: ""
onLoginChanged:{Newsjs.newsfromdb( db,login.username, function(dbnews){
newsSignal(dbnews)
})}
onNewContactsChanged:{if(newContacts.length>0){// download first contact image and update db
//print("newcontact"+JSON.stringify(newContacts[0]));
updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])}
}
onCurrentContactChanged:{// download next contact image after photoplaceholder is finished saving and update db
if(currentContact<newContacts.length){
updateContactInDB(login,db,newContacts[currentContact].isFriend,newContacts[currentContact])}
else if(currentContact==newContacts.length){//newImagesProgress.visible=false;
if (newContacts.length==0) {}
else if (contactLoadType=="news"){
Newsjs.storeNews(login,db,news,root,function(dbnews){
root.newsSignal(dbnews);
root.newContacts=[];
root.currentContact=0;
root.news=[]
})// show news
}
else if (contactLoadType=="friends"){
root.friendsSignal(login.username);
// show friends
Helperjs.readField("id",db,"contacts",login.username,function(contacts){contactlist=contacts;
root.newContacts=[];
root.currentContact=0},"isFriend",1) }
}
}
function updateContactInDB(login,database,isFriend,contact){// for newstab and friendstab
var imagename=login.imagestore+contact.screen_name+".jpg";
var component=Qt.createComponent("qrc:/qml/PhotoPlaceholder.qml");
var sprite = component.createObject(root, {"fillMode": "Image.PreserveAspectFit","x":root.width,"y":50,"imageName":imagename,"source": contact.profile_image_url,"downloadtype":"contact"});
var db=LocalStorage.openDatabaseSync(database[0],database[1],database[2],database[3]);
var result;
db.transaction( function(tx) {
result = tx.executeSql('SELECT * from contacts where id = '+contact.id); // check for news id
if(result.rows.length === 1) {// use update
result = tx.executeSql('UPDATE contacts SET username="'+login.username+'", id='+contact.id+', name="'+Qt.btoa(contact.name)+'", screen_name="'+contact.screen_name+'", location="'+contact.location+'",description="'+Qt.btoa(contact.description)+'", profile_image="'+imagename+'", url="'+contact.url+'" , protected="'+contact.protected+'", followers_count='+contact.followers_count+', friends_count='+contact.friends_count+', created_at="'+ Newsjs.cleanDate(contact.created_at)+'", favourites_count="'+contact.favorites_count+'", utc_offset="'+contact.utc_offset+'", time_zone="'+contact.time_zone+'", statuses_count='+contact.statuses_count+', following="'+contact.following+'", verified ="'+contact.verified+'", statusnet_blocking="'+contact.statusnet_blocking+'", notifications="'+contact.notifictions+'", statusnet_profile_url="'+contact.statusnet_profile_url+'", cid='+contact.cid+', network="'+contact.network+'", isFriend='+isFriend+' where id='+contact.id);
} else {// use insert
result = tx.executeSql('INSERT INTO contacts VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [login.username,contact.id,Qt.btoa(contact.name),contact.screen_name,contact.location,Qt.btoa(contact.description),imagename,contact.url,contact.protected,contact.followers_count, contact.friends_count,Newsjs.cleanDate(contact.created_at),contact.favorites_count,contact.utc_offset,contact.time_zone,contact.statuses_count,contact.following,contact.verfied,contact.statusnet_blocking,contact.notifications,contact.statusnet_profile_url,contact.cid,contact.network,isFriend]);}
});
}
Component.onCompleted: {
if (login==""){Service.initDatabase(db);
}
Helperjs.readField("id",db,"contacts",login.username,function(contacts){contactlist=contacts},"isFriend",1)
}
Tab{
title: qsTr("News")
id: newstab
property string newstabStatus:"news"
source: "qrc:/qml/NewsTab.qml"
}
Tab{
title: qsTr("Friends")
id: friendstab
source: "qrc:/qml/FriendsTab.qml"
}
Tab{
title: qsTr("Photos")
id: fotostab
source: "qrc:/qml/PhotoTab.qml"
}
Tab{
title: qsTr("Config")
source: "qrc:/qml/ConfigTab.qml"
}
}