Explorar o código

Merge pull request #784 from nextcloud/activities

Activities
Andy Scherzinger %!s(int64=8) %!d(string=hai) anos
pai
achega
7706fdb8fc
Modificáronse 26 ficheiros con 865 adicións e 5 borrados
  1. 10 2
      build.gradle
  2. 58 0
      drawable_resources/ic_activity.svg
  3. 58 0
      drawable_resources/ic_activity_light_grey.svg
  4. 1 0
      src/main/AndroidManifest.xml
  5. 293 0
      src/main/java/com/owncloud/android/ui/activity/ActivitiesListActivity.java
  6. 5 0
      src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
  7. 148 0
      src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java
  8. 0 2
      src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
  9. 40 0
      src/main/java/com/owncloud/android/utils/svg/SvgDecoder.java
  10. 37 0
      src/main/java/com/owncloud/android/utils/svg/SvgDrawableTranscoder.java
  11. 43 0
      src/main/java/com/owncloud/android/utils/svg/SvgSoftwareLayerSetter.java
  12. BIN=BIN
      src/main/res/drawable-hdpi/ic_activity.png
  13. BIN=BIN
      src/main/res/drawable-hdpi/ic_activity_light_grey.png
  14. BIN=BIN
      src/main/res/drawable-mdpi/ic_activity.png
  15. BIN=BIN
      src/main/res/drawable-mdpi/ic_activity_light_grey.png
  16. BIN=BIN
      src/main/res/drawable-xhdpi/ic_activity.png
  17. BIN=BIN
      src/main/res/drawable-xhdpi/ic_activity_light_grey.png
  18. BIN=BIN
      src/main/res/drawable-xxhdpi/ic_activity.png
  19. BIN=BIN
      src/main/res/drawable-xxhdpi/ic_activity_light_grey.png
  20. BIN=BIN
      src/main/res/drawable-xxxhdpi/ic_activity.png
  21. BIN=BIN
      src/main/res/drawable-xxxhdpi/ic_activity_light_grey.png
  22. 75 0
      src/main/res/layout/activity_list_item.xml
  23. 81 0
      src/main/res/layout/activity_list_layout.xml
  24. 1 1
      src/main/res/layout/user_info_layout.xml
  25. 5 0
      src/main/res/menu/drawer_menu.xml
  26. 10 0
      src/main/res/values/strings.xml

+ 10 - 2
build.gradle

@@ -32,6 +32,11 @@ ext {
     preDexEnabled = "true".equals(System.getProperty("pre-dex", "true"))
 }
 
