From 4dbbd97db3f76716d9f25e47c392c4f4d2059237 Mon Sep 17 00:00:00 2001 From: ChrisWi Date: Mon, 13 Jul 2026 14:17:06 +0200 Subject: [PATCH] Extend add/capture token with 'alias' and 'icon' --- .../fedorahosted/freeotp/token/TokenLayout.kt | 3 +- .../fedorahosted/freeotp/ui/AddActivity.kt | 30 ++++++++++- .../fedorahosted/freeotp/ui/DeleteActivity.kt | 3 +- .../fedorahosted/freeotp/ui/EditActivity.kt | 54 ++++++++++++++++--- .../fedorahosted/freeotp/ui/MainViewModel.kt | 4 +- .../freeotp/ui/ShareQrCodeActivity.kt | 3 +- .../freeotp/util/TokenDisplayExtensions.kt | 13 +++++ .../freeotp/util/TokenImageViewExtensions.kt | 27 ++++++---- app/src/main/res/layout/metadata.xml | 45 ++++++++++++++++ app/src/main/res/values-af-rZA/strings.xml | 2 + app/src/main/res/values-ar-rSA/strings.xml | 2 + app/src/main/res/values-ca-rES/strings.xml | 2 + app/src/main/res/values-cs-rCZ/strings.xml | 2 + app/src/main/res/values-de-rDE/strings.xml | 2 + app/src/main/res/values-es-rES/strings.xml | 2 + app/src/main/res/values-eu-rES/strings.xml | 2 + app/src/main/res/values-fr-rFR/strings.xml | 2 + app/src/main/res/values-hu-rHU/strings.xml | 2 + app/src/main/res/values-id-rID/strings.xml | 2 + app/src/main/res/values-it-rIT/strings.xml | 2 + app/src/main/res/values-iw-rHE/strings.xml | 2 + app/src/main/res/values-ja-rJP/strings.xml | 2 + app/src/main/res/values-pl-rPL/strings.xml | 2 + app/src/main/res/values-pt-rBR/strings.xml | 2 + app/src/main/res/values-ru-rRU/strings.xml | 2 + app/src/main/res/values-si-rLK/strings.xml | 2 + app/src/main/res/values-sv-rSE/strings.xml | 2 + app/src/main/res/values-ta-rIN/strings.xml | 2 + app/src/main/res/values-tr-rTR/strings.xml | 2 + app/src/main/res/values-uk-rUA/strings.xml | 2 + app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + .../freeotp/data/MigrationUtil.kt | 4 ++ .../org/fedorahosted/freeotp/data/OtpToken.kt | 4 +- .../freeotp/data/OtpTokenDatabase.kt | 15 ++++-- .../freeotp/data/OtpTokenFactory.kt | 2 +- .../freeotp/data/legacy/Token.java | 22 +++++++- .../freeotp/data/module/DataModule.kt | 2 +- .../freeotp/token_images/TokenImage.kt | 8 +++ 40 files changed, 257 insertions(+), 30 deletions(-) create mode 100644 app/src/main/java/org/fedorahosted/freeotp/util/TokenDisplayExtensions.kt diff --git a/app/src/main/java/org/fedorahosted/freeotp/token/TokenLayout.kt b/app/src/main/java/org/fedorahosted/freeotp/token/TokenLayout.kt index b13392c7..ce124cfc 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/token/TokenLayout.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/token/TokenLayout.kt @@ -16,6 +16,7 @@ import org.fedorahosted.freeotp.R import org.fedorahosted.freeotp.data.OtpToken import org.fedorahosted.freeotp.data.OtpTokenType import org.fedorahosted.freeotp.data.legacy.TokenCode +import org.fedorahosted.freeotp.util.displayName import org.fedorahosted.freeotp.util.setTokenImage class TokenLayout : MaterialCardView, View.OnClickListener, Runnable { @@ -85,7 +86,7 @@ class TokenLayout : MaterialCardView, View.OnClickListener, Runnable { // Set the labels. mLabel.text = token.label - mIssuer.text = token.issuer + mIssuer.text = token.displayName() mCode.text = mPlaceholder if (mIssuer.text.isEmpty()) { mIssuer.text = token.label diff --git a/app/src/main/java/org/fedorahosted/freeotp/ui/AddActivity.kt b/app/src/main/java/org/fedorahosted/freeotp/ui/AddActivity.kt index f48a88c7..1acab600 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/ui/AddActivity.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/ui/AddActivity.kt @@ -44,7 +44,10 @@ import kotlinx.coroutines.launch import org.fedorahosted.freeotp.R import org.fedorahosted.freeotp.data.OtpTokenDatabase import org.fedorahosted.freeotp.data.OtpTokenFactory +import org.fedorahosted.freeotp.util.blankToNull import org.fedorahosted.freeotp.util.ImageUtil +import org.liberty.android.freeotp.token_images.TokenImage +import org.liberty.android.freeotp.token_images.displayKey import java.io.UnsupportedEncodingException import java.net.URLEncoder import java.util.* @@ -60,7 +63,9 @@ class AddActivity : AppCompatActivity(), View.OnClickListener, CompoundButton.On private lateinit var mImage: ImageButton private lateinit var mIssuer: EditText private lateinit var mLabel: EditText + private lateinit var mAlias: EditText private lateinit var mCategory: AutoCompleteTextView + private lateinit var mIconKey: AutoCompleteTextView private lateinit var mSecret: EditText private lateinit var mInterval: EditText private lateinit var mCounter: EditText @@ -91,7 +96,9 @@ class AddActivity : AppCompatActivity(), View.OnClickListener, CompoundButton.On mImage = findViewById(R.id.image) mIssuer = findViewById(R.id.issuer) mLabel = findViewById(R.id.label) + mAlias = findViewById(R.id.alias) mCategory = findViewById(R.id.category) + mIconKey = findViewById(R.id.icon_key) mSecret = findViewById(R.id.secret) mInterval = findViewById(R.id.interval) mCounter = findViewById(R.id.counter) @@ -114,10 +121,14 @@ class AddActivity : AppCompatActivity(), View.OnClickListener, CompoundButton.On val tw = AddTextWatcher(this) mIssuer.addTextChangedListener(tw) mLabel.addTextChangedListener(tw) + mAlias.addTextChangedListener(tw) mCategory.addTextChangedListener(tw) + mIconKey.addTextChangedListener(tw) mSecret.addTextChangedListener(AddSecretTextWatcher(this)) mInterval.addTextChangedListener(tw) + setupIconKeyAdapter() + lifecycleScope.launch { val categories = otpTokenDatabase.otpTokenDao().getAllCategories().first().toMutableList() categories.add(0, getString(R.string.uncategorized)) @@ -185,7 +196,9 @@ class AddActivity : AppCompatActivity(), View.OnClickListener, CompoundButton.On // Add the token lifecycleScope.launch { val token = OtpTokenFactory.createFromUri(Uri.parse(uri)).copy( - category = mCategory.text.toString() + alias = mAlias.text.toString().blankToNull(), + category = mCategory.text.toString().blankToNull(), + iconKey = mIconKey.text.toString().blankToNull() ) otpTokenDatabase.otpTokenDao().insert(token) setResult(Activity.RESULT_OK) @@ -216,4 +229,19 @@ class AddActivity : AppCompatActivity(), View.OnClickListener, CompoundButton.On } } } + + private fun setupIconKeyAdapter() { + val iconKeys = TokenImage.values().map { it.displayKey() } + val adapter = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, iconKeys) + mIconKey.setAdapter(adapter) + mIconKey.threshold = 0 + mIconKey.setOnClickListener { + mIconKey.showDropDown() + } + mIconKey.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + mIconKey.showDropDown() + } + } + } } diff --git a/app/src/main/java/org/fedorahosted/freeotp/ui/DeleteActivity.kt b/app/src/main/java/org/fedorahosted/freeotp/ui/DeleteActivity.kt index 21ed44ac..cf9ee782 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/ui/DeleteActivity.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/ui/DeleteActivity.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.launch import org.fedorahosted.freeotp.R import org.fedorahosted.freeotp.data.OtpTokenDatabase import org.fedorahosted.freeotp.databinding.DeleteBinding +import org.fedorahosted.freeotp.util.displayName import org.fedorahosted.freeotp.util.setTokenImage import javax.inject.Inject @@ -65,7 +66,7 @@ class DeleteActivity : AppCompatActivity() { return@collect } - (findViewById(R.id.issuer) as TextView).text = token.issuer + (findViewById(R.id.issuer) as TextView).text = token.displayName() (findViewById(R.id.label) as TextView).text = token.label binding.imageView.setTokenImage(token) } diff --git a/app/src/main/java/org/fedorahosted/freeotp/ui/EditActivity.kt b/app/src/main/java/org/fedorahosted/freeotp/ui/EditActivity.kt index 682889e1..3c8fe439 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/ui/EditActivity.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/ui/EditActivity.kt @@ -48,8 +48,11 @@ import kotlinx.coroutines.launch import org.fedorahosted.freeotp.R import org.fedorahosted.freeotp.data.OtpTokenDatabase import org.fedorahosted.freeotp.databinding.EditBinding +import org.fedorahosted.freeotp.util.blankToNull import org.fedorahosted.freeotp.util.ImageUtil import org.fedorahosted.freeotp.util.Settings +import org.liberty.android.freeotp.token_images.TokenImage +import org.liberty.android.freeotp.token_images.displayKey import javax.inject.Inject @AndroidEntryPoint @@ -62,7 +65,9 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { private lateinit var binding: EditBinding private lateinit var mIssuer: EditText private lateinit var mLabel: EditText + private lateinit var mAlias: EditText private lateinit var mCategory: AutoCompleteTextView + private lateinit var mIconKey: AutoCompleteTextView private lateinit var mImage: ImageButton private lateinit var mRestore: Button private lateinit var mSave: Button @@ -71,8 +76,12 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { private var mIssuerDefault: String? = null private var mLabelCurrent: String? = null private var mLabelDefault: String? = null + private var mAliasCurrent: String? = null + private var mAliasDefault: String? = null private var mCategoryCurrent: String? = null private var mCategoryDefault: String? = null + private var mIconKeyCurrent: String? = null + private var mIconKeyDefault: String? = null private var mImageCurrent: Uri? = null private var mImageDefault: Uri? = null @@ -123,17 +132,23 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { val token = otpTokenDatabase.otpTokenDao().get(tokenId).first() ?: return@launch mIssuerCurrent = token.issuer mLabelCurrent = token.label + mAliasCurrent = token.alias ?: "" mCategoryCurrent = token.category ?: "" + mIconKeyCurrent = token.iconKey ?: "" mImageCurrent = if (token.imagePath != null) Uri.parse(token.imagePath) else null mIssuerDefault = token.issuer mLabelDefault = token.label + mAliasDefault = mAliasCurrent mCategoryDefault = mCategoryCurrent + mIconKeyDefault = mIconKeyCurrent mImageDefault = mImageCurrent // Get references to widgets. mIssuer = findViewById(R.id.issuer) as EditText mLabel = findViewById(R.id.label) as EditText + mAlias = findViewById(R.id.alias) as EditText mCategory = findViewById(R.id.category) as AutoCompleteTextView + mIconKey = findViewById(R.id.icon_key) as AutoCompleteTextView mImage = findViewById(R.id.image) as ImageButton mRestore = findViewById(R.id.restore) as Button mSave = findViewById(R.id.save) as Button @@ -142,7 +157,9 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { // Setup text changed listeners. mIssuer.addTextChangedListener(this@EditActivity) mLabel.addTextChangedListener(this@EditActivity) + mAlias.addTextChangedListener(this@EditActivity) mCategory.addTextChangedListener(this@EditActivity) + mIconKey.addTextChangedListener(this@EditActivity) // Setup click callbacks. findViewById(R.id.cancel).setOnClickListener(this@EditActivity) @@ -157,7 +174,9 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { mLabel.setText(mLabelCurrent) mIssuer.setText(mIssuerCurrent) + mAlias.setText(mAliasCurrent) mCategory.setText(mCategoryCurrent) + mIconKey.setText(mIconKeyCurrent) mIssuer.setSelection(mIssuer.text.length) // Token details @@ -233,6 +252,8 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { mCategory.setText("") } } + + setupIconKeyAdapter() } } @@ -261,9 +282,11 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { val label = mLabel.text.toString() val issuer = mIssuer.text.toString() + val alias = mAlias.text.toString() val category = mCategory.text.toString() - mSave.isEnabled = label != mLabelCurrent || issuer != mIssuerCurrent || category != mCategoryCurrent || !imageIs(mImageCurrent) - mRestore.isEnabled = label != mLabelDefault || issuer != mIssuerDefault || category != mCategoryDefault || !imageIs(mImageDefault) + val iconKey = mIconKey.text.toString() + mSave.isEnabled = label != mLabelCurrent || issuer != mIssuerCurrent || alias != mAliasCurrent || category != mCategoryCurrent || iconKey != mIconKeyCurrent || !imageIs(mImageCurrent) + mRestore.isEnabled = label != mLabelDefault || issuer != mIssuerDefault || alias != mAliasDefault || category != mCategoryDefault || iconKey != mIconKeyDefault || !imageIs(mImageDefault) } override fun afterTextChanged(s: Editable) { @@ -281,11 +304,11 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { R.id.restore -> { mLabel.setText(mLabelDefault) mIssuer.setText(mIssuerDefault) + mAlias.setText(mAliasDefault) mCategory.setText(mCategoryDefault) + mIconKey.setText(mIconKeyDefault) mIssuer.setSelection(mIssuer.text.length) - mImageDefault?.let { - showImage(it) - } + showImage(mImageDefault) } R.id.save -> { @@ -294,7 +317,9 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { val newToken = token.copy( issuer = mIssuer.text.toString(), label = mLabel.text.toString(), - category = mCategory.text.toString(), + alias = mAlias.text.toString().blankToNull(), + category = mCategory.text.toString().blankToNull(), + iconKey = mIconKey.text.toString().blankToNull(), imagePath = mImageDisplay?.toString() ) @@ -312,8 +337,23 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener { } } + private fun setupIconKeyAdapter() { + val iconKeys = TokenImage.values().map { it.displayKey() } + val adapter = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, iconKeys) + mIconKey.setAdapter(adapter) + mIconKey.threshold = 0 + mIconKey.setOnClickListener { + mIconKey.showDropDown() + } + mIconKey.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + mIconKey.showDropDown() + } + } + } + companion object { const val EXTRA_TOKEN_ID = "token_id" const val IMAGE_REQUEST_CODE = 60 } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/fedorahosted/freeotp/ui/MainViewModel.kt b/app/src/main/java/org/fedorahosted/freeotp/ui/MainViewModel.kt index fea1603e..948fd0c1 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/ui/MainViewModel.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/ui/MainViewModel.kt @@ -66,7 +66,9 @@ class MainViewModel @Inject constructor( if (searchQuery.isNotEmpty()) { filteredTokens = filteredTokens.filter { token -> token.label.contains(searchQuery, true) - || token.issuer?.contains(searchQuery, true) ?: false + || (token.issuer?.contains(searchQuery, true) ?: false) + || (token.alias?.contains(searchQuery, true) ?: false) + || (token.iconKey?.contains(searchQuery, true) ?: false) } } diff --git a/app/src/main/java/org/fedorahosted/freeotp/ui/ShareQrCodeActivity.kt b/app/src/main/java/org/fedorahosted/freeotp/ui/ShareQrCodeActivity.kt index eb17be1c..0eeed0a2 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/ui/ShareQrCodeActivity.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/ui/ShareQrCodeActivity.kt @@ -37,6 +37,7 @@ import org.fedorahosted.freeotp.R import org.fedorahosted.freeotp.data.OtpTokenDatabase import org.fedorahosted.freeotp.data.OtpTokenFactory import org.fedorahosted.freeotp.databinding.ShareQrcodeBinding +import org.fedorahosted.freeotp.util.displayName import javax.inject.Inject @AndroidEntryPoint @@ -68,7 +69,7 @@ class ShareQrCodeActivity : AppCompatActivity() { // Get token values. val token = otpTokenDatabase.otpTokenDao().get(tokenId).first() ?: return@launch - title = token.issuer + title = token.displayName() // Get references to widgets. val qrcodeWriter = QRCodeWriter(); diff --git a/app/src/main/java/org/fedorahosted/freeotp/util/TokenDisplayExtensions.kt b/app/src/main/java/org/fedorahosted/freeotp/util/TokenDisplayExtensions.kt new file mode 100644 index 00000000..b3060f5a --- /dev/null +++ b/app/src/main/java/org/fedorahosted/freeotp/util/TokenDisplayExtensions.kt @@ -0,0 +1,13 @@ +package org.fedorahosted.freeotp.util + +import org.fedorahosted.freeotp.data.OtpToken + +fun OtpToken.displayName(): String { + return alias?.takeIf { it.isNotBlank() } + ?: issuer?.takeIf { it.isNotBlank() } + ?: label +} + +fun String?.blankToNull(): String? { + return this?.trim()?.takeIf { it.isNotEmpty() } +} diff --git a/app/src/main/java/org/fedorahosted/freeotp/util/TokenImageViewExtensions.kt b/app/src/main/java/org/fedorahosted/freeotp/util/TokenImageViewExtensions.kt index d54ec999..5fca728b 100644 --- a/app/src/main/java/org/fedorahosted/freeotp/util/TokenImageViewExtensions.kt +++ b/app/src/main/java/org/fedorahosted/freeotp/util/TokenImageViewExtensions.kt @@ -6,8 +6,8 @@ import com.amulyakhare.textdrawable.util.ColorGenerator import com.bumptech.glide.Glide import org.fedorahosted.freeotp.R import org.fedorahosted.freeotp.data.OtpToken -import org.liberty.android.freeotp.token_images.TokenImage import org.liberty.android.freeotp.token_images.matchToken +import org.liberty.android.freeotp.token_images.matchTokenImage fun ImageView.setTokenImage(token: OtpToken) { when { @@ -17,24 +17,31 @@ fun ImageView.setTokenImage(token: OtpToken) { .placeholder(R.drawable.logo) .into(this) } + !token.iconKey.isNullOrBlank() -> { + matchTokenImage(token.iconKey)?.let { + setImageResource(it.resource) + } ?: setFallbackTextImage(token) + } !token.issuer.isNullOrBlank() -> { matchIssuerWithTokenThumbnail(token)?.let { setImageResource(it) - } ?: run { - val tokenText = token.issuer?.substring(0, 1) ?: "" - val color = ColorGenerator.MATERIAL.getColor(tokenText) - val tokenTextDrawable = TextDrawable.builder().buildRoundRect(tokenText, color, 10) - setImageDrawable(tokenTextDrawable) - } + } ?: setFallbackTextImage(token) } else -> { - setImageResource(R.drawable.logo) + setFallbackTextImage(token) } } } +private fun ImageView.setFallbackTextImage(token: OtpToken) { + val tokenText = token.displayName().substring(0, 1) + val color = ColorGenerator.MATERIAL.getColor(tokenText) + val tokenTextDrawable = TextDrawable.builder().buildRoundRect(tokenText, color, 10) + setImageDrawable(tokenTextDrawable) +} + private fun matchIssuerWithTokenThumbnail(token: OtpToken): Int? { - return TokenImage.values().firstOrNull { + return org.liberty.android.freeotp.token_images.TokenImage.values().firstOrNull { it.matchToken(token.issuer, token.label) }?.resource -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/metadata.xml b/app/src/main/res/layout/metadata.xml index 7d126b77..9562ce0c 100644 --- a/app/src/main/res/layout/metadata.xml +++ b/app/src/main/res/layout/metadata.xml @@ -65,6 +65,28 @@ android:textAppearance="?android:attr/textAppearanceSmallInverse" /> + + + + + + + @@ -87,5 +109,28 @@ android:completionThreshold="1" android:textAppearance="?android:attr/textAppearanceSmallInverse" /> + + + + + + + diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af-rZA/strings.xml index b6ab5084..f2912502 100644 --- a/app/src/main/res/values-af-rZA/strings.xml +++ b/app/src/main/res/values-af-rZA/strings.xml @@ -12,6 +12,8 @@ Teller Uitreiker Rekening + Alias + Ikoon ID Geheim Tipe diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index 9f132e8f..2a747e43 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -12,6 +12,8 @@ أداة العد وحدة اصدار الحساب + الاسم المستعار + الأيقونة الكود السر النوع diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index 3b973102..8fc5e10a 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -12,6 +12,8 @@ Comptador Emissor Compte + Àlies + Icona Identificador Clau secreta Tipus diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 7dd134e3..9db89360 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -12,6 +12,8 @@ Počítadlo Vydavatel Účet + Alias + Ikona ID Tajný Typ diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 30313a93..c6a2e2bf 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -12,6 +12,8 @@ Zähler Aussteller Konto + Alias + Symbol ID Geheimnis Art diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index e464721d..8b13a190 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -12,6 +12,8 @@ Contador Emisor Cuenta + Alias + Icono ID Secreto Tipo diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu-rES/strings.xml index f6221ba2..c11b6549 100644 --- a/app/src/main/res/values-eu-rES/strings.xml +++ b/app/src/main/res/values-eu-rES/strings.xml @@ -12,6 +12,8 @@ Kontagailua Igorlea Kontua + Aliasa + Ikonoa ID Sekretua Mota diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index de84eba9..b8df4f4d 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -12,6 +12,8 @@ Compteur Émetteur Compte + Alias + Icône ID Secret Type diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 7c05bc05..9905975c 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -12,6 +12,8 @@ Számláló Kibocsátó Fiók + Álnév + Ikon Azonosító Titok Típus diff --git a/app/src/main/res/values-id-rID/strings.xml b/app/src/main/res/values-id-rID/strings.xml index 298ca398..43d6c93f 100644 --- a/app/src/main/res/values-id-rID/strings.xml +++ b/app/src/main/res/values-id-rID/strings.xml @@ -12,6 +12,8 @@ Counter Penerbit Akun + Alias + Ikon ID Kunci Rahasia Tipe diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 02a7a196..d5307311 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -12,6 +12,8 @@ Contatore Emittente Conto + Alias + Icona ID Segreto Tipo diff --git a/app/src/main/res/values-iw-rHE/strings.xml b/app/src/main/res/values-iw-rHE/strings.xml index c035d775..99404155 100644 --- a/app/src/main/res/values-iw-rHE/strings.xml +++ b/app/src/main/res/values-iw-rHE/strings.xml @@ -12,6 +12,8 @@ מונה מנפיק חשבון + כינוי + סמל מזהה סוד סוג diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 3b7f587c..f589a16e 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -12,6 +12,8 @@ カウンター 発行者 アカウント + エイリアス + アイコン ID 秘密鍵 タイプ diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index b6297f3b..1b674e55 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -12,6 +12,8 @@ Licznik Wydawca Konto + Alias + Ikona ID Sekret Typ diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 9908301c..26ac5ab7 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -12,6 +12,8 @@ Contador Emissor Conta + Apelido + Ícone ID Segredo Tipo diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 178c0cab..56e2299e 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -12,6 +12,8 @@ Счетчик Издатель Аккаунт + Псевдоним + Значок ID Секретный ключ Тип diff --git a/app/src/main/res/values-si-rLK/strings.xml b/app/src/main/res/values-si-rLK/strings.xml index 3042f4ce..cc5a9a58 100644 --- a/app/src/main/res/values-si-rLK/strings.xml +++ b/app/src/main/res/values-si-rLK/strings.xml @@ -12,6 +12,8 @@ කවුන්ටරය නිකුත් කරන්නා ගැන + අන්වර්ථ නාමය + නිරූපකය හැඳුනුම්පත රහස ටයිප් කරන්න diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index 1e48a5b2..e03ad0fe 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -12,6 +12,8 @@ Räknare Utfärdare Konto + Alias + Ikon ID Hemlighet Typ diff --git a/app/src/main/res/values-ta-rIN/strings.xml b/app/src/main/res/values-ta-rIN/strings.xml index 5d70b50c..7122a697 100644 --- a/app/src/main/res/values-ta-rIN/strings.xml +++ b/app/src/main/res/values-ta-rIN/strings.xml @@ -12,6 +12,8 @@ Counter வழங்குபவர் கணக்கு + மாற்றுப்பெயர் + ஐகான் ID இரகசிய கடவு வகை diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 79c46693..425e6657 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -12,6 +12,8 @@ Sayaç Yayınlayan Hesap + Takma ad + Simge Kimlik Gizli Anahtar Tip diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index 2ec9fe7c..7e2005be 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -12,6 +12,8 @@ Лічильник Видавець Обліковий запис + Псевдонім + Значок ІД Секрет Тип diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 08df180c..a5e039fd 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -12,6 +12,8 @@ 计数器 发布人 帐户 + 别名 + 图标 ID 密钥 类型 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 506a565b..6c9f10ea 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -12,6 +12,8 @@ 計數器 發行者 帳號 + 別名 + 圖示 ID 金鑰 類型 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 450cf297..6cb12510 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,6 +12,8 @@ Counter Issuer Account + Alias + Icon ID Secret Type diff --git a/token-data/src/main/java/org/fedorahosted/freeotp/data/MigrationUtil.kt b/token-data/src/main/java/org/fedorahosted/freeotp/data/MigrationUtil.kt index 1c6deb7b..2b4822f3 100644 --- a/token-data/src/main/java/org/fedorahosted/freeotp/data/MigrationUtil.kt +++ b/token-data/src/main/java/org/fedorahosted/freeotp/data/MigrationUtil.kt @@ -38,6 +38,8 @@ class MigrationUtil @Inject constructor( ordinal = index.toLong() + 1, issuer = legacyToken.issuer, label = legacyToken.label, + alias = legacyToken.alias, + iconKey = legacyToken.iconKey, imagePath = legacyToken.image?.toString(), tokenType = if (legacyToken.type == Token.TokenType.HOTP) OtpTokenType.HOTP else OtpTokenType.TOTP, algorithm = legacyToken.algorithm ?: "sha1", @@ -56,6 +58,8 @@ class MigrationUtil @Inject constructor( val uri = OtpTokenFactory.toUri(otpToken) Token(uri).apply { category = otpToken.category + alias = otpToken.alias + iconKey = otpToken.iconKey } } } diff --git a/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpToken.kt b/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpToken.kt index 060baa6b..6538a257 100644 --- a/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpToken.kt +++ b/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpToken.kt @@ -9,6 +9,8 @@ data class OtpToken ( val ordinal: Long, val issuer: String?, val label: String, + val alias: String? = null, + val iconKey: String? = null, val imagePath: String?, val tokenType: OtpTokenType, val algorithm: String, @@ -18,4 +20,4 @@ data class OtpToken ( val period: Int, val encryptionType: EncryptionType, val category: String? = null -) \ No newline at end of file +) diff --git a/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenDatabase.kt b/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenDatabase.kt index 89f84f16..f2efdd09 100644 --- a/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenDatabase.kt +++ b/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenDatabase.kt @@ -7,16 +7,23 @@ import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase import org.fedorahosted.freeotp.data.util.Converters -@Database(entities = [OtpToken::class], version = 2, exportSchema = false) +@Database(entities = [OtpToken::class], version = 3, exportSchema = false) @TypeConverters(Converters::class) abstract class OtpTokenDatabase : RoomDatabase() { abstract fun otpTokenDao(): OtpTokenDao companion object { val MIGRATION_1_2 = object : Migration(1, 2) { - override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("ALTER TABLE otp_tokens ADD COLUMN category TEXT") + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE otp_tokens ADD COLUMN category TEXT") + } + } + + val MIGRATION_2_3 = object : Migration(2, 3) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE otp_tokens ADD COLUMN alias TEXT") + db.execSQL("ALTER TABLE otp_tokens ADD COLUMN iconKey TEXT") } } } -} \ No newline at end of file +} diff --git a/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenFactory.kt b/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenFactory.kt index e2becb80..93170315 100644 --- a/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenFactory.kt +++ b/token-data/src/main/java/org/fedorahosted/freeotp/data/OtpTokenFactory.kt @@ -109,4 +109,4 @@ object OtpTokenFactory { return builder.build() } -} \ No newline at end of file +} diff --git a/token-data/src/main/java/org/fedorahosted/freeotp/data/legacy/Token.java b/token-data/src/main/java/org/fedorahosted/freeotp/data/legacy/Token.java index 4c3a6673..3404a8ff 100644 --- a/token-data/src/main/java/org/fedorahosted/freeotp/data/legacy/Token.java +++ b/token-data/src/main/java/org/fedorahosted/freeotp/data/legacy/Token.java @@ -56,6 +56,8 @@ public static enum TokenType { private String labelAlt; private String image; private String imageAlt; + private String alias; + private String iconKey; private TokenType type; private String algo; private byte[] secret; @@ -353,6 +355,22 @@ public void setCategory(String category) { this.category = category; } + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public String getIconKey() { + return iconKey; + } + + public void setIconKey(String iconKey) { + this.iconKey = iconKey; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -368,6 +386,8 @@ public boolean equals(Object o) { Objects.equals(labelAlt, token.labelAlt) && Objects.equals(image, token.image) && Objects.equals(imageAlt, token.imageAlt) && + Objects.equals(alias, token.alias) && + Objects.equals(iconKey, token.iconKey) && type == token.type && Objects.equals(algo, token.algo) && Arrays.equals(secret, token.secret) && @@ -376,7 +396,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = Objects.hash(issuerInt, issuerExt, issuerAlt, label, labelAlt, image, imageAlt, type, algo, digits, counter, period, category); + int result = Objects.hash(issuerInt, issuerExt, issuerAlt, label, labelAlt, image, imageAlt, alias, iconKey, type, algo, digits, counter, period, category); result = 31 * result + Arrays.hashCode(secret); return result; } diff --git a/token-data/src/main/java/org/fedorahosted/freeotp/data/module/DataModule.kt b/token-data/src/main/java/org/fedorahosted/freeotp/data/module/DataModule.kt index c08a7c76..671ba84d 100644 --- a/token-data/src/main/java/org/fedorahosted/freeotp/data/module/DataModule.kt +++ b/token-data/src/main/java/org/fedorahosted/freeotp/data/module/DataModule.kt @@ -18,7 +18,7 @@ object DataModule { @Provides fun database(@ApplicationContext context:Context) = Room.databaseBuilder(context, OtpTokenDatabase::class.java, "otp-token-db") - .addMigrations(OtpTokenDatabase.MIGRATION_1_2) + .addMigrations(OtpTokenDatabase.MIGRATION_1_2, OtpTokenDatabase.MIGRATION_2_3) .build() @Singleton diff --git a/token-images/src/main/java/org/liberty/android/freeotp/token_images/TokenImage.kt b/token-images/src/main/java/org/liberty/android/freeotp/token_images/TokenImage.kt index 06f34acd..f9247bca 100644 --- a/token-images/src/main/java/org/liberty/android/freeotp/token_images/TokenImage.kt +++ b/token-images/src/main/java/org/liberty/android/freeotp/token_images/TokenImage.kt @@ -279,3 +279,11 @@ fun TokenImage.matchToken(issuer: String?, label: String?): Boolean { issuerMatched } } + +fun TokenImage.displayKey(): String = issuer ?: name + +fun matchTokenImage(query: String?, label: String? = null): TokenImage? { + return TokenImage.values().firstOrNull { + it.matchToken(query, label) + } +}