Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
30 changes: 29 additions & 1 deletion app/src/main/java/org/fedorahosted/freeotp/ui/AddActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -65,7 +66,7 @@ class DeleteActivity : AppCompatActivity() {
return@collect
}

(findViewById<View>(R.id.issuer) as TextView).text = token.issuer
(findViewById<View>(R.id.issuer) as TextView).text = token.displayName()
(findViewById<View>(R.id.label) as TextView).text = token.label
binding.imageView.setTokenImage(token)
}
Expand Down
54 changes: 47 additions & 7 deletions app/src/main/java/org/fedorahosted/freeotp/ui/EditActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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<View>(R.id.issuer) as EditText
mLabel = findViewById<View>(R.id.label) as EditText
mAlias = findViewById<View>(R.id.alias) as EditText
mCategory = findViewById<View>(R.id.category) as AutoCompleteTextView
mIconKey = findViewById<View>(R.id.icon_key) as AutoCompleteTextView
mImage = findViewById<View>(R.id.image) as ImageButton
mRestore = findViewById<View>(R.id.restore) as Button
mSave = findViewById<View>(R.id.save) as Button
Expand All @@ -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<View>(R.id.cancel).setOnClickListener(this@EditActivity)
Expand All @@ -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
Expand Down Expand Up @@ -233,6 +252,8 @@ class EditActivity : AppCompatActivity(), TextWatcher, View.OnClickListener {
mCategory.setText("")
}
}

setupIconKeyAdapter()
}
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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 -> {
Expand All @@ -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()
)

Expand All @@ -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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
}
Loading