+configurations.all {
+    // Check for updates every build
+    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
+}
+
 repositories {
     jcenter()
     maven { url "https://jitpack.io" }
@@ -53,7 +58,7 @@ android {
         javaMaxHeapSize "4g"
     }
 
-    compileSdkVersion 24
+    compileSdkVersion 25
     buildToolsVersion '25.0.0'
 
     defaultConfig {
@@ -168,7 +173,8 @@ dependencies {
     compile name: 'touch-image-view'
     compile 'com.android.support:multidex:1.0.1'
 
-    compile 'com.github.nextcloud:android-library:1.0.11'
+
+    compile 'com.github.nextcloud:android-library:1.0.14'
     compile "com.android.support:support-v4:${supportLibraryVersion}"
     compile "com.android.support:design:${supportLibraryVersion}"
     compile 'com.jakewharton:disklrucache:2.0.2'
@@ -182,6 +188,8 @@ dependencies {
     compile 'com.jakewharton:butterknife:8.4.0'
     annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
 
+    compile 'com.github.bumptech.glide:glide:3.7.0'
+    compile 'com.caverock:androidsvg:1.2.1'
     /// dependencies for local unit tests
     testCompile 'junit:junit:4.12'
     testCompile 'org.mockito:mockito-core:1.10.19'

+ 58 - 0
drawable_resources/ic_activity.svg

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="32"
+   width="32"
+   version="1.0"
+   viewBox="0 0 32 32"
+   id="svg4"
+   sodipodi:docname="ic_activity.svg"
+   inkscape:version="0.92.1 r15371"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\activities\src\main\res\drawable-mdpi\ic_activity.png"
+   inkscape:export-xdpi="72"
+   inkscape:export-ydpi="72">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     d="M 16,1.9491526 6,18.810169 H 17 L 16,30.050847 26,13.189831 H 15 Z"
+     id="path2"
+     style="fill:#757575;fill-opacity:1;stroke-width:0.96784461"
+     inkscape:connector-curvature="0" />
+</svg>

+ 58 - 0
drawable_resources/ic_activity_light_grey.svg

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="32"
+   width="32"
+   version="1.0"
+   viewBox="0 0 32 32"
+   id="svg4"
+   sodipodi:docname="ic_activity_light_grey.svg"
+   inkscape:version="0.92.1 r15371"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\activities\src\main\res\drawable-mdpi\ic_activity_light_grey.png"
+   inkscape:export-xdpi="216"
+   inkscape:export-ydpi="216">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="-20.40678"
+     inkscape:cy="16"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     d="M 16,1.9491526 6,18.810169 H 17 L 16,30.050847 26,13.189831 H 15 Z"
+     id="path2"
+     style="fill:#000000;fill-opacity:1;stroke-width:0.96784461;opacity:0.5"
+     inkscape:connector-curvature="0" />
+</svg>

+ 1 - 0
src/main/AndroidManifest.xml

@@ -77,6 +77,7 @@
         <activity android:name=".ui.activity.ManageAccountsActivity" />
         <activity android:name=".ui.activity.UserInfoActivity" />
         <activity android:name=".ui.activity.ParticipateActivity" />
+        <activity android:name=".ui.activity.ActivitiesListActivity"/>
         <activity android:name=".ui.activity.FolderSyncActivity" />
         <activity android:name=".ui.activity.UploadFilesActivity" />
         <activity android:name=".ui.activity.ReceiveExternalFilesActivity"

+ 293 - 0
src/main/java/com/owncloud/android/ui/activity/ActivitiesListActivity.java

@@ -0,0 +1,293 @@
+/**
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * @author Mario Danic
+ * Copyright (C) 2017 Andy Scherzinger
+ * Copyright (C) 2017 Mario Danic
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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.os.Bundle;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.support.v7.widget.DividerItemDecoration;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageView;
+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.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.lib.resources.activities.GetRemoteActivitiesOperation;
+import com.owncloud.android.ui.adapter.ActivityListAdapter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import butterknife.BindString;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.Unbinder;
+
+/**
+ * Activity displaying all server side stored activity items.
+ */
+public class ActivitiesListActivity extends FileActivity {
+
+    private static final String TAG = ActivitiesListActivity.class.getSimpleName();
+
+    @BindView(R.id.empty_list_view)
+    public LinearLayout emptyContentContainer;
+
+    @BindView(R.id.swipe_containing_list)
+    public SwipeRefreshLayout swipeListRefreshLayout;
+
+    @BindView(R.id.swipe_containing_empty)
+    public SwipeRefreshLayout swipeEmptyListRefreshLayout;
+
+    @BindView(R.id.empty_list_view_text)
+    public TextView emptyContentMessage;
+
+    @BindView(R.id.empty_list_view_headline)
+    public TextView emptyContentHeadline;
+
+    @BindView(R.id.empty_list_icon)
+    public ImageView emptyContentIcon;
+
+    @BindView(R.id.empty_list_progress)
+    public ProgressBar emptyContentProgressBar;
+
+    @BindView(android.R.id.list)
+    public RecyclerView recyclerView;
+
+    @BindString(R.string.activities_no_results_headline)
+    public String noResultsHeadline;
+
+    @BindString(R.string.activities_no_results_message)
+    public String noResultsMessage;
+
+    private ActivityListAdapter adapter;
+    private Unbinder unbinder;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log_OC.v(TAG, "onCreate() start");
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_list_layout);
+        unbinder = ButterKnife.bind(this);
+        // setup toolbar
+        setupToolbar();
+
+        // setup drawer
+        setupDrawer(R.id.nav_activity);
+        getSupportActionBar().setTitle(getString(R.string.drawer_item_activities));
+
+        swipeListRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                setLoadingMessage();
+                fetchAndSetData();
+            }
+        });
+
+        swipeEmptyListRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                setLoadingMessage();
+                fetchAndSetData();
+
+            }
+        });
+        setupContent();
+    }
+
+    public void onDestroy() {
+        super.onDestroy();
+        unbinder.unbind();
+    }
+
+    @Override
+    public void showFiles(boolean onDeviceOnly) {
+        super.showFiles(onDeviceOnly);
+        Intent i = new Intent(getApplicationContext(), FileDisplayActivity.class);
+        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        startActivity(i);
+    }
+
+    /**
+     * sets up the UI elements and loads all activity items.
+     */
+    private void setupContent() {
+        emptyContentIcon.setImageResource(R.drawable.ic_activity_light_grey);
+        setLoadingMessage();
+
+        adapter = new ActivityListAdapter(this);
+        recyclerView.setAdapter(adapter);
+
+        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
+        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
+                layoutManager.getOrientation());
+
+        recyclerView.setLayoutManager(layoutManager);
+        recyclerView.addItemDecoration(dividerItemDecoration);
+
+        fetchAndSetData();
+    }
+
+    private void fetchAndSetData() {
+        final Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext());
+        final Context context = MainApp.getAppContext();
+
+        Thread t = new Thread(new Runnable() {
+
+
+            public void run() {
+                OwnCloudAccount ocAccount = null;
+                try {
+                    ocAccount = new OwnCloudAccount(
+                            currentAccount,
+                            context
+                            );
+                    OwnCloudClient mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                            getClientFor(ocAccount, MainApp.getAppContext());
+                    mClient.setOwnCloudVersion(AccountUtils.getServerVersion(currentAccount));
+
+                    RemoteOperation getRemoteNotificationOperation = new GetRemoteActivitiesOperation();
+                    Log_OC.d(TAG, "BEFORE getRemoteActivitiesOperation.execute");
+                    final RemoteOperationResult result =
+                            getRemoteNotificationOperation.execute(mClient);
+
+                    if (result.isSuccess() && result.getData() != null) {
+                        final ArrayList<Object> activities = result.getData();
+
+                        runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                if (activities.size() > 0) {
+                                    populateList(activities);
+                                    swipeEmptyListRefreshLayout.setVisibility(View.GONE);
+                                    swipeListRefreshLayout.setVisibility(View.VISIBLE);
+                                } else {
+                                    setEmptyContent(noResultsHeadline, noResultsMessage);
+                                }
+                            }
+                        });
+                    } else {
+                        Log_OC.d(TAG, result.getLogMessage());
+                        // show error
+                        String logMessage = result.getLogMessage();
+                        if (result.getHttpCode() == 304) {
+                            logMessage = noResultsMessage;
+                        }
+                        final String finalLogMessage = logMessage;
+                        runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                setEmptyContent(noResultsHeadline, finalLogMessage);
+                            }
+                        });
+                    }
+
+                    hideRefreshLayoutLoader();
+                } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
+                    Log_OC.e(TAG, "Account not found", e);
+                } catch (IOException e) {
+                    Log_OC.e(TAG, "IO error", e);
+                } catch (OperationCanceledException e) {
+                    Log_OC.e(TAG, "Operation has been canceled", e);
+                } catch (AuthenticatorException e) {
+                    Log_OC.e(TAG, "Authentication Exception", e);
+                }
+            }
+        });
+
+        t.start();
+    }
+
+    private void hideRefreshLayoutLoader() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                swipeListRefreshLayout.setRefreshing(false);
+                swipeEmptyListRefreshLayout.setRefreshing(false);
+            }
+        });
+    }
+
+    private void populateList(List<Object> activities) {
+
+        adapter.setActivityItems(activities);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean retval = true;
+
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                if (isDrawerOpen()) {
+                    closeDrawer();
+                } else {
+                    openDrawer();
+                }
+                break;
+            default:
+                Log_OC.w(TAG, "Unknown menu item triggered");
+                retval = super.onOptionsItemSelected(item);
+                break;
+        }
+
+        return retval;
+    }
+
+    private void setLoadingMessage() {
+        emptyContentHeadline.setText(R.string.file_list_loading);
+        emptyContentMessage.setText("");
+
+        emptyContentIcon.setVisibility(View.GONE);
+        emptyContentProgressBar.setVisibility(View.VISIBLE);
+    }
+
+    private void setEmptyContent(String headline, String message) {
+        if (emptyContentContainer != null && emptyContentMessage != null) {
+            emptyContentHeadline.setText(headline);
+            emptyContentMessage.setText(message);
+
+            emptyContentProgressBar.setVisibility(View.GONE);
+            emptyContentIcon.setVisibility(View.VISIBLE);
+        }
+    }
+
+}

