Skip to content

Commit

Permalink
feat(App link): Handle intent for reset password and add unit test(#2079
Browse files Browse the repository at this point in the history
)
  • Loading branch information
liveHarshit committed Jul 11, 2019
1 parent 2219775 commit d27be8c
Show file tree
Hide file tree
Showing 20 changed files with 332 additions and 54 deletions.
1 change: 0 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ dependencies {


testImplementation 'junit:junit:4.12'
testImplementation "io.mockk:mockk:1.9.3"
testImplementation 'org.threeten:threetenbp:1.4.0'
testImplementation "org.koin:koin-test:$koin_version"
testImplementation 'androidx.arch.core:core-testing:2.0.1'
Expand Down
23 changes: 3 additions & 20 deletions app/src/main/java/org/fossasia/openevent/general/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@ import org.fossasia.openevent.general.auth.RC_CREDENTIALS_READ
import org.fossasia.openevent.general.auth.SmartAuthViewModel
import org.fossasia.openevent.general.auth.SmartAuthUtil
import org.fossasia.openevent.general.auth.AuthFragment
import org.fossasia.openevent.general.utils.AppLinkUtils
import org.fossasia.openevent.general.utils.Utils.navAnimGone
import org.fossasia.openevent.general.utils.Utils.navAnimVisible
import org.jetbrains.anko.design.snackbar
import org.koin.androidx.viewmodel.ext.android.viewModel

const val PLAY_STORE_BUILD_FLAVOR = "playStore"
const val EVENT_IDENTIFIER = "eventIdentifier"
const val VERIFICATION_TOKEN = "verificationToken"
private const val VERIFY = "verify"
private const val TOKEN = "token"

class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
Expand All @@ -43,26 +40,12 @@ class MainActivity : AppCompatActivity() {
currentFragmentId = destination.id
handleNavigationVisibility(currentFragmentId)
}
handleAppLinkIntent(intent)
AppLinkUtils.handleIntent(intent, navController)
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
handleAppLinkIntent(intent)
}

private fun handleAppLinkIntent(intent: Intent?) {
val appLinkData = intent?.data
if (appLinkData != null) {
val bundle = Bundle()
if (appLinkData.lastPathSegment == VERIFY) {
bundle.putString(VERIFICATION_TOKEN, appLinkData.getQueryParameter(TOKEN))
navController.navigate(R.id.profileFragment, bundle)
} else {
bundle.putString(EVENT_IDENTIFIER, appLinkData.lastPathSegment)
navController.navigate(R.id.eventDetailsFragment, bundle)
}
}
AppLinkUtils.handleIntent(intent, navController)
}

