Browse Source

Merge pull request #2778 from nextcloud/notificationWithButtons

Notification: add action buttons
Andy Scherzinger 6 years ago
parent
commit
de0a5c002d

+ 1 - 1
scripts/analysis/lint-results.txt

@@ -1,2 +1,2 @@
 DO NOT TOUCH; GENERATED BY DRONE
-      <span class="mdl-layout-title">Lint Report: 92 warnings</span>
+      <span class="mdl-layout-title">Lint Report: 93 warnings</span>

+ 67 - 70
src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java

@@ -25,7 +25,6 @@ package com.owncloud.android.ui.activity;
 import android.accounts.Account;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
-import android.content.Context;
 import android.content.Intent;
 import android.graphics.PorterDuff;
 import android.os.Bundle;
@@ -42,7 +41,6 @@ import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
@@ -69,7 +67,7 @@ import butterknife.ButterKnife;
 import butterknife.Unbinder;
 
 /**
- * Activity displaying all server side stored activity items.
+ * Activity displaying all server side stored notification items.
  */
 public class NotificationsActivity extends FileActivity {
 
@@ -107,6 +105,8 @@ public class NotificationsActivity extends FileActivity {
 
     private NotificationListAdapter adapter;
     private Snackbar snackbar = null;
+    private OwnCloudClient client;
+    private Account currentAccount;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -116,14 +116,17 @@ public class NotificationsActivity extends FileActivity {
         setContentView(R.layout.notifications_layout);
         unbinder = ButterKnife.bind(this);
 
-        String account;
-        Account currentAccount;
-        if (getIntent() != null && getIntent().getExtras() != null &&
-                (account = getIntent().getExtras().getString(NotificationJob.KEY_NOTIFICATION_ACCOUNT)) != null &&
-                (currentAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext())) != null &&
-                !account.equalsIgnoreCase(currentAccount.name)) {
-            AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), account);
-            setAccount(AccountUtils.getCurrentOwnCloudAccount(this));
+        currentAccount = getAccount();
+
+        // use account from intent (opened via android notification can have a different account than current one)
+        if (getIntent() != null && getIntent().getExtras() != null) {
+            String account = getIntent().getExtras().getString(NotificationJob.KEY_NOTIFICATION_ACCOUNT);
+
+            if (account != null && (currentAccount == null || !account.equalsIgnoreCase(currentAccount.name))) {
+                AccountUtils.setCurrentOwnCloudAccount(this, account);
+                setAccount(AccountUtils.getCurrentOwnCloudAccount(this));
+                currentAccount = getAccount();
+            }
         }
 
         // setup toolbar
@@ -136,6 +139,12 @@ public class NotificationsActivity extends FileActivity {
         setupDrawer(R.id.nav_notifications);
         ThemeUtils.setColoredTitle(getSupportActionBar(), getString(R.string.drawer_item_notifications), this);
 
+        if (currentAccount == null) {
+            // show error
+            runOnUiThread(() -> setEmptyContent(noResultsHeadline, getString(R.string.account_not_found)));
+            return;
+        }
+
         swipeListRefreshLayout.setOnRefreshListener(() -> {
             setLoadingMessage();
             fetchAndSetData();
@@ -157,30 +166,26 @@ public class NotificationsActivity extends FileActivity {
                 snackbar.show();
             }
         } else {
-            Context context = getApplicationContext();
-            String pushUrl = context.getResources().getString(R.string.push_server_url);
+            String pushUrl = getResources().getString(R.string.push_server_url);
 
             if (pushUrl.isEmpty()) {
                 snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_not_implemented,
                         Snackbar.LENGTH_INDEFINITE);
             } else {
-                Account account = AccountUtils.getCurrentOwnCloudAccount(context);
                 ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
 
-                if (account != null) {
-                    boolean usesOldLogin = arbitraryDataProvider.getBooleanValue(account.name,
+                    boolean usesOldLogin = arbitraryDataProvider.getBooleanValue(currentAccount.name,
                             AccountUtils.ACCOUNT_USES_STANDARD_PASSWORD);
 
-                    if (usesOldLogin) {
-                        snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_old_login,
-                                Snackbar.LENGTH_INDEFINITE);
-                    } else {
-                        String pushValue = arbitraryDataProvider.getValue(account.name, PushUtils.KEY_PUSH);
+                if (usesOldLogin) {
+                    snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_old_login,
+                            Snackbar.LENGTH_INDEFINITE);
+                } else {
+                    String pushValue = arbitraryDataProvider.getValue(currentAccount.name, PushUtils.KEY_PUSH);
 
-                        if (pushValue == null || pushValue.isEmpty()) {
-                            snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_temp_error,
-                                    Snackbar.LENGTH_INDEFINITE);
-                        }
+                    if (pushValue == null || pushValue.isEmpty()) {
+                        snackbar = Snackbar.make(emptyContentContainer, R.string.push_notifications_temp_error,
+                                Snackbar.LENGTH_INDEFINITE);
                     }
                 }
             }
@@ -221,7 +226,7 @@ public class NotificationsActivity extends FileActivity {
     }
 
     /**
-     * sets up the UI elements and loads all activity items.
+     * sets up the UI elements and loads all notification items.
      */
     private void setupContent() {
         emptyContentIcon.setImageResource(R.drawable.ic_notification_light_grey);
@@ -229,14 +234,22 @@ public class NotificationsActivity extends FileActivity {
                 PorterDuff.Mode.SRC_IN);
         setLoadingMessage();
 
-        adapter = new NotificationListAdapter(this);
+        try {
+            OwnCloudAccount ocAccount = new OwnCloudAccount(currentAccount, this);
+            client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, this);
+            client.setOwnCloudVersion(AccountUtils.getServerVersion(currentAccount));
+
+            hideRefreshLayoutLoader();
+        } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException |
+                IOException | OperationCanceledException | AuthenticatorException e) {
+            Log_OC.e(TAG, "Error initializing client", e);
+        }
+
+        adapter = new NotificationListAdapter(client, this);
         recyclerView.setAdapter(adapter);
 
         LinearLayoutManager layoutManager = new LinearLayoutManager(this);
-        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
-                recyclerView.getContext(),
-                layoutManager.getOrientation()
-        );
+        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, layoutManager.getOrientation());
 
         recyclerView.setLayoutManager(layoutManager);
         recyclerView.addItemDecoration(dividerItemDecoration);