+ 5 - 0
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -305,6 +305,11 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU
                 uploadListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                 startActivity(uploadListIntent);
                 break;
+            case R.id.nav_activity:
+                Intent activityIntent = new Intent(getApplicationContext(), ActivitiesListActivity.class);
+                activityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                startActivity(activityIntent);
+                break;
             case R.id.nav_folder_sync:
                 Intent folderSyncIntent = new Intent(getApplicationContext(),FolderSyncActivity.class);
                 startActivity(folderSyncIntent);

+ 148 - 0
src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java

@@ -0,0 +1,148 @@
+/**
+ * Nextcloud Android client application
+ *
+ * @author Alejandro Bautista
+ * Copyright (C) 2017 Alejandro Bautista
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero 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.graphics.drawable.PictureDrawable;
+import android.net.Uri;
+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.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.GenericRequestBuilder;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+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.resources.activities.models.Activity;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.svg.SvgDecoder;
+import com.owncloud.android.utils.svg.SvgDrawableTranscoder;
+import com.owncloud.android.utils.svg.SvgSoftwareLayerSetter;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Adapter for the activity view
+ */
+
+public class ActivityListAdapter extends RecyclerView.Adapter<ActivityListAdapter.ActivityViewHolder> {
+
+    private Context context;
+    private List<Object> mValues;
+
+    public ActivityListAdapter(Context context) {
+        this.mValues = new ArrayList<>();
+        this.context = context;
+    }
+
+    public void setActivityItems(List<Object> activityItems) {
+        mValues.clear();
+        mValues.addAll(activityItems);
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public ActivityViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_list_item, parent, false);
+        return new ActivityViewHolder(v);
+    }
+
+    @Override
+    public void onBindViewHolder(ActivityViewHolder holder, int position) {
+        Activity activity = (Activity) mValues.get(position);
+        if (activity.getDatetime() != null) {
+            holder.dateTime.setText(DisplayUtils.getRelativeTimestamp(context,
+                    activity.getDatetime().getTime()));
+        } else {
+            holder.dateTime.setText(DisplayUtils.getRelativeTimestamp(context,
+                    activity.getDate().getTime()));
+        }
+
+        if (!TextUtils.isEmpty(activity.getSubject())) {
+            holder.subject.setText(activity.getSubject());
+            holder.subject.setVisibility(View.VISIBLE);
+        } else {
+            holder.subject.setVisibility(View.GONE);
+        }
+
+        if (!TextUtils.isEmpty(activity.getMessage())) {
+            holder.message.setText(activity.getMessage());
+            holder.message.setVisibility(View.VISIBLE);
+        } else {
+            holder.message.setVisibility(View.GONE);
+        }
+
+        if (!TextUtils.isEmpty(activity.getIcon())) {
+            downloadIcon(activity.getIcon(), holder.activityIcon);
+        }
+    }
+
+    private void downloadIcon(String icon, ImageView itemViewType) {
+        GenericRequestBuilder<Uri, InputStream, SVG, PictureDrawable> requestBuilder = Glide.with(context)
+                .using(Glide.buildStreamModelLoader(Uri.class, context), InputStream.class)
+                .from(Uri.class)
+                .as(SVG.class)
+                .transcode(new SvgDrawableTranscoder(), PictureDrawable.class)
+                .sourceEncoder(new StreamEncoder())
+                .cacheDecoder(new FileToStreamDecoder<>(new SvgDecoder()))
+                .decoder(new SvgDecoder())
+                .placeholder(R.drawable.ic_activity)
+                .error(R.drawable.ic_activity)
+                .animate(android.R.anim.fade_in)
+                .listener(new SvgSoftwareLayerSetter<Uri>());
+
+
+        Uri uri = Uri.parse(icon);
+        requestBuilder
+                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
+                .load(uri)
+                .into(itemViewType);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mValues.size();
+    }
+
+    class ActivityViewHolder extends RecyclerView.ViewHolder {
+
+        private final ImageView activityIcon;
+        private final TextView subject;
+        private final TextView message;
+        private final TextView dateTime;
+
+        private ActivityViewHolder(View itemView) {
+            super(itemView);
+            activityIcon = (ImageView) itemView.findViewById(R.id.activity_icon);
+            subject = (TextView) itemView.findViewById(R.id.activity_subject);
+            message = (TextView) itemView.findViewById(R.id.activity_message);
+            dateTime = (TextView) itemView.findViewById(R.id.activity_datetime);
+        }
+    }
+}

