diff --git a/app/build.gradle b/app/build.gradle
index c65b01d763b0d28230f03af8e2f0b82c8c54df46..6efc99a96ab7a13bf9f96309e83a5cfd218e4c5a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -53,6 +53,9 @@ android {
//includeAndroidResources = true
}
}
+ buildFeatures {
+ viewBinding true
+ }
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index be871995566a3c5de7fc4bbb8df3365b36fc9856..33e24a7cf9add50f45afd372847553ed42f23cd6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,95 +1,103 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java
index e0f762fcb4f2d104db8baa88938f26276ddbee85..2a66b9ddfe699683082cb968b6ee3f73695a7416 100644
--- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java
+++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java
@@ -31,6 +31,9 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.resources.files.FileUtils;
import java.io.File;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
import foundation.e.drive.receivers.ScreenOffReceiver;
@@ -293,4 +296,26 @@ public abstract class CommonUtils {
+ "\n File can be read?: " + f.canRead()
+ "\n File can be written?: " + f.canWrite();
}
+
+ /**
+ * Formatter class is not used since bytes passed by server are in SI unit aka 1kb = 1024byte
+ * https://stackoverflow.com/questions/3758606/how-can-i-convert-byte-size-into-a-human-readable-format-in-java/3758880#3758880
+ *
+ * @param bytes file/data size in bytes
+ * @return String in human readable format
+ */
+ public static String humanReadableByteCountBin(long bytes) {
+ long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
+ if (absB < 1024) {
+ return bytes + " B";
+ }
+ long value = absB;
+ CharacterIterator ci = new StringCharacterIterator("KMGTPE");
+ for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
+ value >>= 10;
+ ci.next();
+ }
+ value *= Long.signum(bytes);
+ return String.format(Locale.getDefault(),"%.1f %cB", value / 1024.0, ci.current());
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java b/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee13697d5d61e901a041dd8e8b8daadfbd4231fd
--- /dev/null
+++ b/app/src/main/java/foundation/e/drive/widgets/EDriveWidget.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright © ECORP SAS 2022.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package foundation.e.drive.widgets;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.provider.Settings;
+import android.widget.RemoteViews;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.UserInfo;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+import foundation.e.drive.R;
+import foundation.e.drive.utils.CommonUtils;
+
+/**
+ * Implementation of App Widget functionality.
+ */
+public class EDriveWidget extends AppWidgetProvider {
+ private static final String webpage =
+ "https://esolutions.shop/ecloud-subscriptions/?username=%s&token=%s¤t-quota=%s&from=nextcloud";
+ private static final String addAccountWebpage = "https://e.foundation/e-email-invite/";
+ private static final String accountManagerPackageName = "foundation.e.accountmanager";
+ private static final String getAccountManagerComponentName = accountManagerPackageName +
+ ".ui.setup.LoginActivity";
+ private static final String SETUP_ACCOUNT_PROVIDER_TYPE = "setup_account_provider_type";
+ private static final String ACCOUNT_PROVIDER_EELO = "eelo";
+
+ private final Calendar calender = Calendar.getInstance();
+ private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
+ private final GetRemoteUserInfoOperation getRemoteUserInfoOperation = new GetRemoteUserInfoOperation();
+ private UserInfo userInfo = null;
+ private RemoteViews views = null;
+
+ public void updateAppWidget(final Context context) {
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+ final ComponentName provider = new ComponentName(context, getClass());
+ int[] appWidgetIds = appWidgetManager.getAppWidgetIds(provider);
+
+ for (int appWidgetId : appWidgetIds) {
+ updateAppWidget(context, appWidgetManager, appWidgetId);
+ }
+ }
+
+ public void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager,
+ final int appWidgetId) {
+ final AccountManager accountManager = AccountManager.get(context);
+ final Account account = CommonUtils.getAccount(context.getString(R.string.eelo_account_type),
+ accountManager);
+ final OwnCloudClient client = CommonUtils.getOwnCloudClient(account, context);
+ views = new RemoteViews(context.getPackageName(), R.layout.e_drive_widget);
+
+ HandlerThread handlerThread = new HandlerThread("Network Request");
+ handlerThread.start();
+ Handler mHandler = new Handler(handlerThread.getLooper());
+
+ final EDriveWidgetCallback callback = new EDriveWidgetCallback() {
+ @Override
+ public void onComplete() {
+ onNetworkRequestCompleted(context, appWidgetManager, appWidgetId, client, account);
+ }
+ };
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (client != null) {
+ RemoteOperationResult ocsResult = getRemoteUserInfoOperation.execute(client);
+ if (ocsResult.isSuccess() && ocsResult.getData() != null) {
+ userInfo = (UserInfo) ocsResult.getData().get(0);
+ }
+ }
+ callback.onComplete();
+ }
+ });
+ }
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ // There may be multiple widgets active, so update all of them
+ for (int appWidgetId : appWidgetIds) {
+ updateAppWidget(context, appWidgetManager, appWidgetId);
+ }
+ }
+
+ @Override
+ public void onEnabled(Context context) {
+ updateAppWidget(context);
+
+ }
+
+ @Override
+ public void onDisabled(Context context) {
+ // Enter relevant functionality for when the last widget is disabled
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) return;
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action) ||
+ AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(action)) {
+ updateAppWidget(context);
+ }
+ }
+
+ private String dataForWeb(Long bytes) {
+ String space = CommonUtils.humanReadableByteCountBin(bytes);
+ String[] split = space.split(" ");
+ return Math.round(Double.parseDouble(split[0])) + split[1];
+ }
+
+ private Intent buildIntent(String name, String extra) {
+ Intent intent = new Intent(name);
+ if (!extra.isEmpty()) {
+ intent.setData(Uri.parse(extra));
+ }
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return intent;
+ }
+
+ private void onNetworkRequestCompleted(Context context, AppWidgetManager appWidgetManager,
+ int appWidgetId, OwnCloudClient client, Account account) {
+ if (account == null || userInfo == null) {
+ views = new RemoteViews(context.getPackageName(), R.layout.e_drive_widget_login);
+ Intent accountIntent = buildIntent("", "")
+ .setComponent(new ComponentName(accountManagerPackageName,
+ getAccountManagerComponentName))
+ .putExtra(SETUP_ACCOUNT_PROVIDER_TYPE, ACCOUNT_PROVIDER_EELO);
+ PendingIntent addAccountIntent = PendingIntent.getActivity(context, 0,
+ accountIntent, PendingIntent.FLAG_IMMUTABLE);
+ views.setOnClickPendingIntent(R.id.login, addAccountIntent);
+ PendingIntent pendingIntentNewAccount = PendingIntent.getActivity(context, 0,
+ buildIntent(Intent.ACTION_VIEW, addAccountWebpage), PendingIntent.FLAG_IMMUTABLE);
+ views.setOnClickPendingIntent(R.id.newAccount, pendingIntentNewAccount);
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ return;
+ }
+
+ // Construct the RemoteViews object
+ double usedMB = userInfo.quota.used / 1024.0 / 1024.0;
+ double totalMB = userInfo.quota.total / 1024.0 / 1024.0;
+
+ views.setTextViewText(R.id.email, userInfo.id);
+ if (!userInfo.alternateDisplayName.isEmpty()) {
+ views.setTextViewText(R.id.name, userInfo.alternateDisplayName);
+ } else {
+ views.setTextViewText(R.id.name, userInfo.displayName);
+ }
+
+ views.setProgressBar(R.id.progress, (int) totalMB, (int) usedMB, false);
+
+ views.setTextViewText(R.id.planName, context.getString(R.string.free_plan,
+ CommonUtils.humanReadableByteCountBin(userInfo.quota.total)));
+
+ for (String group : userInfo.groups) {
+ if (group.contains("premium-")) {
+ views.setTextViewText(R.id.planName, context.getString(R.string.premium_plan,
+ group.split("-")[1]));
+ break;
+ }
+ }
+ views.setTextViewText(R.id.status, context.getString(R.string.progress_status,
+ CommonUtils.humanReadableByteCountBin(userInfo.quota.used),
+ CommonUtils.humanReadableByteCountBin(userInfo.quota.total)));
+ views.setTextViewText(R.id.sync, context.getString(R.string.last_synced,
+ sdf.format(calender.getTime())));
+
+ PendingIntent pendingIntentSettings = PendingIntent.getActivity(context, 0,
+ buildIntent(Settings.ACTION_SYNC_SETTINGS, ""), PendingIntent.FLAG_IMMUTABLE);
+ views.setOnClickPendingIntent(R.id.settings, pendingIntentSettings);
+
+ PendingIntent pendingIntentUpgrade = PendingIntent.getActivity(context, 0,
+ buildIntent(Intent.ACTION_VIEW, String.format(webpage, userInfo.id,
+ client.getCredentials().getAuthToken(), dataForWeb(userInfo.quota.total))),
+ PendingIntent.FLAG_IMMUTABLE);
+ views.setOnClickPendingIntent(R.id.upgrade, pendingIntentUpgrade);
+
+ // Instruct the widget manager to update the widget
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/widgets/EDriveWidgetCallback.java b/app/src/main/java/foundation/e/drive/widgets/EDriveWidgetCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0a2b428f3f5c4f69aae7c832a639fc19b671373
--- /dev/null
+++ b/app/src/main/java/foundation/e/drive/widgets/EDriveWidgetCallback.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright © ECORP SAS 2022.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package foundation.e.drive.widgets;
+
+public interface EDriveWidgetCallback {
+ void onComplete();
+}
diff --git a/app/src/main/res/drawable/button_background.xml b/app/src/main/res/drawable/button_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1c1a64eee77dcdd4c2aa2f6d37208daae639dc62
--- /dev/null
+++ b/app/src/main/res/drawable/button_background.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_cloud.xml b/app/src/main/res/drawable/ic_cloud.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3bffa01450258cc5f9522bbf480c1419237b2b69
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cloud.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_down.xml b/app/src/main/res/drawable/ic_keyboard_arrow_down.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5c77dd811a876a83089312e7eb312ca24273ffaf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_keyboard_arrow_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..68ff39626d7cbb46ad8f3c91e2fe127bb2c5e78b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/widget_background.xml b/app/src/main/res/drawable/widget_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d1d23ba6da023008f6222642b1832a83f05c665a
--- /dev/null
+++ b/app/src/main/res/drawable/widget_background.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/e_drive_widget.xml b/app/src/main/res/layout/e_drive_widget.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3feffb91bf049650fdaa426e5ea73d0725eeac58
--- /dev/null
+++ b/app/src/main/res/layout/e_drive_widget.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/e_drive_widget_login.xml b/app/src/main/res/layout/e_drive_widget_login.xml
new file mode 100644
index 0000000000000000000000000000000000000000..51b419a6b866aeae659f37080baeaca7ffd7ab56
--- /dev/null
+++ b/app/src/main/res/layout/e_drive_widget_login.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index db4de51cf5b12c694d17540e5514aace35b15964..94d792e679832a78e5a0f8799a27b18af3574f49 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -9,4 +9,10 @@
#46bdbf
#1c000000
#42221f1f
+
+ #33000000
+ #99FFFFFF
+ #DEFFFFFF
+ #61FFFFFF
+ #5DB2FF
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4db8c59062cb60bac199917d01af9728a1772c39
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ 0dp
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8f9814a8960fdc198e3c59e0825e47b42749a8a7..52668a7d11e3a3218f06f716f4de5a1a2d7865a8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,4 +1,16 @@
/e/ Drive
e.foundation.webdav.eelo
+
+
+ Add widget
+ EDrive Widget
+ %1$s Free Plan
+ Premium %1$s Plan
+ %1$s OF %2$s USED
+ My Plan:
+ Upgrade
+ View aliases
+ Last synced: %1$s
+ /e/Account
diff --git a/app/src/main/res/xml/e_drive_widget_info.xml b/app/src/main/res/xml/e_drive_widget_info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dd3cef9c52ef95390f43f0fa0441dfb332e85f6e
--- /dev/null
+++ b/app/src/main/res/xml/e_drive_widget_info.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index e78e65c08a0957752bd67ab1401ff1c14b9f82b0..c79c847155c511e1bd0eef1d837555928ede948c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,4 +15,4 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-android.useAndroidX=true
+android.useAndroidX=true
\ No newline at end of file
diff --git a/nextcloud-android-lib b/nextcloud-android-lib
index 0b979c255253d17f16521241c1161e8c12ee5ca1..b043a5104962a841daf4ca3e59383216eebf7ef0 160000
--- a/nextcloud-android-lib
+++ b/nextcloud-android-lib
@@ -1 +1 @@
-Subproject commit 0b979c255253d17f16521241c1161e8c12ee5ca1
+Subproject commit b043a5104962a841daf4ca3e59383216eebf7ef0