@@ -256,49 +269,31 @@ public class NotificationsActivity extends FileActivity {
     }
 
     private void fetchAndSetData() {
-        final Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext());
-        final Context context = MainApp.getAppContext();
-
         Thread t = new Thread(() -> {
-            try {
-                if (currentAccount != null) {
-                    OwnCloudAccount ocAccount = new OwnCloudAccount(currentAccount, context);
-                    OwnCloudClient mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
-                            getClientFor(ocAccount, MainApp.getAppContext());
-                    mClient.setOwnCloudVersion(AccountUtils.getServerVersion(currentAccount));
-
-                    RemoteOperation getRemoteNotificationOperation = new GetRemoteNotificationsOperation();
-                    final RemoteOperationResult result = getRemoteNotificationOperation.execute(mClient);
-
-                    if (result.isSuccess() && result.getNotificationData() != null) {
-                        final List<Notification> notifications = result.getNotificationData();
-
-                        runOnUiThread(() -> {
-                            populateList(notifications);
-                            if (notifications.size() > 0) {
-                                swipeEmptyListRefreshLayout.setVisibility(View.GONE);
-                                swipeListRefreshLayout.setVisibility(View.VISIBLE);
-                            } else {
-                                setEmptyContent(noResultsHeadline, noResultsMessage);
-                                swipeListRefreshLayout.setVisibility(View.GONE);
-                                swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE);
-                            }
-                        });
+            RemoteOperation getRemoteNotificationOperation = new GetRemoteNotificationsOperation();
+            final RemoteOperationResult result = getRemoteNotificationOperation.execute(client);
+
+            if (result.isSuccess() && result.getNotificationData() != null) {
+                final List<Notification> notifications = result.getNotificationData();
+
+                runOnUiThread(() -> {
+                    populateList(notifications);
+                    if (notifications.size() > 0) {
+                        swipeEmptyListRefreshLayout.setVisibility(View.GONE);
+                        swipeListRefreshLayout.setVisibility(View.VISIBLE);
                     } else {
-                        Log_OC.d(TAG, result.getLogMessage());
-                        // show error
-                        runOnUiThread(() -> setEmptyContent(noResultsHeadline, result.getLogMessage()));
+                        setEmptyContent(noResultsHeadline, noResultsMessage);
+                        swipeListRefreshLayout.setVisibility(View.GONE);
+                        swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE);
                     }
-
-                    hideRefreshLayoutLoader();
-                } else {
-                    // show error
-                    runOnUiThread(() -> setEmptyContent(noResultsHeadline, getString(R.string.account_not_found)));
-                }
-            } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException | IOException |
-                    OperationCanceledException | AuthenticatorException e) {
-                Log_OC.e(TAG, "Error fetching notification data", e);
+                });
+            } else {
+                Log_OC.d(TAG, result.getLogMessage());
+                // show error
+                runOnUiThread(() -> setEmptyContent(noResultsHeadline, result.getLogMessage()));
             }
+
+            hideRefreshLayoutLoader();
         });
 
         t.start();