+ 0 - 2
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -999,6 +999,4 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended
         editor.putBoolean(String.valueOf(mFile.getFileId()), setGrid);
         editor.apply();
     }
-
-
 }

+ 40 - 0
src/main/java/com/owncloud/android/utils/svg/SvgDecoder.java

@@ -0,0 +1,40 @@
+/*
+ * Nextcloud Android client application
+ *
+ * Copyright 2014 Google, Inc. All rights reserved.
+ * Licenced under the BSD licence
+ *
+ * Borrowed from:
+ * https://github.com/bumptech/glide/blob/master/samples/svg/src/main/java/com/bumptech/glide/samples/svg/
+ * SvgDecoder.java
+ */
+
+package com.owncloud.android.utils.svg;
+
+import com.bumptech.glide.load.ResourceDecoder;
+import com.bumptech.glide.load.engine.Resource;
+import com.bumptech.glide.load.resource.SimpleResource;
+import com.caverock.androidsvg.SVG;
+import com.caverock.androidsvg.SVGParseException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Decodes an SVG internal representation from an {@link InputStream}.
+ */
+public class SvgDecoder implements ResourceDecoder<InputStream, SVG> {
+    public Resource<SVG> decode(InputStream source, int width, int height) throws IOException {
+        try {
+            SVG svg = SVG.getFromInputStream(source);
+            return new SimpleResource<SVG>(svg);
+        } catch (SVGParseException ex) {
+            throw new IOException("Cannot load SVG from stream", ex);
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "SvgDecoder.com.owncloud.android";
+    }
+}

+ 37 - 0
src/main/java/com/owncloud/android/utils/svg/SvgDrawableTranscoder.java

@@ -0,0 +1,37 @@
+/*
+ * Nextcloud Android client application
+ *
+ * Copyright 2014 Google, Inc. All rights reserved.
+ * Licenced under the BSD licence
+ *
+ * Borrowed from:
+ * https://github.com/bumptech/glide/blob/master/samples/svg/src/main/java/com/bumptech/glide/samples/svg/
+ * SvgDrawableTranscoder.java
+ */
+package com.owncloud.android.utils.svg;
+
+import android.graphics.Picture;
+import android.graphics.drawable.PictureDrawable;
+
+import com.bumptech.glide.load.engine.Resource;
+import com.bumptech.glide.load.resource.SimpleResource;
+import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
+import com.caverock.androidsvg.SVG;
+
+/**
+ * Convert the {@link SVG}'s internal representation to an Android-compatible one ({@link Picture}).
+ */
+public class SvgDrawableTranscoder implements ResourceTranscoder<SVG, PictureDrawable> {
+    @Override
+    public Resource<PictureDrawable> transcode(Resource<SVG> toTranscode) {
+        SVG svg = toTranscode.get();
+        Picture picture = svg.renderToPicture();
+        PictureDrawable drawable = new PictureDrawable(picture);
+        return new SimpleResource<PictureDrawable>(drawable);
+    }
+
+    @Override
+    public String getId() {
+        return "";
+    }
+}

+ 43 - 0
src/main/java/com/owncloud/android/utils/svg/SvgSoftwareLayerSetter.java

@@ -0,0 +1,43 @@
+/*
+ * Nextcloud Android client application
+ *
+ * Copyright 2014 Google, Inc. All rights reserved.
+ * Licenced under the BSD licence
+ *
+ * Borrowed from:
+ * https://github.com/bumptech/glide/blob/master/samples/svg/src/main/java/com/bumptech/glide/samples/svg/
+ * SvgSoftwareLayerSetter.java
+ */
+package com.owncloud.android.utils.svg;
+
+import android.annotation.TargetApi;
+import android.graphics.drawable.PictureDrawable;
+import android.os.Build;
+import android.widget.ImageView;
+
+import com.bumptech.glide.request.RequestListener;
+import com.bumptech.glide.request.target.ImageViewTarget;
+import com.bumptech.glide.request.target.Target;
+
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
+public class SvgSoftwareLayerSetter<T> implements RequestListener<T, PictureDrawable> {
+
+    @Override
+    public boolean onException(Exception e, T model, Target<PictureDrawable> target, boolean isFirstResource) {
+        ImageView view = ((ImageViewTarget<?>) target).getView();
+        if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
+            view.setLayerType(ImageView.LAYER_TYPE_NONE, null);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onResourceReady(PictureDrawable resource, T model, Target<PictureDrawable> target,
+                                   boolean isFromMemoryCache, boolean isFirstResource) {
+        ImageView view = ((ImageViewTarget<?>) target).getView();
+        if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
+            view.setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null);
+        }
+        return false;
+    }
+}

