Browse Source

Merge pull request #7794 from nextcloud/themedHeader

Themes header: plain background color and logo, if available
Tobias Kaminsky 4 years ago
parent
commit
28f4cf94e7

+ 3 - 0
src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -2041,6 +2041,8 @@ public class FileDataStorageManager {
                           capability.getServerBackground());
         contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN,
                           capability.getServerSlogan());
+        contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_LOGO,
+                          capability.getServerLogo());
         contentValues.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION,
                           capability.getEndToEndEncryption().getValue());
         contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT,
@@ -2185,6 +2187,7 @@ public class FileDataStorageManager {
             capability.setServerElementColor(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_ELEMENT_COLOR));
             capability.setServerBackground(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_URL));
             capability.setServerSlogan(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN));
+            capability.setServerLogo(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_LOGO));
             capability.setEndToEndEncryption(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION));
             capability.setServerBackgroundDefault(
                 getBoolean(cursor, ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT));

+ 2 - 1
src/main/java/com/owncloud/android/db/ProviderMeta.java

@@ -35,7 +35,7 @@ import java.util.List;
  */
 public class ProviderMeta {
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 61;
+    public static final int DB_VERSION = 62;
 
     private ProviderMeta() {
         // No instance
@@ -211,6 +211,7 @@ public class ProviderMeta {
         public static final String CAPABILITIES_SERVER_ELEMENT_COLOR = "server_element_color";
         public static final String CAPABILITIES_SERVER_BACKGROUND_URL = "background_url";
         public static final String CAPABILITIES_SERVER_SLOGAN = "server_slogan";
+        public static final String CAPABILITIES_SERVER_LOGO = "server_logo";
         public static final String CAPABILITIES_SERVER_BACKGROUND_DEFAULT = "background_default";
         public static final String CAPABILITIES_SERVER_BACKGROUND_PLAIN = "background_plain";
         public static final String CAPABILITIES_END_TO_END_ENCRYPTION = "end_to_end_encryption";

+ 22 - 0
src/main/java/com/owncloud/android/providers/FileContentProvider.java

@@ -783,6 +783,7 @@ public class FileContentProvider extends ContentProvider {
                        + ProviderTableMeta.CAPABILITIES_SERVER_TEXT_COLOR + TEXT
                        + ProviderTableMeta.CAPABILITIES_SERVER_ELEMENT_COLOR + TEXT
                        + ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN + TEXT
+                       + ProviderTableMeta.CAPABILITIES_SERVER_LOGO + TEXT
                        + ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_URL + TEXT
                        + ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION + INTEGER
                        + ProviderTableMeta.CAPABILITIES_ACTIVITY + INTEGER
@@ -2305,6 +2306,27 @@ public class FileContentProvider extends ContentProvider {
             if (!upgraded) {
                 Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
             }
+
+            if (oldVersion < 62 && newVersion >= 62) {
+                Log_OC.i(SQL, "Entering in the #62 add logo to capability");
+                db.beginTransaction();
+                try {
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.CAPABILITIES_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.CAPABILITIES_SERVER_LOGO + " TEXT ");
+
+                    // force refresh
+                    db.execSQL("UPDATE capabilities SET etag = '' WHERE 1=1");
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+
+            if (!upgraded) {
+                Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
+            }
         }
     }
 }

+ 85 - 2
src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -33,21 +33,34 @@ import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.webkit.URLUtil;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 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.bumptech.glide.request.animation.GlideAnimation;
 import com.bumptech.glide.request.target.SimpleTarget;
 import com.google.android.material.button.MaterialButton;
@@ -93,6 +106,9 @@ import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.DrawerMenuUtil;
 import com.owncloud.android.utils.FilesSyncHelper;
 import com.owncloud.android.utils.svg.MenuSimpleTarget;
+import com.owncloud.android.utils.svg.SVGorImage;
+import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder;
+import com.owncloud.android.utils.svg.SvgOrImageDecoder;
 import com.owncloud.android.utils.theme.ThemeBarUtils;
 import com.owncloud.android.utils.theme.ThemeColorUtils;
 import com.owncloud.android.utils.theme.ThemeDrawableUtils;
@@ -104,6 +120,7 @@ import org.greenrobot.eventbus.ThreadMode;
 import org.parceler.Parcels;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -212,8 +229,7 @@ public abstract class DrawerActivity extends ToolbarActivity
 
             // Setting up drawer header
             mNavigationViewHeader = mNavigationView.getHeaderView(0);
-            FrameLayout drawerHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_view);
-            setupDrawerHeader(drawerHeader);
+            updateHeader();
 
             setupDrawerMenu(mNavigationView);
             getAndDisplayUserQuota();
@@ -278,6 +294,73 @@ public abstract class DrawerActivity extends ToolbarActivity
         ThemeBarUtils.colorProgressBar(mQuotaProgressBar, ThemeColorUtils.primaryColor(this));
     }
 
+    public void updateHeader() {
+        if (getAccount() != null &&
+            getStorageManager().getCapability(getAccount().name).getServerBackground() != null) {
+
+            OCCapability capability = getStorageManager().getCapability(getAccount().name);
+            String logo = capability.getServerLogo();
+            int primaryColor = ThemeColorUtils.primaryColor(getAccount(), false, this);
+
+            // set background to primary color
+            LinearLayout drawerHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_view);
+            drawerHeader.setBackgroundColor(ThemeColorUtils.unchangedPrimaryColor(getAccount(), this));
+
+            if (!TextUtils.isEmpty(logo) && URLUtil.isValidUrl(logo)) {
+                // background image
+                GenericRequestBuilder<Uri, InputStream, SVGorImage, Bitmap> requestBuilder = Glide.with(this)
+                    .using(Glide.buildStreamModelLoader(Uri.class, this), InputStream.class)
+                    .from(Uri.class)
+                    .as(SVGorImage.class)
+                    .transcode(new SvgOrImageBitmapTranscoder(128, 128), Bitmap.class)
+                    .sourceEncoder(new StreamEncoder())
+                    .cacheDecoder(new FileToStreamDecoder<>(new SvgOrImageDecoder()))
+                    .decoder(new SvgOrImageDecoder());
+
+                // background image
+                SimpleTarget target = new SimpleTarget<Bitmap>() {
+                    @Override
+                    public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
+                        Drawable[] drawables = {new ColorDrawable(primaryColor), new BitmapDrawable(resource)};
+                        LayerDrawable layerDrawable = new LayerDrawable(drawables);
+
+                        String name = capability.getServerName();
+                        setDrawerHeaderLogo(layerDrawable, name);
+                    }
+                };
+
+                requestBuilder
+                    .diskCacheStrategy(DiskCacheStrategy.SOURCE)
+                    .load(Uri.parse(logo))
+                    .into(target);
+            }
+        }
+    }
+
+    private void setDrawerHeaderLogo(Drawable drawable, String name) {
+        ImageView imageHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_logo);
+        imageHeader.setImageDrawable(drawable);
+        imageHeader.setScaleType(ImageView.ScaleType.FIT_START);
+        imageHeader.setAdjustViewBounds(true);
+
+        imageHeader.setMaxWidth(DisplayUtils.convertDpToPixel(100f, this));
+
+        MarginLayoutParams oldParam = (MarginLayoutParams) imageHeader.getLayoutParams();
+        MarginLayoutParams params = new MarginLayoutParams(LayoutParams.WRAP_CONTENT,
+                                                           LayoutParams.MATCH_PARENT);
+        params.leftMargin = oldParam.leftMargin;
+        params.rightMargin = oldParam.rightMargin;
+
+        imageHeader.setLayoutParams(new LinearLayout.LayoutParams(params));
+
+        if (!TextUtils.isEmpty(name)) {
+            TextView serverName = mNavigationViewHeader.findViewById(R.id.drawer_header_server_name);
+            serverName.setText(name);
+            serverName.setTextColor(ThemeColorUtils.unchangedFontColor(this));
+        }
+
+    }
+    
     /**
      * setup drawer header, basically the logo color
      */

