diff --git a/CHANGELOG.md b/CHANGELOG.md index ad9982e..d1ebb21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,23 +84,26 @@ ## v0.3.2 ## * For news containing url ending with mp3, mp4, avi, webm, ogg: media can be played in app -* Pictures can be renamed or moved to another album -* Bugfix: random crashes for conversations -* Bugfix: attach image to message works again -* Bugfix: check for nickname on Server has been removed due to API change +* Pictures can be renamed or moved to another album +* Bugfix: random crashes for conversations +* Bugfix: attach image to message works again +* Bugfix: check for nickname on Server has been removed due to API change ## v0.3.3 ## -* Update for OpenSSL and At -* Experimental support for Peertube (links are expanded to video widget) -* Some Unicode emojis -* Redesign of contact details (click on contact opens in new stack and shows last news) - +* Update for OpenSSL and At +* Experimental support for Peertube (links are expanded to video widget) +* Some Unicode emojis +* Redesign of contact details (click on contact opens in new stack and shows last news) ## v0.3.4 ## -* Direct message creation from profile page works again -* Profile image upload works again -* Viewing private album pictures of contacts works again -* On first start servername from https://dir.friendica.social/servers/surprise selected -* Register button opens webview of registration page on server +* Direct message creation from profile page works again +* Profile image upload works again +* Viewing private album pictures of contacts works again +* On first start servername from https://dir.friendica.social/servers/surprise selected +* Register button opens webview of registration page on server +## v0.4 ## +* Background sync for friends timeline (interval on config page must be > 0) for Android > 5 +* Replies timeline +* Bugfix: App asks for storage permission on first start diff --git a/README.md b/README.md index 72efcea..b373f84 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ QML based client for the Friendica Social Network. # News # Currently supported: -* Shows Posts from friends, selected group, favorited messages, public timeline, Direct Messages and notifications +* Shows Posts from friends, selected group, replies, favorited messages, public timeline, Direct Messages and notifications +* Background sync with configurable interval of 15 min to 2h for active contact for friends timeline (Android 5 required) * Search button for news * Click on hashtag in newsitem starts search for news with that word * Click on image shows image fullscreen diff --git a/source-android/android/AndroidManifest.xml b/source-android/android/AndroidManifest.xml index 713a51d..516839e 100644 --- a/source-android/android/AndroidManifest.xml +++ b/source-android/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + @@ -49,6 +49,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source-android/android/build.gradle b/source-android/android/build.gradle index 4b3e83a..8d9aacb 100644 --- a/source-android/android/build.gradle +++ b/source-android/android/build.gradle @@ -20,6 +20,13 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } +//apply plugin: 'android-library' + +dependencies { + compile 'com.android.support:support-v4:25.3.1' +} + + android { /******************************************************* * The following variables: @@ -56,4 +63,4 @@ android { } } apply from: "androidnative.gradle" - setAndroidNativePath("/../androidnative.pri"); \ No newline at end of file + setAndroidNativePath("/../androidnative.pri"); diff --git a/source-android/android/src/FriendiqaActivity.java b/source-android/android/src/FriendiqaActivity.java index ce892f3..dc9b643 100644 --- a/source-android/android/src/FriendiqaActivity.java +++ b/source-android/android/src/FriendiqaActivity.java @@ -2,10 +2,6 @@ package androidnative.friendiqa; import androidnative.AndroidNativeActivity; - - - - public class FriendiqaActivity extends AndroidNativeActivity { public FriendiqaActivity() { super(); @@ -13,8 +9,4 @@ public class FriendiqaActivity extends AndroidNativeActivity { QT_ANDROID_THEMES = new String[] {""}; QT_ANDROID_DEFAULT_THEME = ""; } - - - - } diff --git a/source-android/android/src/FriendiqaNotifierService.java b/source-android/android/src/FriendiqaNotifierService.java new file mode 100644 index 0000000..ee17178 --- /dev/null +++ b/source-android/android/src/FriendiqaNotifierService.java @@ -0,0 +1,96 @@ +package androidnative.friendiqa; +import androidnative.SystemDispatcher; +import android.app.Notification; +import android.app.NotificationManager; +import android.util.Log; +import android.os.Handler; +import android.app.Activity; +import android.view.View; +import android.content.Context; +import java.util.Map; +import org.qtproject.qt5.android.QtNative; + +public class FriendiqaNotifierService { + + static { + + SystemDispatcher.addListener(new SystemDispatcher.Listener() { + + NotificationManager m_notificationManager; + Notification.Builder m_builder; + + private void notificationManagerNotify(Map data) { + + final Activity activity = QtNative.activity(); + final Map messageData = data; + + Runnable runnable = new Runnable () { + public void run() { + try { + String title = (String) messageData.get("title"); + + String message = (String) messageData.get("message"); + + if (m_notificationManager == null) { + m_notificationManager = (NotificationManager) activity.getSystemService(Context.NOTIFICATION_SERVICE); + m_builder = new Notification.Builder(activity); + + // Small Icon is a must to make notification works. + // And that is why you need to inherit QtActivity + //m_builder.setSmallIcon(drawable.icon); + } + + m_builder.setContentTitle(title); + m_builder.setContentText(message); + m_notificationManager.notify(1, m_builder.build()); + + // Test function. Remove it later. + SystemDispatcher.dispatch("Notifier.notifyFinished"); + } catch (Exception e) { + Log.d("",e.getMessage()); + } + + }; + }; + activity.runOnUiThread(runnable); + } + + private void hapticFeedbackPerform(Map data) { + + final Activity activity = QtNative.activity(); + final Map messageData = data; + Runnable runnable = new Runnable () { + public void run() { + int feedbackConstant = (Integer) messageData.get("feedbackConstant"); + int flags = (Integer) messageData.get("flags"); + + Log.d("",String.format("hapticFeedbackPerform(%d,%d)",feedbackConstant,flags)); + + View rootView = activity.getWindow().getDecorView().getRootView(); + rootView.performHapticFeedback(feedbackConstant, flags); + + // Test function. Remove it later. + SystemDispatcher.dispatch("hapticFeedbackPerformFinished"); + }; + }; + activity.runOnUiThread(runnable); + } + + public void onDispatched(String name , Map data) { + + if (name.equals("Notifier.notify")) { + notificationManagerNotify(data); + return; + } else if (name.equals("hapticFeedbackPerform")) { + hapticFeedbackPerform(data); + return; + } + + return; + } + }); + + } + +} + diff --git a/source-android/android/src/FriendiqaService.java b/source-android/android/src/FriendiqaService.java new file mode 100644 index 0000000..9115a03 --- /dev/null +++ b/source-android/android/src/FriendiqaService.java @@ -0,0 +1,35 @@ +package androidnative.friendiqa; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import android.app.job.JobService; +import android.app.job.JobParameters; +import androidnative.AndroidNativeService; +import org.qtproject.qt5.android.bindings.QtService; +import org.qtproject.qt5.android.QtNative; +//import androidnative.friendiqa.FriendiqaQtService; + +public class FriendiqaService extends JobService{ + private static String TAG = "AndroidNative"; + //Log.e(TAG,"Service"); + + + @Override + public boolean onStartJob(JobParameters params) { + //Log.d(TAG,"Friendiqa JobService"); + Context context = this.getApplicationContext(); + AndroidNativeService fs = new AndroidNativeService(); + fs.startQtService(context); + jobFinished(params,false); + //Intent serviceIntent = new Intent(this, AndroidNativeService.class); + //startService(serviceIntent); + return false; + } + + @Override + public boolean onStopJob(JobParameters params) { + // whether or not you would like JobScheduler to automatically retry your failed job. + return false; + } +} + diff --git a/source-android/android/src/FriendiqaStopService.java b/source-android/android/src/FriendiqaStopService.java new file mode 100644 index 0000000..e483d62 --- /dev/null +++ b/source-android/android/src/FriendiqaStopService.java @@ -0,0 +1,40 @@ +package androidnative.friendiqa; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import android.app.job.JobService; +import android.app.job.JobParameters; +import androidnative.AndroidNativeService; +import org.qtproject.qt5.android.bindings.QtService; +import org.qtproject.qt5.android.QtNative; +//import androidnative.friendiqa.FriendiqaQtService; + +public class FriendiqaStopService extends JobService{ + private static String TAG = "AndroidNative"; + //Log.e(TAG,"Service"); + + + @Override + public boolean onStartJob(JobParameters params) { + //Log.d(TAG,"Friendiqa JobServiceStop"); + Context context = this.getApplicationContext(); + AndroidNativeService fs = new AndroidNativeService(); + fs.stopQtService(context); + jobFinished(params,false); + //Intent serviceIntent = new Intent(this, AndroidNativeService.class); + //startService(serviceIntent); + return false; + } + + @Override + public boolean onStopJob(JobParameters params) { + // whether or not you would like JobScheduler to automatically retry your failed job. + return true; + } + @Override + public boolean onUnbind(Intent intent) { + stopSelf(); + return super.onUnbind(intent); + } + +} diff --git a/source-android/androidnative.pri/java/src/androidnative/AndroidNativeActivity.java b/source-android/androidnative.pri/java/src/androidnative/AndroidNativeActivity.java index 2a8eab1..4d9d745 100644 --- a/source-android/androidnative.pri/java/src/androidnative/AndroidNativeActivity.java +++ b/source-android/androidnative.pri/java/src/androidnative/AndroidNativeActivity.java @@ -4,6 +4,11 @@ import android.util.Log; import android.app.Activity; import android.os.*; import java.util.Map; +import android.content.pm.PackageManager; +import android.content.Context; +import android.Manifest.permission; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; /** An alternative Activity class for Qt applicaiton. @@ -11,6 +16,8 @@ import java.util.Map; */ public class AndroidNativeActivity extends org.qtproject.qt5.android.bindings.QtActivity { + public static final int MY_PERMISSIONS_REQUEST_WRITE_STORAGE = 0x245285a8; + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -21,6 +28,17 @@ public class AndroidNativeActivity extends org.qtproject.qt5.android.bindings.Qt protected void onResume() { super.onResume(); + if (ContextCompat.checkSelfPermission(this,android.Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) { + + // Permission is not granted + + ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},MY_PERMISSIONS_REQUEST_WRITE_STORAGE); + + // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an + // app-defined int constant. The callback method gets the + // result of the request. + } else { + System.loadLibrary("friendiqa"); if((getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) || (getIntent().getFlags() == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) || (getIntent().getFlags() == Intent.FLAG_ACTIVITY_NEW_TASK) || (getIntent().getFlags() == Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) || (getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))) { SystemDispatcher.onActivityResume(); @@ -48,6 +66,25 @@ public class AndroidNativeActivity extends org.qtproject.qt5.android.bindings.Qt SystemDispatcher.onActivityResume(); }} } + } + + + + + @Override public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults) { + switch (requestCode) { + case MY_PERMISSIONS_REQUEST_WRITE_STORAGE: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + SystemDispatcher.onActivityResume(); + } else { + } + return; + } + } +} + + protected void onNewIntent(Intent data) { System.loadLibrary("friendiqa"); diff --git a/source-android/androidnative.pri/java/src/androidnative/AndroidNativeService.java b/source-android/androidnative.pri/java/src/androidnative/AndroidNativeService.java new file mode 100644 index 0000000..ef0d8bf --- /dev/null +++ b/source-android/androidnative.pri/java/src/androidnative/AndroidNativeService.java @@ -0,0 +1,23 @@ +package androidnative; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import org.qtproject.qt5.android.bindings.QtService; + +public class AndroidNativeService extends QtService + { + private static String TAG = "AndroidNative"; + + public void startQtService(Context ctx) { + Log.d(TAG,"Friendiqa QtService"); + ctx.startService(new Intent(ctx, AndroidNativeService.class)); + } + + public static void stopQtService(Context ctx) { + Log.d(TAG,"Friendiqa QtServiceStop"); + + ctx.stopService(new Intent(ctx, AndroidNativeService.class)); + } + + + } diff --git a/source-android/androidnative.pri/java/src/androidnative/Util.java b/source-android/androidnative.pri/java/src/androidnative/Util.java index d016af5..6ff5819 100644 --- a/source-android/androidnative.pri/java/src/androidnative/Util.java +++ b/source-android/androidnative.pri/java/src/androidnative/Util.java @@ -6,9 +6,15 @@ import android.util.Log; import android.view.View; import android.view.Window; import android.view.WindowManager; - +import android.content.Context; +import android.content.ComponentName; +import android.app.job.JobScheduler; +import android.app.job.JobInfo; import org.qtproject.qt5.android.QtNative; - +import androidnative.friendiqa.FriendiqaService; +import androidnative.friendiqa.FriendiqaStopService; +import androidnative.AndroidNativeService; +import android.content.Intent; import java.util.Map; public class Util { @@ -17,6 +23,7 @@ public class Util { public static final String SET_TRANSLUCENT_STATUS_BAR = "androidnative.Util.setTranslucentStatusBar"; public static final String SET_FULL_SCREEN = "androidnative.Util.setFullScreen"; + public static final String SET_SCHEDULE = "androidnative.Util.setSchedule"; static { @@ -26,6 +33,8 @@ public class Util { setTranslucentStatusBar(message); } else if (type.equals(SET_FULL_SCREEN)) { setFullScreen(message); + } else if (type.equals(SET_SCHEDULE)) { + setSchedule(message); } } }); @@ -62,6 +71,10 @@ public class Util { return; } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return; + } + final Boolean value = (Boolean) message.get("value"); final Activity activity = QtNative.activity(); @@ -84,4 +97,52 @@ public class Util { activity.runOnUiThread(runnable); } + + static void setSchedule(Map message) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return; + } + Log.d(TAG,"Friendiqa schedule Androidnative service"); + final Integer value = (Integer) message.get("value"); + //final Activity activity = QtNative.activity(); + //final Service service = QtNative.service(); + //final int JOB_ID = 1; + final int ONE_MIN = 60 * 1000; + Context context; + if (QtNative.activity() == null){ + context = QtNative.service().getApplicationContext(); + + } else { + context = QtNative.activity().getApplicationContext(); + } + ComponentName component = new ComponentName(context, FriendiqaService.class); + JobInfo.Builder builder = new JobInfo.Builder(2, component) + // schedule it to run any time between 1 - 5 minutes + .setMinimumLatency(value * ONE_MIN) + .setOverrideDeadline((value + 5)*ONE_MIN) + //.setPeriodic(value * ONE_MIN) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + jobScheduler.schedule(builder.build()); + + if (QtNative.service() != null){ + Log.d(TAG,"Schedule Stopping Friendiqa Androidnative service"); + ComponentName componentStopper = new ComponentName(context, FriendiqaStopService.class); + JobInfo.Builder stopbuilder = new JobInfo.Builder(1, componentStopper) + .setMinimumLatency(50) + .setOverrideDeadline(100); + + JobScheduler jobStopScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + jobStopScheduler.schedule(stopbuilder.build()); + + + //AndroidNativeService.stopQtService(context); + } + //context.stopService(new Intent(context, AndroidNativeService.class)); + } + + /**static void stopService(Map message){ + this.stopService(new Intent(this, AndroidNativeService.class)); + } + **/ } diff --git a/source-android/application.qrc b/source-android/application.qrc index d890962..9bb98a7 100644 --- a/source-android/application.qrc +++ b/source-android/application.qrc @@ -225,5 +225,7 @@ qml/newsqml/ContactPage.qml qml/newsqml/NewsLink.qml qml/configqml/RegisterPage.qml + qml/newsqml/NewsYplayer.qml + js/yplayer.html diff --git a/source-android/common/alarm.h b/source-android/common/alarm.h new file mode 100644 index 0000000..a3b3ede --- /dev/null +++ b/source-android/common/alarm.h @@ -0,0 +1,59 @@ +// This file is part of Friendiqa +// https://git.friendi.ca/lubuwest/Friendiqa +// Copyright (C) 2017 Marco R. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations including +// the two. +// +// You must obey the GNU General Public License in all respects for all +// of the code used other than OpenSSL. If you modify file(s) with this +// exception, you may extend this exception to your version of the +// file(s), but you are not obligated to do so. If you do not wish to do +// so, delete this exception statement from your version. If you delete +// this exception statement from all source files in the program, then +// also delete it here. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef ALARM_H +#define ALARM_H + +#include + +class ALARM : public QObject +{ + Q_OBJECT + //Q_PROPERTY(int alarmtime READ alarmtime WRITE setAlarm NOTIFY alarmChanged) +public: + static ALARM *instance(); + + explicit ALARM(QObject *parent = 0); + + //int alarmtime() const; + +signals: + + void alarmChanged(QString url); + +public slots: + void setAlarm(int time); + +private: + int m_time; +}; + +#endif // UPDATENEWS_H diff --git a/source-android/common/alarmandroid.cpp b/source-android/common/alarmandroid.cpp new file mode 100644 index 0000000..49dc694 --- /dev/null +++ b/source-android/common/alarmandroid.cpp @@ -0,0 +1,82 @@ +// This file is part of Friendiqa +// https://git.friendi.ca/lubuwest/Friendiqa +// Copyright (C) 2017 Marco R. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations including +// the two. +// +// You must obey the GNU General Public License in all respects for all +// of the code used other than OpenSSL. If you modify file(s) with this +// exception, you may extend this exception to your version of the +// file(s), but you are not obligated to do so. If you do not wish to do +// so, delete this exception statement from your version. If you delete +// this exception statement from all source files in the program, then +// also delete it here. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//#include +//#include +#include "alarm.h" +#include +#include "AndroidNative/systemdispatcher.h" + +ALARM *ALARM::instance() +{ + static ALARM alarm; + return &alarm; +} + +ALARM::ALARM(QObject *parent) : QObject(parent){} + +void ALARM::setAlarm(int interval) +{ + qDebug() << interval; + QVariantMap message; + message["value"] = interval; + AndroidNative::SystemDispatcher::instance()->loadClass("androidnative.Util"); + AndroidNative::SystemDispatcher::instance()->dispatch("androidnative.Util.setSchedule", message); + //AndroidNative::SystemDispatcher::instance()->dispatch("androidnative.Util.stopService", message); +// auto activity = QtAndroid::androidActivity(); +// auto packageManager = activity.callObjectMethod("getPackageManager", +// "()Landroid/content/pm/PackageManager;"); + +// auto activityIntent = packageManager.callObjectMethod("getLaunchIntentForPackage", +// "(Ljava/lang/String;)Landroid/content/Intent;", +// activity.callObjectMethod("getPackageName", +// "()Ljava/lang/String;").object()); + +// auto pendingIntent = QAndroidJniObject::callStaticObjectMethod("android/app/PendingIntent", "getActivity", +// "(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;", +// activity.object(), jint(0), activityIntent.object(), +// QAndroidJniObject::getStaticField("android/content/Intent", +// "FLAG_ACTIVITY_CLEAR_TOP")); + +// auto alarmManager = activity.callObjectMethod("getSystemService", +// "(Ljava/lang/String;)Ljava/lang/Object;", +// QAndroidJniObject::getStaticObjectField("android/content/Context", +// "ALARM_SERVICE", +// "Ljava/lang/String;").object()); + +// alarmManager.callMethod("set", +// "(IJLandroid/app/PendingIntent;)V", +// QAndroidJniObject::getStaticField("android/app/AlarmManager", "RTC"), +// jlong(QDateTime::currentMSecsSinceEpoch() + 100), pendingIntent.object()); + + +} + diff --git a/source-android/common/friendiqa.cpp b/source-android/common/friendiqa.cpp index 8a0280c..361cf88 100644 --- a/source-android/common/friendiqa.cpp +++ b/source-android/common/friendiqa.cpp @@ -31,10 +31,14 @@ #include #include +#include +#include #include #include "xhr.h" +#include "updatenews.h" #include "filesystem.h" #include "remoteauthasyncimageprovider.h" +#include "alarm.h" #include "AndroidNative/systemdispatcher.h" #include "AndroidNative/environment.h" //#include "AndroidNative/debug.h" @@ -55,6 +59,20 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { int main(int argc, char *argv[]) { + //qDebug()<< "argv Friendiqa"<< argv[0] <<" argv2" <setDatabase(); + updatenews->login(); + updatenews->timeline(); + app.connect (updatenews,SIGNAL(quitapp()),&app,SLOT(quit())); + //QtAndroid::androidService().callMethod("stopSelf"); + return app.exec(); + } + else{ + QApplication app(argc, argv); QQuickView view; QTranslator qtTranslator; @@ -67,10 +85,14 @@ int main(int argc, char *argv[]) { view.rootContext()->setContextProperty("xhr", xhr); FILESYSTEM* filesystem = FILESYSTEM::instance(); view.rootContext()->setContextProperty("filesystem", filesystem); + ALARM* alarm = ALARM::instance(); + view.rootContext()->setContextProperty("alarm", alarm); +// UPDATENEWS* updatenews = UPDATENEWS::instance(); +// view.rootContext()->setContextProperty("updatenews", updatenews); view.setSource(QUrl("qrc:/qml/friendiqa.qml")); view.show(); view.connect(view.rootContext()->engine(), SIGNAL(quit()), &app, SLOT(quit())); return app.exec(); - + } } diff --git a/source-android/common/updatenews.cpp b/source-android/common/updatenews.cpp new file mode 100644 index 0000000..008f92e --- /dev/null +++ b/source-android/common/updatenews.cpp @@ -0,0 +1,399 @@ +// This file is part of Friendiqa +// https://git.friendi.ca/lubuwest/Friendiqa +// Copyright (C) 2017 Marco R. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations including +// the two. +// +// You must obey the GNU General Public License in all respects for all +// of the code used other than OpenSSL. If you modify file(s) with this +// exception, you may extend this exception to your version of the +// file(s), but you are not obligated to do so. If you do not wish to do +// so, delete this exception statement from your version. If you delete +// this exception statement from all source files in the program, then +// also delete it here. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "updatenews.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "AndroidNative/systemdispatcher.h" + + + +UPDATENEWS *UPDATENEWS::instance() +{ + static UPDATENEWS udn; + return &udn; +} + +UPDATENEWS::UPDATENEWS(QObject *parent) : QObject(parent) +{ + +} + +void UPDATENEWS::setUrl(QString url) +{ + if (url!=m_url) { + m_url = url; + xhr.setUrl(url); + emit urlChanged(m_url); + } +} + + +void UPDATENEWS::setDatabase() +{ + static QQmlEngine qe; + QString db_url=qe.offlineStorageDatabaseFilePath("Friendiqa"); + m_db = QSqlDatabase::addDatabase("QSQLITE"); + m_db.setDatabaseName(QUrl("file://"+db_url+".sqlite").toLocalFile()); + //qDebug() << db_url; + + if (!m_db.open()) + { + qDebug() << "Error: connection with database fail " << m_db.lastError(); + } +} + + +void UPDATENEWS::login() +{ + QSqlQuery query("SELECT * FROM config WHERE isActive=0",m_db); + while (query.next()) + { + username = query.value(1).toString(); + QByteArray bpassword=query.value(2).toByteArray(); + QString password=QByteArray::fromBase64(bpassword); + m_login=username+":"+password ; + xhr.setLogin(m_login); + m_url=query.value(0).toString(); + xhr.setUrl(m_url); + m_imagedir=query.value(3).toString(); + xhr.setImagedir(m_imagedir); + QString isActive=query.value(7).toString(); + m_updateInterval=query.value(5).toInt(); + m_api="/api/statuses/friends_timeline"; + xhr.setApi(m_api); + } +} + + +void UPDATENEWS::timeline() +{ + qDebug()<<"Friendiqa start timeline"; + QSqlQuery query("SELECT status_id FROM news WHERE username='"+ username +"' ORDER BY status_id DESC LIMIT 1",m_db); + if (query.isActive() && query.isSelect()){query.first();}; + QString lastid=query.value(0).toString(); + xhr.clearParams(); + xhr.setParam("since_id",lastid); + xhr.setParam("count","50"); + xhr.get(); + QObject::connect(&xhr,SIGNAL(success(QByteArray,QString)),this,SLOT(store(QByteArray,QString))); + QObject::connect(&xhr,SIGNAL(error(QString,QString,QString,int)),this,SLOT(showError(QString,QString,QString,int))); +} + + +//void UPDATENEWS::startservice(QString type,QVariantMap map) +//{ +// qDebug ()<<"Friediqa start service "<error(m_api,QTextCodec::codecForName("utf-8")->toUnicode(serverreply)); + if(m_updateInterval!=0){ + m_db.close(); + m_db.removeDatabase(m_db.connectionName()); + emit quitapp(); + alarm.setAlarm(m_updateInterval); + }; + } + QList newcontacts=findNewContacts(news); + updateContacts(newcontacts); + startImagedownload(); + connect(&xhr, SIGNAL(downloaded(QString, QString, QString, int)), this, SLOT(updateImageLocation(QString,QString, QString, int))); + +} + +void UPDATENEWS::updateImageLocation(QString downloadtype,QString imageurl, QString filename, int index){ + if (downloadtype=="contactlist"){ + QSqlQuery testquery("SELECT profile_image FROM contacts WHERE profile_image_url ='"+imageurl+ "' AND username = '" +username+"'",m_db); + testquery.exec(); + //qDebug()<< "update imageurl for " < UPDATENEWS::findNewContacts(QJsonDocument news){ + QSqlQuery query("SELECT profile_image_url FROM contacts",m_db); + QList imageurls; + while (query.next()){ + imageurls.append(query.value(0).toString()); + } + QList newcontacts; + qDebug()<<"updatenews findcontacts count "< contacts){ + qint64 currentTime =QDateTime::currentMSecsSinceEpoch(); + for (int i=0; i < contacts.count();i++){ + QJsonValue contact=contacts[i]; + QSqlQuery query(m_db); + //qDebug() << "updatecontact " << contact["screen_name"]; + QSqlQuery testquery("SELECT url FROM contacts WHERE username='"+ username +"' AND url='" + contact["url"].toString() +"'",m_db); + if (testquery.first()){ + query.prepare("UPDATE contacts SET id=?, name=?, screen_name=?, location=?,imageAge=?," + "profile_image_url=?, description=?, protected=?, followers_count=?," + "friends_count=?, created_at=?, favourites_count=?, utc_offset=?, time_zone=?, statuses_count=?," + "following=?, verified=?, statusnet_blocking=?, notifications=?, statusnet_profile_url=?, cid=?, network=?, timestamp=? " + " WHERE username='"+ username +"' AND url='" + contact["url"].toString() +"'"); + query.bindValue(0, contact["id"].toInt()); + query.bindValue(1, contact["name"].toString().toUtf8().toBase64()); + query.bindValue(2, contact["screen_name"]); + query.bindValue(3, contact["location"]); + query.bindValue(4, currentTime); + query.bindValue(5, contact["profile_image_url"]); + if(contact["description"].isNull() ){query.bindValue(6,"");}else{query.bindValue(6, contact["description"].toString().toUtf8().toBase64());}; + query.bindValue(7,contact["protected"].toBool()); + query.bindValue(8,contact["followers_count"].toInt()); + query.bindValue(9,contact["friends_count"].toInt()); + QString sourcedate=contact["created_at"].toString(); + QString formateddate=sourcedate.mid(0,3)+", "+sourcedate.mid(8,3)+sourcedate.mid(4,3)+sourcedate.mid(25,5)+sourcedate.mid(10,15); + query.bindValue(10,QDateTime::fromString(formateddate,Qt::RFC2822Date).toMSecsSinceEpoch() ); + query.bindValue(11,contact["favorites_count"].toInt()); + query.bindValue(12,contact["utc_offset"].toInt()); + query.bindValue(13,contact["time_zone"].toString()); + query.bindValue(14,contact["statuses_count"].toInt()); + query.bindValue(15,contact["following"].toBool()); + query.bindValue(16,contact["verfied"].toBool()); + query.bindValue(17,contact["statusnet_blocking"].toBool()); + query.bindValue(18,contact["notifications"].toBool()); + query.bindValue(19,contact["statusnet_profile_url"]); + query.bindValue(20,contact["cid"].toInt()); + query.bindValue(21,contact["network"]); + qint64 timestamp=0; + QString timestamphelper=contact["profile_image_url"].toString(); + try {timestamp=timestamphelper.mid(timestamphelper.indexOf("?ts")+4,timestamphelper.length()).toUInt();} catch(...){}; + query.bindValue(22,timestamp); + } + + else{ + query.prepare("INSERT INTO contacts (username, id, name, screen_name, location,imageAge," + "profile_image_url, description, profile_image, url, protected, followers_count," + "friends_count, created_at, favourites_count, utc_offset, time_zone, statuses_count," + "following, verified, statusnet_blocking, notifications, statusnet_profile_url, cid, network, isFriend, timestamp)" + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); + + query.bindValue(0,username); + query.bindValue(1, contact["id"].toInt()); + query.bindValue(2, contact["name"].toString().toUtf8().toBase64()); + query.bindValue(3, contact["screen_name"]); + query.bindValue(4, contact["location"]); + query.bindValue(5, currentTime); + query.bindValue(6, contact["profile_image_url"]); + if(contact["description"].isNull() ){query.bindValue(7,"");}else{query.bindValue(7, contact["description"].toString().toUtf8().toBase64());}; + query.bindValue(8,"none"); + query.bindValue(9, contact["url"].toString()); + query.bindValue(10,contact["protected"].toBool()); + query.bindValue(11,contact["followers_count"].toInt()); + query.bindValue(12,contact["friends_count"].toInt()); + QString sourcedate=contact["created_at"].toString(); + QString formateddate=sourcedate.mid(0,3)+", "+sourcedate.mid(8,3)+sourcedate.mid(4,3)+sourcedate.mid(25,5)+sourcedate.mid(10,15); + query.bindValue(13,QDateTime::fromString(formateddate,Qt::RFC2822Date).toMSecsSinceEpoch() ); + query.bindValue(14,contact["favorites_count"].toInt()); + query.bindValue(15,contact["utc_offset"].toInt()); + query.bindValue(16,contact["time_zone"].toString()); + query.bindValue(17,contact["statuses_count"].toInt()); + query.bindValue(18,contact["following"].toBool()); + query.bindValue(19,contact["verfied"].toBool()); + query.bindValue(20,contact["statusnet_blocking"].toBool()); + query.bindValue(21,contact["notifications"].toBool()); + query.bindValue(22,contact["statusnet_profile_url"]); + query.bindValue(23,contact["cid"].toInt()); + query.bindValue(24,contact["network"]); + query.bindValue(25, 0); + qint64 timestamp=0; + QString timestamphelper=contact["profile_image_url"].toString(); + try {timestamp=timestamphelper.mid(timestamphelper.indexOf("?ts")+4,timestamphelper.length()).toUInt();} catch(...){}; + query.bindValue(26,timestamp); + + } + query.exec() ; + } + emit this->success(m_api); + if ((contacts.count()==0) && (m_updateInterval!=0)){ + m_db.close(); + m_db.removeDatabase(m_db.connectionName()); + emit quitapp(); + alarm.setAlarm(m_updateInterval); + }; +} + +QString UPDATENEWS::url() const +{ + return m_url; +} + +void UPDATENEWS::startImagedownload() +{ + xhr.setDownloadtype("contactlist"); + xhr.setFilelist(newcontactimagelinks); + xhr.setContactlist(newcontactnames); + xhr.setImagedir(m_imagedir); + xhr.getlist(); +} + +void UPDATENEWS::showError(QString data, QString url,QString api, int code ) +{ + emit this->error(api,data); + if(m_updateInterval!=0){ + m_db.close(); + m_db.removeDatabase(m_db.connectionName()); + emit quitapp(); + alarm.setAlarm(m_updateInterval); + }; +} diff --git a/source-android/common/updatenews.h b/source-android/common/updatenews.h new file mode 100644 index 0000000..1acc52c --- /dev/null +++ b/source-android/common/updatenews.h @@ -0,0 +1,92 @@ +// This file is part of Friendiqa +// https://git.friendi.ca/lubuwest/Friendiqa +// Copyright (C) 2017 Marco R. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations including +// the two. +// +// You must obey the GNU General Public License in all respects for all +// of the code used other than OpenSSL. If you modify file(s) with this +// exception, you may extend this exception to your version of the +// file(s), but you are not obligated to do so. If you do not wish to do +// so, delete this exception statement from your version. If you delete +// this exception statement from all source files in the program, then +// also delete it here. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef UPDATENEWS_H +#define UPDATENEWS_H + +#include +#include +#include +#include "xhr.h" +#include "alarm.h" +#include "AndroidNative/systemdispatcher.h" + +class UPDATENEWS : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) +// Q_PROPERTY(QString login READ login NOTIFY loginChanged) +public: + static UPDATENEWS *instance(); + + explicit UPDATENEWS(QObject *parent = 0); + + QString url() const; + //QString login() const; + +signals: + + void urlChanged(QString url); + void success(QString api); + void error(QString api, QString content); + void quitapp(); + +public slots: + void setUrl(QString url); + void setDatabase(); + void login(); + void timeline(); + //void startservice(QString type,QVariantMap map); + void startImagedownload(); + void updateImageLocation(QString downloadtype,QString imageurl, QString filename, int index); + void store(QByteArray serverreply,QString apiname); + void showError(QString data, QString url,QString api, int code); + +private: + QString m_url; + QString m_api; + QString m_imagedir; + QString m_login; + QString username; + QSqlDatabase m_db; + QList findNewContacts(QJsonDocument news); + int m_updateInterval; + //void timeline(); + //void store(QByteArray serverreply,QString apiname); + void updateContacts(QList contacts); + + XHR xhr; + ALARM alarm; + QList newcontactimagelinks; + QList newcontactnames; +}; + +#endif // UPDATENEWS_H diff --git a/source-android/common/xhr.cpp b/source-android/common/xhr.cpp index 72940d2..7df4deb 100644 --- a/source-android/common/xhr.cpp +++ b/source-android/common/xhr.cpp @@ -290,7 +290,7 @@ void XHR::onReplyError(QNetworkReply::NetworkError code) void XHR::onReplySuccess() { qDebug() << "!"; - emit this->success( bufferToString(), m_api); + emit this->success(buffer, m_api); buffer.clear(); // reply->deleteLater(); } diff --git a/source-android/common/xhr.h b/source-android/common/xhr.h index d56f23f..ad50a60 100644 --- a/source-android/common/xhr.h +++ b/source-android/common/xhr.h @@ -79,7 +79,7 @@ signals: void networktypeChanged(); void downloaded(QString type, QString url, QString filename, int i); void downloadedjson(QString type, QString url, QString filename, int i,QJsonObject jsonObject); - void success(QString data, QString api); + void success(QByteArray data, QString api); void error(QString data, QString url,QString api, int code); public slots: diff --git a/source-android/friendiqa.pro b/source-android/friendiqa.pro index 1eabae6..5d84450 100644 --- a/source-android/friendiqa.pro +++ b/source-android/friendiqa.pro @@ -21,7 +21,9 @@ SOURCES += common/friendiqa.cpp \ common/uploadableimage.cpp \ common/xhr.cpp \ common/filesystem.cpp \ - common/remoteauthasyncimageprovider.cpp + common/remoteauthasyncimageprovider.cpp \ + common/updatenews.cpp \ + common/alarmandroid.cpp ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android @@ -38,14 +40,17 @@ OTHER_FILES += qml/friendiqa.qml \ js/*.js TRANSLATIONS += translations/friendiqa-de.ts \ - translations/friendiqa-es.ts + translations/friendiqa-es.ts \ + translations/friendiqa-it.ts HEADERS += \ common/uploadableimage.h \ common/xhr.h \ common/filesystem.h \ - common/remoteauthasyncimageprovider.h - + common/remoteauthasyncimageprovider.h \ + common/updatenews.h \ + common/alarm.h + DISTFILES += \ qml/calendarqml/*.qml \ android/AndroidManifest.xml \ diff --git a/source-android/js/helper.js b/source-android/js/helper.js index ac113d1..1a22e3d 100644 --- a/source-android/js/helper.js +++ b/source-android/js/helper.js @@ -95,6 +95,20 @@ function friendicaWebRequest(url,rootwindow,callback) { xhrequest.send(); } +function friendicaXmlRequest(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.responseXML)} + catch (e){showMessage("Error","API:\n" +url+" "+e+"\n Return: "+xhrequest.responseText, rootwindow)} + } + } + xhrequest.open("GET", url); + xhrequest.responseType ="document"; + xhrequest.send(); +} + function friendicaRemoteAuthRequest(login,url,c_url,rootwindow,callback) { var xhrequest = new XMLHttpRequest(); xhrequest.onreadystatechange = function() { diff --git a/source-android/js/news.js b/source-android/js/news.js index 2b266fe..c9407e4 100644 --- a/source-android/js/news.js +++ b/source-android/js/news.js @@ -465,7 +465,7 @@ function chatsfromdb(database,user,callback,stop_time){ helpernews.statusnet_html=Qt.atob(helpernews.statusnet_html); helpernews.text=Qt.atob(helpernews.text); helpernews.id=helpernews.status_id; - if (helpernews.attachments!==null){print(Qt.atob(helpernews.attachments));helpernews.attachments=JSON.parse(Qt.atob(helpernews.attachments))}; + if (helpernews.attachments!==null){helpernews.attachments=JSON.parse(Qt.atob(helpernews.attachments))}; newsArray.push(helpernews); } callback(newsArray); diff --git a/source-android/js/newsworker.js b/source-android/js/newsworker.js index f84d00f..10d5c8a 100644 --- a/source-android/js/newsworker.js +++ b/source-android/js/newsworker.js @@ -135,6 +135,21 @@ else{ if ((attachmentList.length==0) || (attachmentList[attachmentList.length-1].url!=ptvideohelper.url)){attachmentList.push(ptvideohelper)} } } +// if (newsitemobject.text.indexOf("https://www.youtube.com/watch")>-1){ +// //print("message "+msg.options.showWebsiteForLinks); +// if (msg.options.showYoutube!="false"){ +// var ythelper={mimetype:"video/youtube"} +// var yttext=newsitemobject.text; +// while (yttext.indexOf("https://www.youtube.com/watch")>-1){ +// var ythelperstringposition=linktext.indexOf("watch?v="); +// var ytposend=findend(yttext,ythelperstringposition); +// ythelper.url=yttext.substring(yttext.lastIndexOf("http",linkhelperstringposition),linkposend); +// linktext=linktext.substring(linkhelperstringposition+5,linktext.length) +// if ((attachmentList.length==0) || (attachmentList[attachmentList.length-1].url!=linkhelper.url)){attachmentList.push(linkhelper)} +// } +// } +// } + // if (newsitemobject.text.indexOf(".html")>-1){ // //print("message "+msg.options.showWebsiteForLinks); // if (msg.options.showWebsiteForLinks!="false"){ diff --git a/source-android/js/service.js b/source-android/js/service.js index ff2ad99..b375010 100644 --- a/source-android/js/service.js +++ b/source-android/js/service.js @@ -513,9 +513,6 @@ function updateView(viewtype){ //downloadNotice.text="xhr start "+Date.now() switch(viewtype){ case "Conversations": -// updatenews.setDatabase(); -// updatenews.login(); -// updatenews.timeline(); var lastnews=Newsjs.getLastNews(login,db); xhr.setLogin(login.username+":"+Qt.atob(login.password)); xhr.setUrl(login.server); @@ -525,9 +522,6 @@ function updateView(viewtype){ xhr.setParam("count",50) break; case "Timeline": -// updatenews.setDatabase(); -// updatenews.login(); -// updatenews.timeline(); var lastnews=Newsjs.getLastNews(login,db); xhr.setLogin(login.username+":"+Qt.atob(login.password)); xhr.setUrl(login.server); @@ -565,6 +559,12 @@ function updateView(viewtype){ xhr.setApi("/api/favorites"); xhr.clearParams(); break; + case "Replies": + xhr.setLogin(login.username+":"+Qt.atob(login.password)); + xhr.setUrl(login.server); + xhr.setApi("/api/statuses/replies"); + xhr.clearParams(); + break; default: var lastnews=Newsjs.getLastNews(login,db); xhr.setLogin(login.username+":"+Qt.atob(login.password)); @@ -575,8 +575,8 @@ function updateView(viewtype){ xhr.setParam("count",50) newstab.newstabstatus="Conversations"; } - xhr.get(); + xhr.get(); if (viewtype==="Conversations"){Newsjs.allchatsfromdb(db,login.username,function(temp){ newsStack.allchats=temp })} diff --git a/source-android/js/yplayer.html b/source-android/js/yplayer.html new file mode 100644 index 0000000..8222d36 --- /dev/null +++ b/source-android/js/yplayer.html @@ -0,0 +1,45 @@ + + + -1 + + + +
+ + + \ No newline at end of file diff --git a/source-android/qml/configqml/ConfigTab.qml b/source-android/qml/configqml/ConfigTab.qml index 1d20d7b..e13aefd 100644 --- a/source-android/qml/configqml/ConfigTab.qml +++ b/source-android/qml/configqml/ConfigTab.qml @@ -93,99 +93,106 @@ StackView{ } Text { - text: qsTr("Server") - x: 4*mm; y: 10*mm + text: qsTr("Server") + font.pixelSize:3*mm + x: 4*mm; y: 10*mm } Text { - text: qsTr("Nickname") - x: 4*mm; y: 20*mm + text: qsTr("Nickname") + font.pixelSize:3*mm + x: 4*mm; y: 20*mm } Text { text: qsTr("Password") - x: 4*mm; y: 30*mm + font.pixelSize:3*mm + x: 4*mm; y: 30*mm } Text { - text: qsTr("Image dir.") - x: 4*mm; y: 40*mm + text: qsTr("Image dir.") + font.pixelSize:3*mm + x: 4*mm; y: 40*mm } - Text { - text: qsTr("Max. News") - x: 4*mm; y: 50*mm - } - Text { - text: qsTr("News as") - x: 4*mm; y: 60*mm + Text { + text: qsTr("Max. News") + font.pixelSize:3*mm + x: 4*mm; y: 50*mm } Text { - text: qsTr("Interval (0=None)") - visible: false - x: 4*mm; y: 70*mm; width:20*mm;wrapMode: Text.Wrap - } + text: qsTr("News as") + font.pixelSize:3*mm + x: 4*mm; y: 60*mm + } + Text { + text: qsTr("Sync Interval (0=None)") + font.pixelSize:3*mm + //visible: false + x: 4*mm; y: 70*mm; //width:35*mm;wrapMode: Text.Wrap + } -// Text { +// Text { // text: qsTr("Show Website") -// x: 4*mm; y: 70*mm; width: 20*mm -// } +// x: 4*mm; y:80*mm; width: 20*mm +// } - Image{ - id:servericon - x:19*mm;y:10*mm - width:5*mm; height: 5*mm - visible: false - source:"" - MouseArea{ - anchors.fill:parent - onClicked:{ - Service.showServerConfig(servername.text, configBackground, function(configString){ - var serverconfigObject=Qt.createQmlObject(configString,configBackground,"serverconfigOutput");}) - } + Image{ + id:servericon + x:4*mm;y:13.5*mm + width:5*mm; height: 5*mm + visible: false + source:"" + MouseArea{ + anchors.fill:parent + onClicked:{ + Service.showServerConfig(servername.text, configBackground, function(configString){ + var serverconfigObject=Qt.createQmlObject(configString,configBackground,"serverconfigOutput");}) } } + } - BlueButton{ - id:serverSearchButton - text:"\uf002" - x:19*mm - y:10*mm - width: 5*mm; height:5*mm - visible: servericon.visible?false:true - onClicked:{Qt.openUrlExternally(Qt.resolvedUrl("https://dir.friendica.social/servers"))} - } + BlueButton{ + id:serverSearchButton + text:"\uf002" + x:4*mm + y:13.5*mm + width: 5*mm; height:5*mm + visible: servericon.visible?false:true + onClicked:{Qt.openUrlExternally(Qt.resolvedUrl("https://dir.friendica.social/servers"))} + } - - Rectangle{color: "light grey"; 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://..." - onEditingFinished:{ + Rectangle{color: "light grey"; x: 10*mm; y: 13.5*mm; width: root.width-12*mm; height: 5*mm;} + Flickable { + id: servernameFlickable + x: 10*mm; y: 13.5*mm; width: root.width-12*mm; height: 5*mm; + contentWidth: servername.paintedWidth + contentHeight: servername.paintedHeight + clip: true + TextEdit { + id: servername + width: servernameFlickable.width + height: servernameFlickable.height + focus: true + font.pixelSize:3*mm + text:"https://..." + onEditingFinished:{ if((servername.text).substring(0,14) =="https://...http"){ serverstring.text= (serverstring.text).substring(11) } - configBackground.setServericon(servername.text) } onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,servernameFlickable) - } - } + } + } - Rectangle{ - color: "light grey" - x: 25*mm; y: 20*mm; width: root.width/2-9*mm; height: 5*mm; - TextInput { - id: username - anchors.fill: parent - selectByMouse: true + Rectangle{ + color: "light grey" + x: 4*mm; y: 23.5*mm; width: root.width-14*mm; height: 5*mm; + TextInput { + id: username + anchors.fill: parent + font.pixelSize:3*mm + selectByMouse: true onEditingFinished:{ if (username.text.indexOf('@')>-1){ Helperjs.showMessage(qsTr("Error"),qsTr("Nicknames containing @ symbol currently not supported"),configBackground) @@ -201,84 +208,40 @@ StackView{ } } } - BlueButton { - x: root.width/2+18*mm; y: 20*mm; width:7*mm - text: "\uf234" - onClicked: { - configStack.push({item:"qrc:/qml/configqml/RegisterPage.qml",properties:{url:servername.text+"/register?nickname="+username.getText(0,username.length)}}) - } - } + BlueButton { + x: root.width-9*mm; y: 23.5*mm; width:7*mm + text: "\uf234" + onClicked: { + configStack.push({item:"qrc:/qml/configqml/RegisterPage.qml",properties:{url:servername.text+"/register?nickname="+username.getText(0,username.length)}}) + } + } Rectangle{ color: "light grey" - x: 25*mm; y: 30*mm; width: root.width/2; height: 5*mm; + x: 4*mm; y: 33.5*mm; width: root.width-6*mm; height: 5*mm; TextInput { id: password anchors.fill: parent + font.pixelSize:3*mm selectByMouse: true echoMode: TextInput.PasswordEchoOnEdit } } - Rectangle{color: "light grey"; x: 25*mm; y: 40*mm; width: root.width/2-9*mm; height: 5*mm;} + Rectangle{color: "light grey"; x: 4*mm; y: 43.5*mm; width: root.width-14*mm; height: 5*mm;} Flickable { id: imagestoreFlickable - x: 25*mm; y: 40*mm; width: root.width/2-9*mm; height: 5*mm; + x: 4*mm; y: 43.5*mm; width: root.width-14*mm; height: 5*mm; clip: true TextInput { id: imagestore width: imagestoreFlickable.width height: imagestoreFlickable.height + font.pixelSize:3*mm wrapMode: TextEdit.NoWrap onCursorRectangleChanged: Layoutjs.ensureVisibility(cursorRectangle,imagestoreFlickable) } } - Slider{ id: maxNews - x:34*mm; y: 50*mm;width: root.width/3;height:5*mm - minimumValue: 0;maximumValue:2000; stepSize: 100 - } - - - Rectangle{color: "light grey"; 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; - color:"light grey" - Text{ - id: newsTypeField - anchors.fill: parent - text:"Conversations" - } - MouseArea{ - anchors.fill:parent - onClicked:newstypemenu.popup() - } - } - Slider{ id: messageIntervalSlider - visible: false - x:37*mm; y: 70*mm;width: root.width/3;height:5*mm - minimumValue: 0;maximumValue:24; stepSize: 0.5 - } - Rectangle{ - visible:false - x: 25*mm; y: 70*mm; width: 9*mm; height: 5*mm; - TextEdit{ - id: messageIntervalField - anchors.fill: parent - verticalAlignment:TextEdit.AlignRight - text:messageIntervalSlider.value - focus: true - selectByMouse: true - } - } FileDialog { id: imagestoreDialog @@ -290,20 +253,71 @@ StackView{ imagestoreString=imagestoreString.replace(/^(file:\/{2})/,"")+"/" imagestore.text=imagestoreString } - } + } BlueButton { - x: root.width/2+18*mm; y: 40*mm; width: 7*mm; height: 5*mm; + x: root.width-9*mm; y: 43.5*mm; width: 7*mm; height: 5*mm; text: "..." onClicked: {imagestoreDialog.open()} } + Slider{ id: maxNews + x:19*mm; y: 53.5*mm;width: root.width/2;height:5*mm + minimumValue: 0;maximumValue:2000; stepSize: 100 + } + + + Rectangle{color: "light grey"; x: 4*mm; y: 53.5*mm; width: 9*mm; height: 5*mm; + TextEdit{id:maxNewsText; + anchors.fill: parent + font.pixelSize:3*mm + verticalAlignment:TextEdit.AlignRight + text:maxNews.value + focus: true + selectByMouse: true + } + } + + Rectangle{ + x: 4*mm; y: 63.5*mm; width: newsTypeField.contentWidth+2*mm; height: 5*mm; + color:"light grey" + Text{ + id: newsTypeField + anchors.fill: parent + font.pixelSize:3*mm + text:"Conversations" + } + MouseArea{ + anchors.fill:parent + onClicked:newstypemenu.popup() + } + } + Slider{ id: messageIntervalSlider + x:22*mm; y: 73.5*mm;width: root.width/2;height:5*mm + minimumValue: 0;maximumValue:120; stepSize: 15 + } + Rectangle{ + x: 4*mm; y: 73.5*mm; width: 9*mm; height: 5*mm; + TextEdit{ + id: messageIntervalField + anchors.fill: parent + font.pixelSize:3*mm + verticalAlignment:TextEdit.AlignRight + text:messageIntervalSlider.value + focus: true + selectByMouse: true + } + } + Text{x: 14*mm; y: 73.5*mm; width: 5*mm; height: 5*mm; + font.pixelSize:3*mm + text:qsTr("Min.") + } // CheckBox{ // id:showwebsiteCheckbox -// x:35*mm;y:70*mm +// x:35*mm;y:80*mm // onClicked:{ // if (checked==true){ // Service.updateglobaloptions(root.db,"showWebsiteForLinks","true") @@ -314,11 +328,10 @@ StackView{ // root.globaloptions.showWebsiteForLinks="false" // } // } - // } BlueButton { - x: 25*mm; y: 78*mm + x: 4*mm; y: 83.5*mm text: qsTr("Confirm") onClicked:{ var userconfig={server: servername.text, username: username.text, password:Qt.btoa(password.text), imagestore:imagestore.text,maxnews:maxNewsText.text,interval: messageIntervalField.text, newsViewType:newsTypeField.text}; @@ -352,7 +365,10 @@ StackView{ root.login=userconfig; root.news=[]; },"isActive",0); - Service.requestProfile(userconfig,db,root,function(nc){root.newContacts=nc}) + Service.requestProfile(userconfig,db,root,function(nc){root.newContacts=nc}); + if(osSettings.osType=="Android" && userconfig.timerInterval !=0){ + alarm.setAlarm(userconfig.timerInterval); + } Helperjs.showMessage(qsTr("Success"),qsTr("Name")+": "+credentials.name+"\nScreen Name: "+credentials.screen_name,root) } }); @@ -382,7 +398,7 @@ StackView{ imagestore.text=""; maxNews.value=0; newsTypeField.text="Conversations"; - messageIntervalSlider.value=0; + messageIntervalSlider.value=30; userButton.text=qsTr("User"); Helperjs.readData(db,"config","",function(storedUsers){ storedUsers.sort(function(obj1, obj2) { @@ -405,7 +421,7 @@ StackView{ imagestore.text="" maxNews.value=0 newsTypeField.text="Conversations" - messageIntervalSlider.value=0 + messageIntervalSlider.value=30 userButton.text=qsTr("User") } } @@ -449,12 +465,12 @@ StackView{ if( obj.isActive==0){userButton.fontColor='black'} else {userButton.fontColor='grey'}},"isActive",0 ) }) - //Service.readGlobaloptions(db,function(go){ +// Service.readGlobaloptions(db,function(go){ // if (root.globaloptions.showWebsiteForLinks!="false"){showwebsiteCheckbox.checked=true} - //}) +// }) } - catch (e){ + catch (e){print(e) Helperjs.friendicaWebRequest("https://dir.friendica.social/servers/surprise",configBackground,function(html){ var bpos=html.indexOf("baseurl"); var baseurl=html.substring(html.indexOf("http",bpos),html.indexOf('"',html.indexOf("http",bpos))); diff --git a/source-android/qml/configqml/InfoBox.qml b/source-android/qml/configqml/InfoBox.qml index 98c04ff..7cf6306 100644 --- a/source-android/qml/configqml/InfoBox.qml +++ b/source-android/qml/configqml/InfoBox.qml @@ -43,7 +43,7 @@ Rectangle{ textFormat: Text.RichText width: parent.width wrapMode: Text.WrapAtWordBoundaryOrAnywhere - text: "Friendiqa v0.3.4
Licensed under GPL 3 with the exception of OpenSSL
"+ + text: "Friendiqa v0.4
Licensed under GPL 3 with the exception of OpenSSL
"+ "Profile https://freunde.ma-nic.de/profile/friendiqa
"+ "Sourcecode: https://git.friendi.ca/LubuWest/Friendiqa
"+ "Most of C++ code by Fabio
"+ diff --git a/source-android/qml/configqml/OSSettingsAndroid.qml b/source-android/qml/configqml/OSSettingsAndroid.qml index 715d54b..8dd7ec5 100644 --- a/source-android/qml/configqml/OSSettingsAndroid.qml +++ b/source-android/qml/configqml/OSSettingsAndroid.qml @@ -36,6 +36,7 @@ QtObject{ property int appHeight: Screen.desktopAvailableHeight property int backKey: Qt.Key_Back //property string attachImageDir:filesystem.cameraPath+"/" + property string osType: "Android" property string imagePickQml: "ImagePicker" property string imagePicker:'import QtQuick 2.0; import "qrc:/qml/genericqml";'+ imagePickQml+'{multiple : true;onReady: {attachImageURLs.push(imageUrl);'+ diff --git a/source-android/qml/configqml/OSSettingsLinux.qml b/source-android/qml/configqml/OSSettingsLinux.qml index 1f107b5..37fc606 100644 --- a/source-android/qml/configqml/OSSettingsLinux.qml +++ b/source-android/qml/configqml/OSSettingsLinux.qml @@ -34,6 +34,7 @@ QtObject{ property real appWidth: 500 property real appHeight: 500 property int backKey: Qt.Key_Escape + property string osType: "Android" //property string attachImageDir:filesystem.homePath+"/Pictures/" property string imagePickQml: "ImagePickerLinux" } diff --git a/source-android/qml/friendiqa.qml b/source-android/qml/friendiqa.qml index d61790c..ba8034f 100644 --- a/source-android/qml/friendiqa.qml +++ b/source-android/qml/friendiqa.qml @@ -194,8 +194,10 @@ TabView{ Component.onCompleted: { Service.readGlobaloptions(db,function(go){globaloptions=go}) //print(xhr.networktype); - if(osSettings.imagePickQml=="ImagePicker"){var component = Qt.createComponent("qrc:/qml/genericqml/IntentReceiver.qml"); - var IntentReceiverQml = component.createObject(root) + if(osSettings.osType=="Android"){ + var component = Qt.createComponent("qrc:/qml/genericqml/IntentReceiver.qml"); + var IntentReceiverQml = component.createObject(root); + } } } diff --git a/source-android/qml/genericqml/IntentReceiver.qml b/source-android/qml/genericqml/IntentReceiver.qml index 3a640fe..69ec590 100644 --- a/source-android/qml/genericqml/IntentReceiver.qml +++ b/source-android/qml/genericqml/IntentReceiver.qml @@ -38,6 +38,10 @@ Item { Component.onCompleted: { SystemDispatcher.setInitialized(); + print("timer " + login.timerInterval) + if (login.timerInterval !=0){ + alarm.setAlarm(login.timerInterval); + } } } diff --git a/source-android/qml/newsqml/NewsLink.qml b/source-android/qml/newsqml/NewsLink.qml index 56e80ed..5d50ab7 100644 --- a/source-android/qml/newsqml/NewsLink.qml +++ b/source-android/qml/newsqml/NewsLink.qml @@ -45,8 +45,23 @@ Rectangle{ // WebView {id:htmlview; // anchors.fill: parent // } - Component.onCompleted: //Helperjs.friendicaWebRequest(url,parent,function(html){ - //print(html); - htmlview.text="Text