private fun setupBottomNavigationMenu(navController: NavController) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ interface AuthApi {

@POST("auth/verify-email")
fun verifyEmail(@Body requestEmailVerification: RequestEmailVerification): Single<EmailVerificationResponse>

@PATCH("auth/reset-password")
fun resetPassword(@Body requestPasswordReset: RequestPasswordReset): Single<ResetPasswordResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ class AuthFragment : Fragment(), ComplexBackPressFragment {
val snackbarMessage = safeArgs.snackbarMessage
if (!snackbarMessage.isNullOrEmpty()) rootView.snackbar(snackbarMessage)

val email = safeArgs.email
if (email != null) {
rootView.email.setText(email)
}

rootView.skipTextView.isVisible = safeArgs.showSkipButton
rootView.skipTextView.setOnClickListener {
findNavController(rootView).navigate(
Expand All @@ -83,7 +88,6 @@ class AuthFragment : Fragment(), ComplexBackPressFragment {
authViewModel.checkUser(rootView.email.text.toString())
}

rootView.email.setText(safeArgs.email)
rootView.email.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { /*Do Nothing*/ }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { /*Do Nothing*/ }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,8 @@ class AuthService(
fun verifyEmail(token: String): Single<EmailVerificationResponse> {
return authApi.verifyEmail(RequestEmailVerification(Token(token)))
}

fun resetPassword(requestPasswordReset: RequestPasswordReset): Single<ResetPasswordResponse> {
return authApi.resetPassword(requestPasswordReset)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import org.fossasia.openevent.general.CircleTransform
import org.fossasia.openevent.general.PLAY_STORE_BUILD_FLAVOR
import org.fossasia.openevent.general.R
import org.fossasia.openevent.general.BottomIconDoubleClick
import org.fossasia.openevent.general.VERIFICATION_TOKEN
import org.fossasia.openevent.general.utils.VERIFICATION_TOKEN
import org.fossasia.openevent.general.utils.Utils
import org.fossasia.openevent.general.utils.Utils.requireDrawable
import org.fossasia.openevent.general.utils.extensions.nonNull
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.fossasia.openevent.general.auth

import org.fossasia.openevent.general.auth.forgot.PasswordReset

class RequestPasswordReset(
val data: PasswordReset
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.fossasia.openevent.general.auth

import com.github.jasminb.jsonapi.LongIdHandler
import com.github.jasminb.jsonapi.annotations.Id

class ResetPasswordResponse(
@Id(LongIdHandler::class)
val id: Long? = null,
val email: String? = null,
val name: String? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.fossasia.openevent.general.auth.forgot

class PasswordReset(
val token: String,
val password: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ val apiModule = module {

val viewModelModule = module {
viewModel { LoginViewModel(get(), get(), get()) }
viewModel { EventsViewModel(get(), get(), get(), get(), get(), get(), get()) }
viewModel { EventsViewModel(get(), get(), get(), get(), get(), get(), get(), get()) }
viewModel { ProfileViewModel(get(), get()) }
viewModel { SignUpViewModel(get(), get(), get()) }
viewModel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import kotlinx.android.synthetic.main.content_fetching_event_error.view.retry
import kotlinx.android.synthetic.main.dialog_feedback.view.feedback
import kotlinx.android.synthetic.main.dialog_feedback.view.feedbackTextInputLayout
import kotlinx.android.synthetic.main.dialog_feedback.view.feedbackrating
import org.fossasia.openevent.general.EVENT_IDENTIFIER
import org.fossasia.openevent.general.utils.EVENT_IDENTIFIER
import org.fossasia.openevent.general.R
import org.fossasia.openevent.general.common.SessionClickListener
import org.fossasia.openevent.general.common.SpeakerClickListener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package org.fossasia.openevent.general.event

import android.graphics.Color
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
Expand All @@ -15,6 +18,10 @@ import androidx.navigation.Navigation.findNavController
import androidx.navigation.fragment.FragmentNavigatorExtras
import kotlinx.android.synthetic.main.content_no_internet.view.noInternetCard
import kotlinx.android.synthetic.main.content_no_internet.view.retry
import kotlinx.android.synthetic.main.dialog_reset_password.view.confirmNewPassword
import kotlinx.android.synthetic.main.dialog_reset_password.view.newPassword
import kotlinx.android.synthetic.main.dialog_reset_password.view.textInputLayoutConfirmNewPassword
import kotlinx.android.synthetic.main.dialog_reset_password.view.textInputLayoutNewPassword
import kotlinx.android.synthetic.main.fragment_events.view.eventsRecycler
import kotlinx.android.synthetic.main.fragment_events.view.locationTextView
import kotlinx.android.synthetic.main.fragment_events.view.shimmerEvents
Expand All @@ -30,20 +37,24 @@ import kotlinx.android.synthetic.main.fragment_events.view.newNotificationDotToo
import kotlinx.android.synthetic.main.fragment_events.view.notificationToolbar
import org.fossasia.openevent.general.R
import org.fossasia.openevent.general.BottomIconDoubleClick
import org.fossasia.openevent.general.utils.RESET_PASSWORD_TOKEN
import org.fossasia.openevent.general.common.EventClickListener
import org.fossasia.openevent.general.common.FavoriteFabClickListener
import org.fossasia.openevent.general.data.Preference
import org.fossasia.openevent.general.search.location.SAVED_LOCATION
import org.fossasia.openevent.general.utils.extensions.nonNull
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.fossasia.openevent.general.utils.Utils.setToolbar
import org.fossasia.openevent.general.utils.Utils.progressDialog
import org.fossasia.openevent.general.utils.Utils.show
import org.fossasia.openevent.general.utils.extensions.setPostponeSharedElementTransition
import org.fossasia.openevent.general.utils.extensions.setStartPostponedEnterTransition
import org.fossasia.openevent.general.utils.extensions.hideWithFading
import org.fossasia.openevent.general.utils.extensions.showWithFading
import org.jetbrains.anko.design.longSnackbar

const val BEEN_TO_WELCOME_SCREEN = "beenToWelcomeScreen"
private const val EVENTS_FRAGMENT = "eventsFragment"

class EventsFragment : Fragment(), BottomIconDoubleClick {
private val eventsViewModel by viewModel<EventsViewModel>()
Expand All @@ -65,6 +76,26 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
}
setToolbar(activity, show = false)

val progressDialog = progressDialog(context, getString(R.string.loading_message))

val token = arguments?.getString(RESET_PASSWORD_TOKEN)
if (token != null)
showResetPasswordAlertDialog(token)

eventsViewModel.resetPasswordEmail
.nonNull()
.observe(viewLifecycleOwner, Observer {
findNavController(rootView).navigate(
EventsFragmentDirections.actionEventsToAuth(email = it, redirectedFrom = EVENTS_FRAGMENT)
)
})

eventsViewModel.dialogProgress
.nonNull()
.observe(viewLifecycleOwner, Observer {
progressDialog.show(it)
})

rootView.eventsRecycler.layoutManager =
GridLayoutManager(activity, resources.getInteger(R.integer.events_column_count))

Expand Down Expand Up @@ -101,7 +132,7 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
rootView.shimmerEvents.isVisible = it
})

eventsViewModel.error
eventsViewModel.message
.nonNull()
.observe(viewLifecycleOwner, Observer {
rootView.longSnackbar(it)
Expand Down Expand Up @@ -255,5 +286,86 @@ class EventsFragment : Fragment(), BottomIconDoubleClick {
rootView.eventsEmptyView.isVisible = show
}

private fun showResetPasswordAlertDialog(token: String) {
val layout = layoutInflater.inflate(R.layout.dialog_reset_password, null)

val alertDialog = AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.title_change_password))
.setView(layout)
.setPositiveButton(getString(R.string.change)) { _, _ ->
eventsViewModel.checkAndReset(token, layout.newPassword.text.toString())
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.cancel()
}
.setCancelable(false)
.show()
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false

layout.newPassword.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) {

/* to make PasswordToggle visible again, if made invisible
after empty field error
*/
if (!layout.textInputLayoutNewPassword.isEndIconVisible) {
layout.textInputLayoutNewPassword.isEndIconVisible = true
}

if (layout.newPassword.text.toString().length >= 8) {
layout.textInputLayoutNewPassword.error = null
layout.textInputLayoutNewPassword.isErrorEnabled = false
} else {
layout.textInputLayoutNewPassword.error = getString(R.string.invalid_password_message)
}
if (layout.confirmNewPassword.text.toString() == layout.newPassword.text.toString()) {
layout.textInputLayoutConfirmNewPassword.error = null
layout.textInputLayoutConfirmNewPassword.isErrorEnabled = false
} else {
layout.textInputLayoutConfirmNewPassword.error =
getString(R.string.invalid_confirm_password_message)
}
when (layout.textInputLayoutConfirmNewPassword.isErrorEnabled ||
layout.textInputLayoutNewPassword.isErrorEnabled) {
true -> alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
false -> alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
}
}

override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { /*Implement here*/ }

override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { /*Implement here*/ }
})

layout.confirmNewPassword.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) {

/* to make PasswordToggle visible again, if made invisible
after empty field error
*/
if (!layout.textInputLayoutConfirmNewPassword.isEndIconVisible) {
layout.textInputLayoutConfirmNewPassword.isEndIconVisible = true
}

if (layout.confirmNewPassword.text.toString() == layout.newPassword.text.toString()) {
layout.textInputLayoutConfirmNewPassword.error = null
layout.textInputLayoutConfirmNewPassword.isErrorEnabled = false
} else {
layout.textInputLayoutConfirmNewPassword.error =
getString(R.string.invalid_confirm_password_message)
}
when (layout.textInputLayoutConfirmNewPassword.isErrorEnabled ||
layout.textInputLayoutNewPassword.isErrorEnabled) {
true -> alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
false -> alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
}
}

override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { /*Implement here*/ }

override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { /*Implement here*/ }
})
}

override fun doubleClick() = rootView.scrollView.smoothScrollTo(0, 0)
}
Loading

0 comments on commit d27be8c

Please sign in to comment.