+ 0 - 0
src/main/java/com/owncloud/android/utils/ThemeUtils.java


+ 47 - 0
src/main/java/com/owncloud/android/utils/svg/SVGorImage.java

@@ -0,0 +1,47 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2021 Tobias Kaminsky
+ * Copyright (C) 2021 Nextcloud GmbH
+ *
+ * Adapted from https://stackoverflow.com/a/54523482
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.utils.svg;
+
+import android.graphics.Bitmap;
+
+import com.caverock.androidsvg.SVG;
+
+public class SVGorImage {
+    private SVG svg;
+    private Bitmap bitmap;
+
+    public SVGorImage(SVG svg, Bitmap bitmap) {
+        this.svg = svg;
+        this.bitmap = bitmap;
+    }
+
+    public SVG getSVG() {
+        return svg;
+    }
+
+    public Bitmap getBitmap() {
+        return bitmap;
+    }
+}

+ 81 - 0
src/main/java/com/owncloud/android/utils/svg/SvgOrImageBitmapTranscoder.java

@@ -0,0 +1,81 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2021 Tobias Kaminsky
+ * Copyright (C) 2021 Nextcloud GmbH
+ *
+ * Adapted from https://stackoverflow.com/a/54523482
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.utils.svg;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+
+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;
+import com.caverock.androidsvg.SVGParseException;
+import com.owncloud.android.lib.common.utils.Log_OC;
+
+/**
+ * Convert the {@link SVG}'s internal representation to a Bitmap.
+ */
+public class SvgOrImageBitmapTranscoder implements ResourceTranscoder<SVGorImage, Bitmap> {
+    private int width;
+    private int height;
+
+    public SvgOrImageBitmapTranscoder(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    @Override
+    public Resource<Bitmap> transcode(Resource<SVGorImage> toTranscode) {
+        SVGorImage svGorImage = toTranscode.get();
+
+        if (svGorImage.getSVG() != null) {
+            SVG svg = svGorImage.getSVG();
+
+            try {
+                svg.setDocumentHeight("100%");
+                svg.setDocumentWidth("100%");
+            } catch (SVGParseException e) {
+                Log_OC.e(this, "Could not set document size. Output might have wrong size");
+            }
+
+            // Create a canvas to draw onto
+            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+
+            // Render our document onto our canvas
+            svg.renderToCanvas(canvas);
+
+            return new SimpleResource<>(bitmap);
+        } else {
+            Bitmap bitmap = svGorImage.getBitmap();
+
+            return new SimpleResource<>(bitmap);
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "";
+    }
+}

+ 77 - 0
src/main/java/com/owncloud/android/utils/svg/SvgOrImageDecoder.java

@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ * Adapted from https://stackoverflow.com/a/54523482
+ *
+ */
+
+package com.owncloud.android.utils.svg;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.bumptech.glide.load.ResourceDecoder;
+import com.bumptech.glide.load.engine.Resource;
+import com.bumptech.glide.load.resource.SimpleResource;
+import com.caverock.androidsvg.PreserveAspectRatio;
+import com.caverock.androidsvg.SVG;
+import com.caverock.androidsvg.SVGParseException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Decodes an SVG internal representation from an {@link InputStream}.
+ */
+public class SvgOrImageDecoder implements ResourceDecoder<InputStream, SVGorImage> {
+    private int height = -1;
+    private int width = -1;
+
+    public SvgOrImageDecoder(int height, int width) {
+        this.height = height;
+        this.width = width;
+    }
+
+    public SvgOrImageDecoder() {
+        // empty constructor
+    }
+
+    public Resource<SVGorImage> decode(InputStream source, int w, int h) throws IOException {
+        byte[] array = new byte[source.available()];
+        source.read(array);
+        ByteArrayInputStream svgInputStream = new ByteArrayInputStream(array.clone());
+        ByteArrayInputStream pngInputStream = new ByteArrayInputStream(array.clone());
+
+        try {
+            SVG svg = SVG.getFromInputStream(svgInputStream);
+            source.close();
+            pngInputStream.close();
+
+            if (width > 0) {
+                svg.setDocumentWidth(width);
+            }
+            if (height > 0) {
+                svg.setDocumentHeight(height);
+            }
+            svg.setDocumentPreserveAspectRatio(PreserveAspectRatio.LETTERBOX);
+
+            return new SimpleResource<>(new SVGorImage(svg, null));
+        } catch (SVGParseException ex) {
+            Bitmap bitmap = BitmapFactory.decodeStream(pngInputStream);
+            return new SimpleResource<>(new SVGorImage(null, bitmap));
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "SvgDecoder.com.owncloud.android";
+    }
+}

+ 20 - 0
src/main/java/com/owncloud/android/utils/theme/ThemeColorUtils.java

@@ -316,4 +316,24 @@ public final class ThemeColorUtils {
     public static String primaryColorToHexString(Context context) {
         return String.format("#%06X", 0xFFFFFF & primaryColor(context, true));
     }
+
+    public static int unchangedPrimaryColor(Account account, Context context) {
+        try {
+            return Color.parseColor(getCapability(account, context).getServerColor());
+        } catch (Exception e) {
+            return context.getResources().getColor(R.color.primary);
+        }
+    }
+
+    public static int unchangedFontColor(Context context) {
+        try {
+            return Color.parseColor(getCapability(context).getServerTextColor());
+        } catch (Exception e) {
+            if (darkTheme(context)) {
+                return Color.WHITE;
+            } else {
+                return Color.BLACK;
+            }
+        }
+    }
 }

+ 18 - 5
src/main/res/layout/drawer_header.xml

@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="utf-8"?>
+<!--
   Nextcloud Android client application
 
   Copyright (C) 2016 Andy Scherzinger
@@ -18,19 +19,31 @@
   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/>.
   -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/drawer_header_view"
     android:layout_width="match_parent"
     android:layout_height="@dimen/drawer_header_height"
-    android:fitsSystemWindows="true">
+    android:fitsSystemWindows="true"
+    android:orientation="horizontal"
+    tools:background="@color/primary">
 
     <ImageView
         android:id="@+id/drawer_header_logo"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_margin="@dimen/standard_margin"
-        android:contentDescription="@string/empty"
+        android:contentDescription="@null"
         android:scaleType="fitCenter"
         android:src="@drawable/nextcloud_logo" />
 
-</FrameLayout>
+    <TextView
+        android:id="@+id/drawer_header_server_name"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:ellipsize="middle"
+        android:gravity="center_vertical"
+        android:textSize="18sp"
+        android:textStyle="bold"
+        tools:text="Custom Server Name" />
+</LinearLayout>