BIN=BIN
src/main/res/drawable-hdpi/ic_activity.png


BIN=BIN
src/main/res/drawable-hdpi/ic_activity_light_grey.png


BIN=BIN
src/main/res/drawable-mdpi/ic_activity.png


BIN=BIN
src/main/res/drawable-mdpi/ic_activity_light_grey.png


BIN=BIN
src/main/res/drawable-xhdpi/ic_activity.png


BIN=BIN
src/main/res/drawable-xhdpi/ic_activity_light_grey.png


BIN=BIN
src/main/res/drawable-xxhdpi/ic_activity.png


BIN=BIN
src/main/res/drawable-xxhdpi/ic_activity_light_grey.png


BIN=BIN
src/main/res/drawable-xxxhdpi/ic_activity.png


BIN=BIN
src/main/res/drawable-xxxhdpi/ic_activity_light_grey.png


+ 75 - 0
src/main/res/layout/activity_list_item.xml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2017 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program. If not, see <http://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="12dp">
+
+    <ImageView
+        android:id="@+id/activity_icon"
+        android:layout_width="@dimen/user_icon_size"
+        android:layout_height="@dimen/user_icon_size"
+        android:layout_alignParentTop="true"
+        android:layout_marginRight="24dp"
+        android:src="@drawable/ic_activity"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_alignTop="@id/activity_icon"
+        android:layout_toRightOf="@id/activity_icon">
+
+        <TextView
+            android:id="@+id/activity_subject"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:text="@string/placeholder_filename"
+            android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+        <TextView
+            android:id="@+id/activity_message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="3"
+            android:text="@string/placeholder_sentence"
+            android:textColor="?android:attr/textColorSecondary"/>
+
+        <TextView
+            android:id="@+id/activity_datetime"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="right"
+            android:ellipsize="end"
+            android:text="@string/placeholder_sentence"
+            android:textColor="?android:attr/textColorSecondary"/>
+
+    </LinearLayout>
+
+</RelativeLayout>

