From 59c45f5627e5cfc3a98844399b99be273cf30119 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Fri, 19 Jul 2019 16:03:40 +0200 Subject: [PATCH] Kotlinized icons --- .../keepass/activities/EntryActivity.kt | 3 +- .../keepass/activities/EntryEditActivity.kt | 16 +- .../keepass/activities/GroupActivity.kt | 4 +- .../dialogs/GroupEditDialogFragment.kt | 16 +- .../dialogs/IconPickerDialogFragment.kt | 2 +- .../kunzisoft/keepass/adapters/NodeAdapter.kt | 3 +- .../adapters/SearchEntryCursorAdapter.kt | 3 +- .../keepass/icons/IconDrawableFactory.java | 335 ------------------ .../keepass/icons/IconDrawableFactory.kt | 258 ++++++++++++++ .../com/kunzisoft/keepass/icons/IconPack.java | 159 --------- .../com/kunzisoft/keepass/icons/IconPack.kt | 143 ++++++++ .../keepass/icons/IconPackChooser.java | 141 -------- .../keepass/icons/IconPackChooser.kt | 128 +++++++ .../icons/IconPackUnknownException.java | 8 - .../preference/IconPackListPreference.kt | 15 +- 15 files changed, 562 insertions(+), 672 deletions(-) delete mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java create mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt delete mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconPack.java create mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconPack.kt delete mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.java create mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.kt delete mode 100644 app/src/main/java/com/kunzisoft/keepass/icons/IconPackUnknownException.java diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt index 786f5c4a5..38177a673 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt @@ -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() diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt index db62f2957..10bd7294a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt @@ -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) } } diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt index 21bee42f5..0fce3cb4d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt @@ -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) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/GroupEditDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/GroupEditDialogFragment.kt index 5d26ae0fb..a2dc5c4a0 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/GroupEditDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/GroupEditDialogFragment.kt @@ -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(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) { diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/IconPickerDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/IconPickerDialogFragment.kt index 4e3be5d64..e47a49351 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/IconPickerDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/IconPickerDialogFragment.kt @@ -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 diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.kt b/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.kt index 8e497e182..199b0a71c 100644 --- a/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.kt +++ b/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.kt @@ -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 diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt index a9b7f58c7..0110b0027 100644 --- a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt +++ b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt @@ -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()) diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java deleted file mode 100644 index f878e6494..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java +++ /dev/null @@ -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 . - * - */ -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(); - } - -} diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt new file mode 100644 index 000000000..c6904138f --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt @@ -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 . + * + */ +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) + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconPack.java b/app/src/main/java/com/kunzisoft/keepass/icons/IconPack.java deleted file mode 100644 index 96cecae7c..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/icons/IconPack.java +++ /dev/null @@ -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 . - * - */ -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 - * - *

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 - *

- * - */ -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)); - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconPack.kt b/app/src/main/java/com/kunzisoft/keepass/icons/IconPack.kt new file mode 100644 index 000000000..3018c7d92 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/icons/IconPack.kt @@ -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 . + * + */ +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 + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.java b/app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.java deleted file mode 100644 index e1f3f4c2d..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.java +++ /dev/null @@ -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 . - * - */ -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 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 build.gradle - * - *

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')}
- * Each name of icon pack must be in {@code ICON_PACKS} in the build.gradle file

- * - * @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 getIconPackList(Context context) { - build(context); - return iconPackList; - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.kt b/app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.kt new file mode 100644 index 000000000..bd30ed8ca --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/icons/IconPackChooser.kt @@ -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 . + * + */ +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() + 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')`

+ * 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 { + build(context) + return iconPackList + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconPackUnknownException.java b/app/src/main/java/com/kunzisoft/keepass/icons/IconPackUnknownException.java deleted file mode 100644 index 15bd56c6b..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/icons/IconPackUnknownException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.kunzisoft.keepass.icons; - -public class IconPackUnknownException extends Exception{ - - IconPackUnknownException() { - super("Icon pack isn't defined"); - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/preference/IconPackListPreference.kt b/app/src/main/java/com/kunzisoft/keepass/settings/preference/IconPackListPreference.kt index 1fe803c91..fa6524309 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/preference/IconPackListPreference.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/preference/IconPackListPreference.kt @@ -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() val values = ArrayList() for (iconPack in IconPackChooser.getIconPackList(context)) { - entries.add(iconPack.name) - values.add(iconPack.id) + if (iconPack.id != null) { + entries.add(iconPack.name) + values.add(iconPack.id!!) + } } setEntries(entries.toTypedArray()) entryValues = values.toTypedArray() - setDefaultValue(IconPackChooser.getSelectedIconPack(context).id) + IconPackChooser.getSelectedIconPack(context)?.let { selectedIconPack -> + setDefaultValue(selectedIconPack.id) + } } }