@@ -345,8 +340,10 @@ public class NotificationsActivity extends FileActivity {
         if (emptyContentContainer != null && emptyContentMessage != null) {
             emptyContentHeadline.setText(headline);
             emptyContentMessage.setText(message);
+            emptyContentMessage.setVisibility(View.VISIBLE);
 
             emptyContentProgressBar.setVisibility(View.GONE);
+            emptyContentIcon.setImageResource(R.drawable.ic_notification_light_grey);
             emptyContentIcon.setVisibility(View.VISIBLE);
         }
     }

+ 123 - 26
src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.java

@@ -1,36 +1,39 @@
-/**
+/*
  * ownCloud Android client application
  *
  * @author Andy Scherzinger
  * Copyright (C) 2016 ownCloud Inc.
- * <p/>
+ *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2,
  * as published by the Free Software Foundation.
- * <p/>
+ *
  * 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.
- * <p/>
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.owncloud.android.ui.adapter;
 
-import android.content.Context;
 import android.content.Intent;
+import android.graphics.PorterDuff;
 import android.graphics.Typeface;
 import android.graphics.drawable.PictureDrawable;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.support.annotation.NonNull;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.bumptech.glide.GenericRequestBuilder;
@@ -40,12 +43,25 @@ import com.bumptech.glide.load.model.StreamEncoder;
 import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
 import com.caverock.androidsvg.SVG;
 import com.owncloud.android.R;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.notifications.models.Action;
 import com.owncloud.android.lib.resources.notifications.models.Notification;
+import com.owncloud.android.ui.activity.NotificationsActivity;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ThemeUtils;
 import com.owncloud.android.utils.svg.SvgDecoder;
 import com.owncloud.android.utils.svg.SvgDrawableTranscoder;
 import com.owncloud.android.utils.svg.SvgSoftwareLayerSetter;
 
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -57,31 +73,36 @@ import butterknife.ButterKnife;
  * This Adapter populates a RecyclerView with all notifications for an account within the app.
  */
 public class NotificationListAdapter extends RecyclerView.Adapter<NotificationListAdapter.NotificationViewHolder> {
-    private List<Notification> mValues;
-    private Context context;
+    private static final String TAG = NotificationListAdapter.class.getSimpleName();
+
+    private List<Notification> notificationsList;
+    private OwnCloudClient client;
+    private NotificationsActivity notificationsActivity;
 
-    public NotificationListAdapter(Context context) {
-        this.mValues = new ArrayList<>();
-        this.context = context;
+    public NotificationListAdapter(OwnCloudClient client, NotificationsActivity notificationsActivity) {
+        this.notificationsList = new ArrayList<>();
+        this.client = client;
+        this.notificationsActivity = notificationsActivity;
     }
 
     public void setNotificationItems(List<Notification> notificationItems) {
-        mValues.clear();
-        mValues.addAll(notificationItems);
+        notificationsList.clear();
+        notificationsList.addAll(notificationItems);
         notifyDataSetChanged();
     }
 
     @NonNull
     @Override
     public NotificationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_list_item, parent, false);
+        View v = LayoutInflater.from(notificationsActivity).inflate(R.layout.notification_list_item, parent, false);
         return new NotificationViewHolder(v);
     }
 
     @Override
     public void onBindViewHolder(@NonNull NotificationViewHolder holder, int position) {
-        Notification notification = mValues.get(position);
-        holder.dateTime.setText(DisplayUtils.getRelativeTimestamp(context, notification.getDatetime().getTime()));
+        Notification notification = notificationsList.get(position);
+        holder.dateTime.setText(DisplayUtils.getRelativeTimestamp(notificationsActivity,
+                notification.getDatetime().getTime()));
 
         String subject = notification.getSubject();
         if (!TextUtils.isEmpty(notification.getLink())) {
@@ -95,14 +116,88 @@ public class NotificationListAdapter extends RecyclerView.Adapter<NotificationLi
 
         // Todo set proper action icon (to be clarified how to pick)
         if (!TextUtils.isEmpty(notification.getIcon())) {
-            downloadIcon(notification.getIcon(), holder.activityIcon);
+            downloadIcon(notification.getIcon(), holder.icon);
+        }
+
+        // add action buttons
+        holder.buttons.removeAllViews();
+        Button button;
+        ExecuteActionTask executeActionTask = new ExecuteActionTask(holder);
+
+        for (Action action : notification.getActions()) {
+            button = new Button(notificationsActivity);
+            button.setText(action.label);
+            if (action.primary) {
+                button.getBackground().setColorFilter(ThemeUtils.primaryColor(notificationsActivity, true),
+                        PorterDuff.Mode.SRC_ATOP);
+                button.setTextColor(ThemeUtils.fontColor(notificationsActivity));
+            }
+
+            button.setOnClickListener(v -> executeActionTask.execute(action));
+
+            holder.buttons.addView(button);
+        }
+    }
+
+    private class ExecuteActionTask extends AsyncTask<Action, Void, Boolean> {
+
+        private NotificationViewHolder holder;
+
+        ExecuteActionTask(NotificationViewHolder holder) {
+            this.holder = holder;
         }
 
+        @Override
+        protected Boolean doInBackground(Action... actions) {
+            HttpMethod method;
+            Action action = actions[0];
+
+            switch (action.type) {
+                case "GET":
+                    method = new GetMethod(action.link);
+                    break;
+
+                case "POST":
+                    method = new PostMethod(action.link);
+                    break;
+
+                case "DELETE":
+                    method = new DeleteMethod(action.link);
+                    break;
+
+                default:
+                    // do nothing
+                    return false;
+            }
+
+            method.setRequestHeader(RemoteOperation.OCS_API_HEADER, RemoteOperation.OCS_API_HEADER_VALUE);
+
+            int status;
+            try {
+                status = client.executeMethod(method);
+            } catch (IOException e) {
+                Log_OC.e(TAG, "Execution of notification action failed: " + e);
+                return false;
+            }
+
+            return status == HttpStatus.SC_OK;
+        }
+
+        @Override
+        protected void onPostExecute(Boolean success) {
+            if (success) {
+                int position = holder.getAdapterPosition();
+                notificationsList.remove(position);
+                notifyItemRemoved(position);
+            } else {
+                DisplayUtils.showSnackMessage(notificationsActivity, "Failed to execute action!");
+            }
+        }
     }
 
     private void downloadIcon(String icon, ImageView itemViewType) {
-        GenericRequestBuilder<Uri, InputStream, SVG, PictureDrawable> requestBuilder = Glide.with(context)
-                .using(Glide.buildStreamModelLoader(Uri.class, context), InputStream.class)
+        GenericRequestBuilder<Uri, InputStream, SVG, PictureDrawable> requestBuilder = Glide.with(notificationsActivity)
+                .using(Glide.buildStreamModelLoader(Uri.class, notificationsActivity), InputStream.class)
                 .from(Uri.class)
                 .as(SVG.class)
                 .transcode(new SvgDrawableTranscoder(), PictureDrawable.class)
@@ -112,7 +207,7 @@ public class NotificationListAdapter extends RecyclerView.Adapter<NotificationLi
                 .placeholder(R.drawable.ic_notification)
                 .error(R.drawable.ic_notification)
                 .animate(android.R.anim.fade_in)
-                .listener(new SvgSoftwareLayerSetter<Uri>());
+                .listener(new SvgSoftwareLayerSetter<>());
 
 
         Uri uri = Uri.parse(icon);
@@ -123,23 +218,25 @@ public class NotificationListAdapter extends RecyclerView.Adapter<NotificationLi
     }
 
     private void openLink(String link) {
-        context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link)));
+        notificationsActivity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link)));
     }
 
     @Override
     public int getItemCount() {
-        return mValues.size();
+        return notificationsList.size();
     }
 
     static class NotificationViewHolder extends RecyclerView.ViewHolder {
-        @BindView(R.id.activity_icon)
-        public ImageView activityIcon;
-        @BindView(R.id.activity_subject)
+        @BindView(R.id.notification_icon)
+        public ImageView icon;
+        @BindView(R.id.notification_subject)
         public TextView subject;
-        @BindView(R.id.activity_message)
+        @BindView(R.id.notification_message)
         public TextView message;
-        @BindView(R.id.activity_datetime)
+        @BindView(R.id.notification_datetime)
         public TextView dateTime;
+        @BindView(R.id.notification_buttons)
+        public LinearLayout buttons;
 
         private NotificationViewHolder(View itemView) {
             super(itemView);

+ 89 - 0
src/main/res/layout/notification_list_item.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Nextcloud Android client application
+
+  @author Tobias Kaminsky
+  Copyright (C) 2018 Tobias Kaminsky
+  Copyright (C) 2018 Nextcloud GmbH.
+ 
+  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.
+ 
+  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 <https://www.gnu.org/licenses/>.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:paddingTop="@dimen/standard_padding"
+    android:paddingRight="@dimen/standard_padding"
+    android:paddingBottom="@dimen/standard_padding"
+    android:paddingLeft="@dimen/standard_padding">
+
+    <ImageView
+        android:id="@+id/notification_icon"
+        android:layout_width="@dimen/notification_icon_width"
+        android:layout_height="@dimen/notification_icon_height"
+        android:layout_alignParentTop="true"
+        android:layout_marginRight="@dimen/notification_icon_layout_right_end_margin"
+        android:layout_marginEnd="@dimen/notification_icon_layout_right_end_margin"
+        android:alpha="0.5"
+        android:src="@drawable/ic_notification"
+        android:contentDescription="@string/notification_icon"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_alignTop="@id/notification_icon"
+        android:layout_toRightOf="@id/notification_icon"
+        android:layout_toEndOf="@id/notification_icon">
+
+        <TextView
+            android:id="@+id/notification_subject"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:text="@string/placeholder_filename"
+            android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+        <TextView
+            android:id="@+id/notification_message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:text="@string/placeholder_sentence"
+            android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+        <LinearLayout
+            android:id="@+id/notification_buttons"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/alternate_half_margin"
+            android:layout_marginLeft="@dimen/notification_list_item_grid_layout_left_start_margin"
+            android:layout_marginStart="@dimen/notification_list_item_grid_layout_left_start_margin"
+            android:columnCount="3"
+            android:orientation="horizontal"/>
+
+        <TextView
+            android:id="@+id/notification_datetime"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:ellipsize="end"
+            android:text="@string/placeholder_sentence"
+            android:textColor="?android:attr/textColorSecondary"/>
+
+    </LinearLayout>
+
+</RelativeLayout>

+ 4 - 0
src/main/res/values/dims.xml

@@ -98,6 +98,10 @@
     <dimen name="activity_list_item_title_header_text_size">20sp</dimen>
     <dimen name="activity_list_layout_recycler_view_margin">-3dp</dimen>
     <dimen name="activity_row_layout_height">48dp</dimen>
+    <dimen name="notification_icon_width">32dp</dimen>
+    <dimen name="notification_icon_height">32dp</dimen>
+    <dimen name="notification_icon_layout_right_end_margin">24dp</dimen>
+    <dimen name="notification_list_item_grid_layout_left_start_margin">-3dp</dimen>
     <dimen name="uploader_list_separator_height">1dp</dimen>
     <dimen name="contactlist_item_icon_layout_width">40dp</dimen>
     <dimen name="contactlist_item_icon_layout_height">40dp</dimen>

+ 1 - 0
src/main/res/values/strings.xml

@@ -826,4 +826,5 @@
     <string name="stream_not_possible_headline">Internal streaming not possible</string>
     <string name="stream_not_possible_message">Please download media instead or use external app.</string>
     <string name="folder_already_exists">Folder already exists</string>
+    <string name="notification_icon">Notification icon</string>
 </resources>