+ 81 - 0
src/main/res/layout/activity_list_layout.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Nextcloud Android client application
+
+  Copyright (C) 2017 Andy Scherzinger
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+  License as published by the Free Software Foundation; either
+  version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
+
+  You should have received a copy of the GNU Affero General Public
+  License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                                        android:id="@+id/drawer_layout"
+                                        android:layout_width="match_parent"
+                                        android:layout_height="match_parent"
+                                        android:clickable="true"
+                                        android:fitsSystemWindows="true">
+
+    <!-- The main content view -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <include
+            layout="@layout/toolbar_standard"/>
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <android.support.v4.widget.SwipeRefreshLayout
+                android:id="@+id/swipe_containing_list"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:footerDividersEnabled="false"
+                android:visibility="visible">
+
+                <android.support.v7.widget.RecyclerView
+                    android:id="@android:id/list"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_marginBottom="-3dp"
+                    android:layout_marginLeft="-3dp"
+                    android:layout_marginRight="-3dp"
+                    android:clipToPadding="false"
+                    android:scrollbarStyle="outsideOverlay"
+                    android:scrollbars="vertical"
+                    android:visibility="visible"/>
+
+            </android.support.v4.widget.SwipeRefreshLayout>
+
+            <android.support.v4.widget.SwipeRefreshLayout
+                android:id="@+id/swipe_containing_empty"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:footerDividersEnabled="false"
+                android:visibility="visible">
+
+                <include layout="@layout/empty_list"/>
+            </android.support.v4.widget.SwipeRefreshLayout>
+
+        </FrameLayout>
+
+    </LinearLayout>
+
+    <include
+        layout="@layout/drawer"
+        android:layout_width="240dp"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"/>
+
+</android.support.v4.widget.DrawerLayout>

