mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Kotlinized icons
This commit is contained in:
@@ -42,6 +42,7 @@ import com.kunzisoft.keepass.view.EntryContentsView
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.PwNodeId
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.notifications.NotificationEntryCopyManager
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil.isFirstTimeAskAllowCopyPasswordAndProtectedFields
|
||||
@@ -140,7 +141,7 @@ class EntryActivity : LockingHideActivity() {
|
||||
val database = App.currentDatabase
|
||||
database.startManageEntry(entry)
|
||||
// Assign title icon
|
||||
database.drawFactory.assignDatabaseIconTo(this, titleIconView, entry.icon, iconColor)
|
||||
titleIconView?.assignDatabaseIcon(database.drawFactory, entry.icon, iconColor)
|
||||
|
||||
// Assign title text
|
||||
titleView?.text = entry.getVisualTitle()
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.kunzisoft.keepass.activities.dialogs.GeneratePasswordDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment
|
||||
import com.kunzisoft.keepass.activities.dialogs.IconPickerDialogFragment.Companion.KEY_ICON_STANDARD
|
||||
import com.kunzisoft.keepass.activities.lock.LockingHideActivity
|
||||
import com.kunzisoft.keepass.view.EntryEditCustomField
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
||||
import com.kunzisoft.keepass.database.action.node.ActionNodeValues
|
||||
@@ -45,11 +44,14 @@ import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.education.EntryEditActivityEducation
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.icons.assignDefaultDatabaseIcon
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.utils.MenuUtil
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
import com.kunzisoft.keepass.view.EntryEditCustomField
|
||||
|
||||
class EntryEditActivity : LockingHideActivity(), IconPickerDialogFragment.IconPickerListener, GeneratePasswordDialogFragment.GeneratePasswordListener {
|
||||
|
||||
@@ -140,7 +142,9 @@ class EntryEditActivity : LockingHideActivity(), IconPickerDialogFragment.IconPi
|
||||
mEntry = mDatabase?.createEntry()
|
||||
mParent = mDatabase?.getGroupById(it)
|
||||
// Add the default icon
|
||||
mDatabase?.drawFactory?.assignDefaultDatabaseIconTo(this, entryIconView, iconColor)
|
||||
mDatabase?.drawFactory?.let { iconFactory ->
|
||||
entryIconView?.assignDefaultDatabaseIcon(iconFactory, iconColor)
|
||||
}
|
||||
}
|
||||
|
||||
// Close the activity if entry or parent can't be retrieve
|
||||
@@ -392,12 +396,8 @@ class EntryEditActivity : LockingHideActivity(), IconPickerDialogFragment.IconPi
|
||||
}
|
||||
|
||||
private fun assignIconView() {
|
||||
mEntry?.icon?.let {
|
||||
mDatabase?.drawFactory?.assignDatabaseIconTo(
|
||||
this,
|
||||
entryIconView,
|
||||
it,
|
||||
iconColor)
|
||||
if (mDatabase?.drawFactory != null && mEntry?.icon != null) {
|
||||
entryIconView?.assignDatabaseIcon(mDatabase?.drawFactory!!, mEntry?.icon!!, iconColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.kunzisoft.keepass.database.action.ProgressDialogSaveDatabaseThread
|
||||
import com.kunzisoft.keepass.database.action.node.*
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService
|
||||
import com.kunzisoft.keepass.magikeyboard.KeyboardHelper
|
||||
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
||||
@@ -347,7 +348,8 @@ class GroupActivity : LockingActivity(),
|
||||
// Assign the group icon depending of IconPack or custom icon
|
||||
iconView?.visibility = View.VISIBLE
|
||||
mCurrentGroup?.let {
|
||||
mDatabase?.drawFactory?.assignDatabaseIconTo(this, iconView, it.icon, mIconColor)
|
||||
if (mDatabase?.drawFactory != null)
|
||||
iconView?.assignDatabaseIcon(mDatabase?.drawFactory!!, it.icon, mIconColor)
|
||||
|
||||
if (toolbar != null) {
|
||||
if (mCurrentGroup?.containsParent() == true)
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.GroupVersioned
|
||||
import com.kunzisoft.keepass.database.element.PwIcon
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
|
||||
class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconPickerListener {
|
||||
|
||||
@@ -45,7 +46,7 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
private var nameGroup: String? = null
|
||||
private var iconGroup: PwIcon? = null
|
||||
|
||||
private var iconButton: ImageView? = null
|
||||
private var iconButtonView: ImageView? = null
|
||||
private var iconColor: Int = 0
|
||||
|
||||
enum class EditGroupDialogAction {
|
||||
@@ -76,7 +77,7 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
activity?.let { activity ->
|
||||
val root = activity.layoutInflater.inflate(R.layout.group_edit, null)
|
||||
val nameField = root?.findViewById<TextView>(R.id.group_edit_name)
|
||||
iconButton = root?.findViewById(R.id.group_edit_icon_button)
|
||||
iconButtonView = root?.findViewById(R.id.group_edit_icon_button)
|
||||
|
||||
// Retrieve the textColor to tint the icon
|
||||
val ta = activity.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColorPrimary))
|
||||
@@ -133,7 +134,7 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
this@GroupEditDialogFragment.dialog.cancel()
|
||||
}
|
||||
|
||||
iconButton?.setOnClickListener { _ ->
|
||||
iconButtonView?.setOnClickListener { _ ->
|
||||
fragmentManager?.let {
|
||||
IconPickerDialogFragment().show(it, "IconPickerDialogFragment")
|
||||
}
|
||||
@@ -145,12 +146,9 @@ class GroupEditDialogFragment : DialogFragment(), IconPickerDialogFragment.IconP
|
||||
}
|
||||
|
||||
private fun assignIconView() {
|
||||
mDatabase?.drawFactory
|
||||
?.assignDatabaseIconTo(
|
||||
context,
|
||||
iconButton,
|
||||
iconGroup,
|
||||
iconColor)
|
||||
if (mDatabase?.drawFactory != null && iconGroup != null) {
|
||||
iconButtonView?.assignDatabaseIcon(mDatabase?.drawFactory!!, iconGroup!!, iconColor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun iconPicked(bundle: Bundle) {
|
||||
|
||||
@@ -61,7 +61,7 @@ class IconPickerDialogFragment : DialogFragment() {
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
|
||||
iconPack = IconPackChooser.getSelectedIconPack(context)
|
||||
iconPack = IconPackChooser.getSelectedIconPack(context!!)
|
||||
|
||||
// Inflate and set the layout for the dialog
|
||||
// Pass null as the parent view because its going in the dialog layout
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.Util
|
||||
|
||||
@@ -207,7 +208,7 @@ class NodeAdapter
|
||||
Type.GROUP -> iconGroupColor
|
||||
Type.ENTRY -> iconEntryColor
|
||||
}
|
||||
mDatabase.drawFactory.assignDatabaseIconTo(context, holder.icon, subNode.icon, iconColor)
|
||||
holder.icon?.assignDatabaseIcon(mDatabase.drawFactory, subNode.icon, iconColor)
|
||||
// Assign text
|
||||
holder.text?.text = subNode.title
|
||||
// Assign click
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.kunzisoft.keepass.database.cursor.EntryCursor
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.EntryVersioned
|
||||
import com.kunzisoft.keepass.database.element.PwIcon
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import java.util.*
|
||||
|
||||
@@ -89,7 +90,7 @@ class SearchEntryCursorAdapter(context: Context, private val database: Database)
|
||||
val viewHolder = view.tag as ViewHolder
|
||||
|
||||
// Assign image
|
||||
database.drawFactory.assignDatabaseIconTo(context, viewHolder.imageViewIcon, icon, iconColor)
|
||||
viewHolder.imageViewIcon?.assignDatabaseIcon(database.drawFactory, icon, iconColor)
|
||||
|
||||
// Assign title
|
||||
val showTitle = EntryVersioned.getVisualTitle(false, title, username, url, uuid.toString())
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.icons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.widget.ImageViewCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.database.element.PwIcon;
|
||||
import com.kunzisoft.keepass.database.element.PwIconCustom;
|
||||
import com.kunzisoft.keepass.database.element.PwIconStandard;
|
||||
|
||||
import org.apache.commons.collections.map.AbstractReferenceMap;
|
||||
import org.apache.commons.collections.map.ReferenceMap;
|
||||
|
||||
/**
|
||||
* Factory class who build database icons dynamically, can assign an icon of IconPack, or a custom icon to an ImageView with a tint
|
||||
*/
|
||||
public class IconDrawableFactory {
|
||||
|
||||
private static final String TAG = IconDrawableFactory.class.getName();
|
||||
|
||||
private static Drawable blank = null;
|
||||
private static int blankWidth = -1;
|
||||
private static int blankHeight = -1;
|
||||
|
||||
/** customIconMap
|
||||
* Cache for icon drawable.
|
||||
* Keys: UUID, Values: Drawables
|
||||
*/
|
||||
private ReferenceMap customIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
|
||||
|
||||
/** standardIconMap
|
||||
* Cache for icon drawable.
|
||||
* Keys: Integer, Values: Drawables
|
||||
*/
|
||||
private ReferenceMap standardIconMap = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK);
|
||||
|
||||
/**
|
||||
* Assign a default database icon to an ImageView and tint it if needed
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param iconView ImageView that will host the drawable
|
||||
* @param tintColor Use this color to tint tintable icon
|
||||
*/
|
||||
public void assignDefaultDatabaseIconTo(Context context, ImageView iconView, int tintColor) {
|
||||
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
|
||||
assignDrawableTo(context,
|
||||
iconView,
|
||||
IconPackChooser.getSelectedIconPack(context).getDefaultIconId(),
|
||||
true,
|
||||
tintColor);
|
||||
} else {
|
||||
assignDrawableTo(context,
|
||||
iconView,
|
||||
IconPackChooser.getSelectedIconPack(context).getDefaultIconId(),
|
||||
false,
|
||||
Color.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a database icon to an ImageView and tint it if needed
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param iconView ImageView that will host the drawable
|
||||
* @param icon The icon from the database
|
||||
* @param tintColor Use this color to tint tintable icon
|
||||
*/
|
||||
public void assignDatabaseIconTo(Context context, ImageView iconView, PwIcon icon, int tintColor) {
|
||||
if (IconPackChooser.getSelectedIconPack(context).tintable()) {
|
||||
assignDrawableToImageView(getIconDrawable(context, icon, true, tintColor),
|
||||
iconView,
|
||||
true,
|
||||
tintColor);
|
||||
} else {
|
||||
assignDrawableToImageView(getIconDrawable(context, icon, true, tintColor),
|
||||
iconView,
|
||||
false,
|
||||
Color.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an image by its resourceId to an ImageView and tint it
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param imageView ImageView that will host the drawable
|
||||
* @param iconId iconId from the resources
|
||||
* @param tint true will tint the drawable with tintColor
|
||||
* @param tintColor Use this color if tint is true
|
||||
*/
|
||||
public void assignDrawableTo(Context context, ImageView imageView, int iconId, boolean tint, int tintColor) {
|
||||
assignDrawableToImageView(new SuperDrawable(getIconDrawable(context, iconId, tint, tintColor)),
|
||||
imageView,
|
||||
tint,
|
||||
tintColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to assign a drawable to an ImageView and tint it
|
||||
*/
|
||||
private void assignDrawableToImageView(SuperDrawable superDrawable, ImageView imageView, boolean tint, int tintColor) {
|
||||
if (imageView != null && superDrawable.drawable != null) {
|
||||
imageView.setImageDrawable(superDrawable.drawable);
|
||||
if (!superDrawable.custom && tint) {
|
||||
ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(tintColor));
|
||||
} else {
|
||||
ImageViewCompat.setImageTintList(imageView, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the drawable icon from cache or build it and add it to the cache if not exists yet
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param icon The icon from database
|
||||
* @return The build drawable
|
||||
*/
|
||||
public Drawable getIconDrawable(Context context, PwIcon icon) {
|
||||
return getIconDrawable(context, icon, false, Color.WHITE).drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the drawable icon from cache or build it and add it to the cache if not exists yet then tint it if needed
|
||||
*
|
||||
* @param context Context to build the drawable
|
||||
* @param icon The icon from database
|
||||
* @param tint true will tint the drawable with tintColor
|
||||
* @param tintColor Use this color if tint is true
|
||||
* @return The build drawable
|
||||
*/
|
||||
public SuperDrawable getIconDrawable(Context context, PwIcon icon, boolean tint, int tintColor) {
|
||||
if (icon instanceof PwIconStandard) {
|
||||
return new SuperDrawable(getIconDrawable(context.getApplicationContext(), (PwIconStandard) icon, tint, tintColor));
|
||||
} else {
|
||||
return new SuperDrawable(getIconDrawable(context, (PwIconCustom) icon), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a blank drawable
|
||||
* @param res Resource to build the drawable
|
||||
*/
|
||||
private static void initBlank(Resources res) {
|
||||
if (blank==null) {
|
||||
blankWidth = (int) res.getDimension(R.dimen.icon_size);
|
||||
blankHeight = (int) res.getDimension(R.dimen.icon_size);
|
||||
blank = new ColorDrawable(Color.TRANSPARENT);
|
||||
blank.setBounds(0, 0, blankWidth, blankHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Key class to retrieve a Drawable in the cache if it's tinted or not
|
||||
*/
|
||||
private class CacheKey {
|
||||
int resId;
|
||||
boolean isTint;
|
||||
int color;
|
||||
|
||||
CacheKey(int resId, boolean isTint, int color) {
|
||||
this.resId = resId;
|
||||
this.isTint = isTint;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CacheKey cacheKey = (CacheKey) o;
|
||||
if (isTint)
|
||||
return resId == cacheKey.resId &&
|
||||
cacheKey.isTint &&
|
||||
color == cacheKey.color;
|
||||
else
|
||||
return resId == cacheKey.resId &&
|
||||
!cacheKey.isTint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the drawable icon from cache or build it and add it to the cache if not exists yet
|
||||
*
|
||||
* @param context Context to make drawable
|
||||
* @param icon Icon from database
|
||||
* @param isTint Tint the drawable if true
|
||||
* @param tintColor Use this color if tint is true
|
||||
* @return The drawable
|
||||
*/
|
||||
private Drawable getIconDrawable(Context context, PwIconStandard icon, boolean isTint, int tintColor) {
|
||||
int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.getIconId());
|
||||
|
||||
return getIconDrawable(context, resId, isTint, tintColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the drawable icon from cache or build it and add it to the cache if not exists yet
|
||||
*
|
||||
* @param context Context to make drawable
|
||||
* @param iconId iconId from resources
|
||||
* @param isTint Tint the drawable if true
|
||||
* @param tintColor Use this color if tint is true
|
||||
* @return The drawable
|
||||
*/
|
||||
private Drawable getIconDrawable(Context context, int iconId, boolean isTint, int tintColor) {
|
||||
CacheKey newCacheKey = new CacheKey(iconId, isTint, tintColor);
|
||||
|
||||
Drawable draw = (Drawable) standardIconMap.get(newCacheKey);
|
||||
if (draw == null) {
|
||||
try {
|
||||
draw = ContextCompat.getDrawable(context, iconId);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can't get icon", e);
|
||||
}
|
||||
if (draw != null) {
|
||||
standardIconMap.put(newCacheKey, draw);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw == null) {
|
||||
if (blank == null)
|
||||
initBlank(context.getResources());
|
||||
draw = blank;
|
||||
}
|
||||
|
||||
return draw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class to prevent a custom icon to be tint
|
||||
*/
|
||||
private class SuperDrawable {
|
||||
Drawable drawable;
|
||||
boolean custom;
|
||||
|
||||
SuperDrawable(Drawable drawable) {
|
||||
this.drawable = drawable;
|
||||
this.custom = false;
|
||||
}
|
||||
|
||||
SuperDrawable(Drawable drawable, boolean custom) {
|
||||
this.drawable = drawable;
|
||||
this.custom = custom;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a custom icon from database
|
||||
* @param context Context to build the drawable
|
||||
* @param icon Icon from database
|
||||
* @return The drawable
|
||||
*/
|
||||
private Drawable getIconDrawable(Context context, PwIconCustom icon) {
|
||||
initBlank(context.getResources());
|
||||
if (icon == null) {
|
||||
return blank;
|
||||
}
|
||||
|
||||
Drawable draw = (Drawable) customIconMap.get(icon.getUuid());
|
||||
|
||||
if (draw == null) {
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(icon.getImageData(), 0, icon.getImageData().length);
|
||||
|
||||
// Could not understand custom icon
|
||||
if (bitmap == null) {
|
||||
return blank;
|
||||
}
|
||||
|
||||
bitmap = resize(bitmap);
|
||||
|
||||
draw = new BitmapDrawable(context.getResources(), bitmap);
|
||||
customIconMap.put(icon.getUuid(), draw);
|
||||
}
|
||||
|
||||
return draw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the custom icon to match the built in icons
|
||||
*
|
||||
* @param bitmap Bitmap to resize
|
||||
* @return Bitmap resized
|
||||
*/
|
||||
private Bitmap resize(Bitmap bitmap) {
|
||||
int width = bitmap.getWidth();
|
||||
int height = bitmap.getHeight();
|
||||
|
||||
if (width == blankWidth && height == blankHeight) {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
return Bitmap.createScaledBitmap(bitmap, blankWidth, blankHeight, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache of icons
|
||||
*/
|
||||
public void clearCache() {
|
||||
standardIconMap.clear();
|
||||
customIconMap.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.icons
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.support.v4.content.res.ResourcesCompat
|
||||
import android.support.v4.widget.ImageViewCompat
|
||||
import android.util.Log
|
||||
import android.widget.ImageView
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.PwIcon
|
||||
import com.kunzisoft.keepass.database.element.PwIconCustom
|
||||
import com.kunzisoft.keepass.database.element.PwIconStandard
|
||||
import org.apache.commons.collections.map.AbstractReferenceMap
|
||||
import org.apache.commons.collections.map.ReferenceMap
|
||||
|
||||
/**
|
||||
* Factory class who build database icons dynamically, can assign an icon of IconPack, or a custom icon to an ImageView with a tint
|
||||
*/
|
||||
class IconDrawableFactory {
|
||||
|
||||
/** customIconMap
|
||||
* Cache for icon drawable.
|
||||
* Keys: UUID, Values: Drawables
|
||||
*/
|
||||
private val customIconMap = ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK)
|
||||
|
||||
/** standardIconMap
|
||||
* Cache for icon drawable.
|
||||
* Keys: Integer, Values: Drawables
|
||||
*/
|
||||
private val standardIconMap = ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.WEAK)
|
||||
|
||||
/**
|
||||
* Utility method to assign a drawable to an ImageView and tint it
|
||||
*/
|
||||
fun assignDrawableToImageView(superDrawable: SuperDrawable, imageView: ImageView?, tint: Boolean, tintColor: Int) {
|
||||
if (imageView != null) {
|
||||
imageView.setImageDrawable(superDrawable.drawable)
|
||||
if (!superDrawable.custom && tint) {
|
||||
ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(tintColor))
|
||||
} else {
|
||||
ImageViewCompat.setImageTintList(imageView, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [SuperDrawable] [icon] (from cache, or build it and add it to the cache if not exists yet), then [tint] it with [tintColor] if needed
|
||||
*/
|
||||
fun getIconSuperDrawable(context: Context, icon: PwIcon, tint: Boolean = false, tintColor: Int = Color.WHITE): SuperDrawable {
|
||||
return when (icon) {
|
||||
is PwIconStandard -> {
|
||||
val resId = IconPackChooser.getSelectedIconPack(context)?.iconToResId(icon.iconId) ?: R.drawable.ic_blank_32dp
|
||||
getIconSuperDrawable(context, resId, tint, tintColor)
|
||||
}
|
||||
is PwIconCustom -> {
|
||||
SuperDrawable(getIconDrawable(context.resources, icon), true)
|
||||
}
|
||||
else -> {
|
||||
SuperDrawable(PatternIcon(context.resources).blankDrawable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [SuperDrawable] PwIconStandard from [iconId] (cache, or build it and add it to the cache if not exists yet)
|
||||
* , then [tint] it with [tintColor] if needed
|
||||
*/
|
||||
fun getIconSuperDrawable(context: Context, iconId: Int, tint: Boolean, tintColor: Int): SuperDrawable {
|
||||
return SuperDrawable(getIconDrawable(context.resources, iconId, tint, tintColor))
|
||||
}
|
||||
|
||||
/**
|
||||
* Key class to retrieve a Drawable in the cache if it's tinted or not
|
||||
*/
|
||||
private inner class CacheKey internal constructor(internal var resId: Int, internal var isTint: Boolean, internal var color: Int) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
val cacheKey = other as CacheKey
|
||||
return if (isTint)
|
||||
resId == cacheKey.resId &&
|
||||
cacheKey.isTint &&
|
||||
color == cacheKey.color
|
||||
else
|
||||
resId == cacheKey.resId && !cacheKey.isTint
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = resId
|
||||
result = 31 * result + isTint.hashCode()
|
||||
result = 31 * result + color
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a custom [Drawable] from custom [icon]
|
||||
*/
|
||||
private fun getIconDrawable(resources: Resources, icon: PwIconCustom): Drawable {
|
||||
val patternIcon = PatternIcon(resources)
|
||||
|
||||
var draw: Drawable? = customIconMap[icon.uuid] as Drawable?
|
||||
if (draw == null) {
|
||||
var bitmap: Bitmap? = BitmapFactory.decodeByteArray(icon.imageData, 0, icon.imageData.size)
|
||||
// Could not understand custom icon
|
||||
bitmap?.let { bitmapIcon ->
|
||||
bitmap = resize(bitmapIcon, patternIcon)
|
||||
draw = BitmapDrawable(resources, bitmap)
|
||||
customIconMap[icon.uuid] = draw
|
||||
return draw!!
|
||||
}
|
||||
} else {
|
||||
return draw!!
|
||||
}
|
||||
return patternIcon.blankDrawable
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the standard [Drawable] icon from [iconId] (cache or build it and add it to the cache if not exists yet)
|
||||
* , then [tint] it with [tintColor] if needed
|
||||
*/
|
||||
private fun getIconDrawable(resources: Resources, iconId: Int, tint: Boolean, tintColor: Int): Drawable {
|
||||
val newCacheKey = CacheKey(iconId, tint, tintColor)
|
||||
|
||||
var draw: Drawable? = standardIconMap[newCacheKey] as Drawable?
|
||||
if (draw == null) {
|
||||
try {
|
||||
draw = ResourcesCompat.getDrawable(resources, iconId, null)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Can't get icon", e)
|
||||
}
|
||||
|
||||
if (draw != null) {
|
||||
standardIconMap[newCacheKey] = draw
|
||||
}
|
||||
}
|
||||
|
||||
if (draw == null) {
|
||||
draw = PatternIcon(resources).blankDrawable
|
||||
}
|
||||
|
||||
return draw
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the custom icon to match the built in icons
|
||||
*
|
||||
* @param bitmap Bitmap to resize
|
||||
* @return Bitmap resized
|
||||
*/
|
||||
private fun resize(bitmap: Bitmap, dimensionPattern: PatternIcon): Bitmap {
|
||||
val width = bitmap.width
|
||||
val height = bitmap.height
|
||||
|
||||
return if (width == dimensionPattern.width && height == dimensionPattern.height) {
|
||||
bitmap
|
||||
} else Bitmap.createScaledBitmap(bitmap, dimensionPattern.width, dimensionPattern.height, true)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache of icons
|
||||
*/
|
||||
fun clearCache() {
|
||||
standardIconMap.clear()
|
||||
customIconMap.clear()
|
||||
}
|
||||
|
||||
private class PatternIcon
|
||||
/**
|
||||
* Build a blankDrawable drawable
|
||||
* @param res Resource to build the drawable
|
||||
*/(res: Resources) {
|
||||
|
||||
var blankDrawable: Drawable = ColorDrawable(Color.TRANSPARENT)
|
||||
var width = -1
|
||||
var height = -1
|
||||
|
||||
init {
|
||||
width = res.getDimension(R.dimen.icon_size).toInt()
|
||||
height = res.getDimension(R.dimen.icon_size).toInt()
|
||||
blankDrawable.setBounds(0, 0, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class to prevent a custom icon to be tint
|
||||
*/
|
||||
class SuperDrawable(var drawable: Drawable, var custom: Boolean = false)
|
||||
|
||||
companion object {
|
||||
|
||||
private val TAG = IconDrawableFactory::class.java.name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a default database icon to an ImageView and tint it with [tintColor] if needed
|
||||
*/
|
||||
fun ImageView.assignDefaultDatabaseIcon(iconFactory: IconDrawableFactory, tintColor: Int = Color.WHITE) {
|
||||
IconPackChooser.getSelectedIconPack(context)?.let { selectedIconPack ->
|
||||
|
||||
iconFactory.assignDrawableToImageView(
|
||||
iconFactory.getIconSuperDrawable(context,
|
||||
selectedIconPack.defaultIconId,
|
||||
selectedIconPack.tintable(),
|
||||
tintColor),
|
||||
this,
|
||||
selectedIconPack.tintable(),
|
||||
tintColor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a database [icon] to an ImageView and tint it with [tintColor] if needed
|
||||
*/
|
||||
fun ImageView.assignDatabaseIcon(iconFactory: IconDrawableFactory, icon: PwIcon, tintColor: Int = Color.WHITE) {
|
||||
IconPackChooser.getSelectedIconPack(context)?.let { selectedIconPack ->
|
||||
|
||||
iconFactory.assignDrawableToImageView(
|
||||
iconFactory.getIconSuperDrawable(context,
|
||||
icon,
|
||||
true,
|
||||
tintColor),
|
||||
this,
|
||||
selectedIconPack.tintable(),
|
||||
tintColor)
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.icons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* Class who construct dynamically database icons contains in a separate library
|
||||
*
|
||||
* <p>It only supports icons with specific nomenclature <strong>[stringId]_[%2d]_32dp</strong>
|
||||
* where [stringId] contains in a string xml attribute with id <strong>resource_id</strong> and
|
||||
* [%2d] 2 numerical numbers between 00 and 68 included,
|
||||
* </p>
|
||||
* <p>See <i>icon-pack-classic</i> module as sample
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class IconPack {
|
||||
|
||||
private static final int NB_ICONS = 68;
|
||||
|
||||
private SparseIntArray icons;
|
||||
private String resourceStringId;
|
||||
private String name;
|
||||
private boolean tintable;
|
||||
|
||||
private Resources resources;
|
||||
|
||||
/**
|
||||
* Construct dynamically the icon pack provide by the string resource id
|
||||
*
|
||||
* @param context Context of the app to retrieve the resources
|
||||
* @param resourceId String Id of the pack (ex : com.kunzisoft.keepass.icon.classic.R.string.resource_id)
|
||||
*/
|
||||
IconPack(Context context, int resourceId) {
|
||||
|
||||
resources = context.getResources();
|
||||
icons = new SparseIntArray();
|
||||
resourceStringId = context.getString(resourceId);
|
||||
// If finish with a _ remove it
|
||||
if (resourceStringId.lastIndexOf('_') == resourceStringId.length() - 1)
|
||||
resourceStringId = resourceStringId.substring(0, resourceStringId.length() -1);
|
||||
|
||||
// Build the list of icons
|
||||
int num = 0;
|
||||
while(num <= NB_ICONS) {
|
||||
// To construct the id with name_ic_XX_32dp (ex : classic_ic_08_32dp )
|
||||
int resId = resources.getIdentifier(
|
||||
resourceStringId + "_" + new DecimalFormat("00").format(num) + "_32dp",
|
||||
"drawable",
|
||||
context.getPackageName());
|
||||
icons.put(num, resId);
|
||||
num++;
|
||||
}
|
||||
// Get visual name
|
||||
name = resources.getString(
|
||||
resources.getIdentifier(
|
||||
resourceStringId + "_" + "name",
|
||||
"string",
|
||||
context.getPackageName()
|
||||
)
|
||||
);
|
||||
// If icons are tintable
|
||||
tintable = resources.getBoolean(
|
||||
resources.getIdentifier(
|
||||
resourceStringId + "_" + "tintable",
|
||||
"bool",
|
||||
context.getPackageName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the IconPack
|
||||
*
|
||||
* @return String visual name of the pack
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the IconPack
|
||||
*
|
||||
* @return String id of the pack
|
||||
*/
|
||||
public String getId() {
|
||||
return resourceStringId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if each icon in the pack can be tint
|
||||
*
|
||||
* @return true if icons are tintable
|
||||
*/
|
||||
public boolean tintable() {
|
||||
return tintable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of icons in this pack
|
||||
*
|
||||
* @return int Number of database icons
|
||||
*/
|
||||
public int numberOfIcons() {
|
||||
return icons.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon as a resourceId
|
||||
*
|
||||
* @param iconId Icon database Id of the icon to retrieve
|
||||
* @return int resourceId
|
||||
*/
|
||||
public int iconToResId(int iconId) {
|
||||
return icons.get(iconId, R.drawable.ic_blank_32dp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Get the default icon resource id
|
||||
*/
|
||||
public int getDefaultIconId() {
|
||||
return iconToResId(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon as a drawable
|
||||
*
|
||||
* @param iconId Icon database Id of the icon to retrieve
|
||||
* @return int resourceId
|
||||
*/
|
||||
public Drawable getDrawable(int iconId) {
|
||||
return resources.getDrawable(iconToResId(iconId));
|
||||
}
|
||||
}
|
||||
143
app/src/main/java/com/kunzisoft/keepass/icons/IconPack.kt
Normal file
143
app/src/main/java/com/kunzisoft/keepass/icons/IconPack.kt
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.icons
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.util.SparseIntArray
|
||||
import com.kunzisoft.keepass.R
|
||||
import java.text.DecimalFormat
|
||||
|
||||
/**
|
||||
* Class who construct dynamically database icons contains in a separate library
|
||||
*
|
||||
*
|
||||
* It only supports icons with specific nomenclature **[stringId]_[%2d]_32dp**
|
||||
* where [stringId] contains in a string xml attribute with id **resource_id** and
|
||||
* [%2d] 2 numerical numbers between 00 and 68 included,
|
||||
*
|
||||
*
|
||||
* See *icon-pack-classic* module as sample
|
||||
*
|
||||
*
|
||||
*/
|
||||
class IconPack
|
||||
/**
|
||||
* Construct dynamically the icon pack provide by the string resource id
|
||||
*
|
||||
* @param packageName Context of the app to retrieve the resources
|
||||
* @param packageName Context of the app to retrieve the resources
|
||||
* @param resourceId String Id of the pack (ex : com.kunzisoft.keepass.icon.classic.R.string.resource_id)
|
||||
*/
|
||||
internal constructor(packageName: String, resources: Resources, resourceId: Int) {
|
||||
|
||||
private val icons: SparseIntArray = SparseIntArray()
|
||||
/**
|
||||
* Get the id of the IconPack
|
||||
*
|
||||
* @return String id of the pack
|
||||
*/
|
||||
var id: String? = null
|
||||
private set
|
||||
/**
|
||||
* Get the name of the IconPack
|
||||
*
|
||||
* @return String visual name of the pack
|
||||
*/
|
||||
val name: String
|
||||
|
||||
private val tintable: Boolean
|
||||
|
||||
/**
|
||||
* @return int Get the default icon resource id
|
||||
*/
|
||||
val defaultIconId: Int
|
||||
get() = iconToResId(0)
|
||||
|
||||
init {
|
||||
|
||||
id = resources.getString(resourceId)
|
||||
// If finish with a _ remove it
|
||||
id?.let { idRes ->
|
||||
if (idRes.lastIndexOf('_') == idRes.length - 1)
|
||||
id = idRes.substring(0, idRes.length - 1)
|
||||
}
|
||||
|
||||
// Build the list of icons
|
||||
var num = 0
|
||||
while (num <= NB_ICONS) {
|
||||
// To construct the id with name_ic_XX_32dp (ex : classic_ic_08_32dp )
|
||||
val resId = resources.getIdentifier(
|
||||
id + "_" + DecimalFormat("00").format(num.toLong()) + "_32dp",
|
||||
"drawable",
|
||||
packageName)
|
||||
icons.put(num, resId)
|
||||
num++
|
||||
}
|
||||
// Get visual name
|
||||
name = resources.getString(
|
||||
resources.getIdentifier(
|
||||
id + "_" + "name",
|
||||
"string",
|
||||
packageName
|
||||
)
|
||||
)
|
||||
// If icons are tintable
|
||||
tintable = resources.getBoolean(
|
||||
resources.getIdentifier(
|
||||
id + "_" + "tintable",
|
||||
"bool",
|
||||
packageName
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if each icon in the pack can be tint
|
||||
*
|
||||
* @return true if icons are tintable
|
||||
*/
|
||||
fun tintable(): Boolean {
|
||||
return tintable
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of icons in this pack
|
||||
*
|
||||
* @return int Number of database icons
|
||||
*/
|
||||
fun numberOfIcons(): Int {
|
||||
return icons.size()
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon as a resourceId
|
||||
*
|
||||
* @param iconId Icon database Id of the icon to retrieve
|
||||
* @return int resourceId
|
||||
*/
|
||||
fun iconToResId(iconId: Int): Int {
|
||||
return icons.get(iconId, R.drawable.ic_blank_32dp)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val NB_ICONS = 68
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.icons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class to built and select an IconPack dynamically by libraries importation
|
||||
*
|
||||
* @author J-Jamet
|
||||
*/
|
||||
public class IconPackChooser {
|
||||
|
||||
private static final String TAG = IconPackChooser.class.getName();
|
||||
|
||||
private static List<IconPack> iconPackList = new ArrayList<>();
|
||||
private static IconPack iconPackSelected = null;
|
||||
|
||||
private static IconPackChooser sIconPackBuilder;
|
||||
|
||||
/**
|
||||
* IconPackChooser as singleton
|
||||
*/
|
||||
private IconPackChooser(){
|
||||
if (sIconPackBuilder != null){
|
||||
throw new RuntimeException("Use build() method to get the single instance of this class.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Built the icon pack chooser based on imports made in <i>build.gradle</i>
|
||||
*
|
||||
* <p>Dynamic import can be done for each flavor by prefixing the 'implementation' command with the name of the flavor.< br/>
|
||||
* (ex : {@code libreImplementation project(path: ':icon-pack-classic')} <br />
|
||||
* Each name of icon pack must be in {@code ICON_PACKS} in the build.gradle file</p>
|
||||
*
|
||||
* @param context Context to construct each pack with the resources
|
||||
* @return An unique instance of {@link IconPackChooser}, recall {@link #build(Context)} provide the same instance
|
||||
*/
|
||||
@SuppressWarnings("JavaDoc")
|
||||
public static IconPackChooser build(Context context) {
|
||||
if (sIconPackBuilder == null) { //if there is no instance available... create new one
|
||||
synchronized (IconPackChooser.class) {
|
||||
if (sIconPackBuilder == null) {
|
||||
sIconPackBuilder = new IconPackChooser();
|
||||
|
||||
for (String iconPackString : BuildConfig.ICON_PACKS) {
|
||||
addOrCatchNewIconPack(context, iconPackString);
|
||||
}
|
||||
if (iconPackList.isEmpty()) {
|
||||
Log.e(TAG, "Icon packs can't be load, retry with one by default");
|
||||
addDefaultIconPack(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sIconPackBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct dynamically the icon pack provide by the default string resource "resource_id"
|
||||
*/
|
||||
private static void addDefaultIconPack(Context context) {
|
||||
int resourceId = context.getResources().getIdentifier("resource_id", "string", context.getPackageName());
|
||||
iconPackList.add(new IconPack(context, resourceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to add new icon pack or catch exception if not retrieve
|
||||
*/
|
||||
private static void addOrCatchNewIconPack(Context context, String iconPackString) {
|
||||
try {
|
||||
iconPackList.add(new IconPack(context, context.getResources().getIdentifier(
|
||||
iconPackString + "_resource_id",
|
||||
"string",
|
||||
context.getPackageName())));
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Icon pack "+ iconPackString +" can't be load");
|
||||
}
|
||||
}
|
||||
|
||||
public static void setSelectedIconPack(String iconPackIdString) {
|
||||
for(IconPack iconPack : iconPackList) {
|
||||
if (iconPack.getId().equals(iconPackIdString)) {
|
||||
App.Companion.getCurrentDatabase().getDrawFactory().clearCache();
|
||||
iconPackSelected = iconPack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current IconPack used
|
||||
*
|
||||
* @param context Context to build the icon pack if not already build
|
||||
* @return IconPack currently in usage
|
||||
*/
|
||||
public static IconPack getSelectedIconPack(Context context) {
|
||||
build(context);
|
||||
if (iconPackSelected == null)
|
||||
setSelectedIconPack(PreferencesUtil.INSTANCE.getIconPackSelectedId(context));
|
||||
return iconPackSelected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of IconPack available
|
||||
*
|
||||
* @param context Context to build the icon pack if not already build
|
||||
* @return IconPack available
|
||||
*/
|
||||
public static List<IconPack> getIconPackList(Context context) {
|
||||
build(context);
|
||||
return iconPackList;
|
||||
}
|
||||
}
|
||||
128
app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.kt
Normal file
128
app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.kt
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2018 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.icons
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig
|
||||
import com.kunzisoft.keepass.app.App
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Utility class to built and select an IconPack dynamically by libraries importation
|
||||
*
|
||||
* @author J-Jamet
|
||||
*/
|
||||
object IconPackChooser {
|
||||
|
||||
private val TAG = IconPackChooser::class.java.name
|
||||
|
||||
private val iconPackList = ArrayList<IconPack>()
|
||||
private var iconPackSelected: IconPack? = null
|
||||
|
||||
private var isIconPackChooserBuilt: Boolean = false
|
||||
|
||||
/**
|
||||
* Built the icon pack chooser based on imports made in *build.gradle*
|
||||
*
|
||||
*
|
||||
* Dynamic import can be done for each flavor by prefixing the 'implementation' command with the name of the flavor.< br/>
|
||||
* (ex : `libreImplementation project(path: ':icon-pack-classic')` <br></br>
|
||||
* Each name of icon pack must be in `ICON_PACKS` in the build.gradle file
|
||||
*
|
||||
* @param context Context to construct each pack with the resources
|
||||
* @return An unique instance of [IconPackChooser], recall [.build] provide the same instance
|
||||
*/
|
||||
fun build(context: Context) {
|
||||
synchronized(IconPackChooser::class.java) {
|
||||
if (!isIconPackChooserBuilt) {
|
||||
isIconPackChooserBuilt = true
|
||||
|
||||
for (iconPackString in BuildConfig.ICON_PACKS) {
|
||||
addOrCatchNewIconPack(context, iconPackString)
|
||||
}
|
||||
if (iconPackList.isEmpty()) {
|
||||
Log.e(TAG, "Icon packs can't be load, retry with one by default")
|
||||
addDefaultIconPack(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct dynamically the icon pack provide by the default string resource "resource_id"
|
||||
*/
|
||||
private fun addDefaultIconPack(context: Context) {
|
||||
val resourceId = context.resources.getIdentifier("resource_id", "string", context.packageName)
|
||||
iconPackList.add(IconPack(context.packageName, context.resources, resourceId))
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to add new icon pack or catch exception if not retrieve
|
||||
*/
|
||||
private fun addOrCatchNewIconPack(context: Context, iconPackString: String) {
|
||||
try {
|
||||
iconPackList.add(IconPack(context.packageName, context.resources, context.resources.getIdentifier(
|
||||
iconPackString + "_resource_id",
|
||||
"string",
|
||||
context.packageName)))
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Icon pack $iconPackString can't be load")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setSelectedIconPack(iconPackIdString: String?) {
|
||||
for (iconPack in iconPackList) {
|
||||
if (iconPack.id == iconPackIdString) {
|
||||
App.currentDatabase.drawFactory.clearCache()
|
||||
iconPackSelected = iconPack
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current IconPack used
|
||||
*
|
||||
* @param context Context to build the icon pack if not already build
|
||||
* @return IconPack currently in usage
|
||||
*/
|
||||
fun getSelectedIconPack(context: Context): IconPack? {
|
||||
build(context)
|
||||
if (iconPackSelected == null)
|
||||
setSelectedIconPack(PreferencesUtil.getIconPackSelectedId(context))
|
||||
return iconPackSelected
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of IconPack available
|
||||
*
|
||||
* @param context Context to build the icon pack if not already build
|
||||
* @return IconPack available
|
||||
*/
|
||||
fun getIconPackList(context: Context): List<IconPack> {
|
||||
build(context)
|
||||
return iconPackList
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.kunzisoft.keepass.icons;
|
||||
|
||||
public class IconPackUnknownException extends Exception{
|
||||
|
||||
IconPackUnknownException() {
|
||||
super("Icon pack isn't defined");
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,9 @@ package com.kunzisoft.keepass.settings.preference
|
||||
import android.content.Context
|
||||
import android.support.v7.preference.ListPreference
|
||||
import android.util.AttributeSet
|
||||
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.icons.IconPack
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.*
|
||||
|
||||
class IconPackListPreference @JvmOverloads constructor(context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@@ -20,12 +17,16 @@ class IconPackListPreference @JvmOverloads constructor(context: Context,
|
||||
val entries = ArrayList<String>()
|
||||
val values = ArrayList<String>()
|
||||
for (iconPack in IconPackChooser.getIconPackList(context)) {
|
||||
if (iconPack.id != null) {
|
||||
entries.add(iconPack.name)
|
||||
values.add(iconPack.id)
|
||||
values.add(iconPack.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
setEntries(entries.toTypedArray())
|
||||
entryValues = values.toTypedArray()
|
||||
setDefaultValue(IconPackChooser.getSelectedIconPack(context).id)
|
||||
IconPackChooser.getSelectedIconPack(context)?.let { selectedIconPack ->
|
||||
setDefaultValue(selectedIconPack.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user