-
Notifications
You must be signed in to change notification settings - Fork 104
Conversation
Thanks for your first contribution, @mihainisipeanusv. I'll defer to the engineering and UX teams to help review this. A few pointers, since I failed to explain these the other day:
Thanks again! 🏅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR seems to work well, but I think it needs some work before it lands.
The uni-directional data flow would demand that we set up an ItemDetailStore
and perhaps a ClipboardStore
; this would get rid of a bunch view layer code in your presenter, and make it more testable. You can see how the swift version works in the ItemDetailStore and CopyDisplayStore.
Please also read the rest of the comments, and ask questions if they don't make sense.
get() = tapStub | ||
|
||
override val editUsername: EditText | ||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: unwanted TODO
, and generated comments.
|
||
override fun updateItem(item: ItemDetailViewModel) { | ||
this.item = item | ||
} | ||
|
||
override fun copyNotification(strId: Int) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: have you forgotten to git add
something, or should this be a // NOOP
comment?
} | ||
|
||
override fun updatePasswordField(visible: Boolean){ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same.
override val editUsername: EditText | ||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. | ||
override val editPassword: EditText | ||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same.
@@ -6,23 +6,69 @@ | |||
|
|||
package mozilla.lockbox.presenter | |||
|
|||
import android.util.Log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use log
, which is declared in LockboxApplication
.
|
||
this.view.btnPasswordCopyClicks | ||
.subscribe { | ||
clipboardCopy("password", view.editPassword.text.toString()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should be using the ServerPassword
or the ItemDetailViewModel
version of the username/password, rather than the UI version.
private val dispatcher: Dispatcher = Dispatcher.shared, | ||
private val dataStore: DataStore = DataStore.shared | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: whitespace.
|
||
interface ItemDetailView { | ||
var itemId: String? | ||
fun updateItem(item: ItemDetailViewModel) | ||
fun copyNotification(strId: Int) | ||
fun updatePasswordField(visible: Boolean) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a boolean flag like this, consider using a field with a getter/setter.
inputPassword.transformationMethod = null | ||
btnPasswordToggle.setImageResource(R.drawable.ic_hide) | ||
} else { | ||
inputPassword.transformationMethod = PasswordTransformationMethod() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using PasswordTransformationMethod.getInstance()
val subject = ItemDetailPresenter(view, dataStore = dataStore) | ||
val clipboardManager = Mockito.mock(ClipboardManager::class.java) | ||
|
||
val subject = ItemDetailPresenter(view, clipboardManager, dataStore = dataStore) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests needed.
@mihainisipeanusv this looks great and functions as expected. I did notice an issue with the icon sizes & color. After digging into Zeplin, I realized that although the icons were exportable, they were retaining the original size & color of our icon symbol within Sketch. Meaning although we had resized this icon to 18px by 18px and changed the color in the design, it was exporting at 16px as well as not including the transparent bounding box. I apologize for this and have fixed this in Zeplin now, as well as am including the icons below. My assumption is that we will take care of styling the snackbar for the copy notifications in a later issue, is that correct?
|
nick I had noticed that the new version of the hide and show icon are not ok. In the hide one the eye is at the image center and in the show is not, and when you change image it just jump up and down |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your hard work on this. This is starting to look like the right shape. :)
I've added some more comments. Ask in #Lockbox slack or in the PR itself if you have any questions.
app/src/main/java/mozilla/lockbox/presenter/ItemDetailPresenter.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/mozilla/lockbox/presenter/ItemDetailPresenter.kt
Outdated
Show resolved
Hide resolved
inputPassword.transformationMethod = PasswordTransformationMethod.getInstance() | ||
btnPasswordToggle.setImageResource(R.drawable.ic_icon_show) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice.
app/src/main/java/mozilla/lockbox/presenter/ItemDetailPresenter.kt
Outdated
Show resolved
Hide resolved
) : Presenter() { | ||
|
||
override fun onViewReady() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: whitespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting really close.
Please make the final changes and land this.
Lovely work, thank you.
view.itemId?.let { | ||
dataStore.get(it) | ||
.subscribe { | ||
dispatcher.dispatch(ClipboardAction.Clip("username", it!!.username!!)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when there is no username?
|
||
this.view.passwordCopyClicks | ||
.subscribe { | ||
view.itemId?.let { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract this statement into a method, parameterized for username
and password
.
At some point, it would be good to not hit the database each time, and stash the itemViewModel
, but I don't think we need to worry about that now.
when (it) { | ||
is ClipboardAction.Clip -> { | ||
addToClipboard(it.label, it.str) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good. Consider making a CopyUsername
/ CopyPassword
objects, but this shouldn't stop you landing this at this point.
} | ||
|
||
fun addToClipboard(label: String, str: String) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace.
|
||
val clipboardManager: ClipboardManager = RuntimeEnvironment.application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager | ||
assertTrue(clipboardManager.primaryClip.getItemAt(0).text.equals(testString)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be made into a property?
RuntimeEnvironment.application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||
override fun showToastNotification(@StringRes strId: Int) { | ||
Toast.makeText(activity, getString(strId), Toast.LENGTH_SHORT).show() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
sealed class ClipboardAction : Action { | ||
data class Clip(val label: String, val str: String) : ClipboardAction() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider CopyUsername
, CopyPassword
.
The unit tests were failing on the last two commits and this merged branch now has
|
There are also 6 new linting errors (full list isn't enumerated on bitrise) |
Fixes #13
Fixes #12
Adding the username and password copy in ItemDetailFragment, also reveal / hide password