+ 1 - 1
src/main/res/layout/user_info_layout.xml

@@ -46,7 +46,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
-                android:visibility="gone">
+                android:visibility="visible">
 
                 <android.support.v7.widget.CardView
                     android:id="@+id/primary_user_info_view"

+ 5 - 0
src/main/res/menu/drawer_menu.xml

@@ -37,6 +37,11 @@
             android:id="@+id/nav_uploads"
             android:icon="@drawable/ic_uploads"
             android:title="@string/drawer_item_uploads_list"/>
+        <item
+            android:orderInCategory="0"
+            android:id="@+id/nav_activity"
+            android:icon="@drawable/ic_activity"
+            android:title="@string/drawer_item_activities"/>
         <item
             android:orderInCategory="0"
             android:id="@+id/nav_folder_sync"

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

@@ -25,6 +25,7 @@
     <string name="drawer_item_on_device">On device</string>
     <string name="drawer_item_settings">Settings</string>
     <string name="drawer_item_uploads_list">Uploads</string>
+    <string name="drawer_item_activities">Activities</string>
     <string name="drawer_quota">%1$s of %2$s used</string>
 	<string name="drawer_close">Close</string>
     <string name="drawer_open">Open</string>
@@ -546,6 +547,10 @@
         <item quantity="one">%d selected</item>
         <item quantity="other">%d selected</item>
     </plurals>
+
+    <string name="activity_list_loading_activity">Loading activities&#8230;</string>
+    <string name="activity_list_no_results">No activities found.</string>
+
     <string name="upload_file_dialog_title">Input upload filename and filetype</string>
     <string name="upload_file_dialog_filename">Filename</string>
     <string name="upload_file_dialog_filetype">Filetype</string>
@@ -582,4 +587,9 @@
 
     <string name="user_information_description">User information</string>
 
+    <!-- Activities -->
+    <string name="activities_no_results_headline">No activity yet</string>
+    <string name="activities_no_results_message">This stream will show events like\nadditions, changes &amp; shares</string>
+
+
 </resources>