WIP 2
This commit is contained in:
parent
ef83b93fa6
commit
417e9ea322
@ -35,8 +35,9 @@ class MainActivity : ComponentActivity() {
|
|||||||
val currentToken = authRepository.getCurrentToken()
|
val currentToken = authRepository.getCurrentToken()
|
||||||
|
|
||||||
if(currentToken == null) {
|
if(currentToken == null) {
|
||||||
|
val loginIntent = Intent(this@MainActivity, LogInActivity::class.java)
|
||||||
signInActivityResult.launch(Intent(this@MainActivity, LogInActivity::class.java))
|
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
signInActivityResult.launch(loginIntent)
|
||||||
} else {
|
} else {
|
||||||
val homeActivityIntent = Intent(this@MainActivity, HomeActivity::class.java)
|
val homeActivityIntent = Intent(this@MainActivity, HomeActivity::class.java)
|
||||||
homeActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
homeActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
|||||||
@ -58,12 +58,4 @@ class LogInViewModel @Inject constructor(private val authRepository: AuthReposit
|
|||||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun signUp() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun forgotPassword() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
25
app/src/main/java/com/isolaatti/sign_up/Module.kt
Normal file
25
app/src/main/java/com/isolaatti/sign_up/Module.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package com.isolaatti.sign_up
|
||||||
|
|
||||||
|
import com.isolaatti.connectivity.RetrofitClient
|
||||||
|
import com.isolaatti.sign_up.data.SignUpApi
|
||||||
|
import com.isolaatti.sign_up.data.SignUpRepositoryImpl
|
||||||
|
import com.isolaatti.sign_up.domain.SignUpRepository
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
class Module {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideSignUpApi(retrofitClient: RetrofitClient): SignUpApi {
|
||||||
|
return retrofitClient.client.create(SignUpApi::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideSignUpRepository(signUpApi: SignUpApi): SignUpRepository {
|
||||||
|
return SignUpRepositoryImpl(signUpApi)
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/src/main/java/com/isolaatti/sign_up/data/SignUpApi.kt
Normal file
34
app/src/main/java/com/isolaatti/sign_up/data/SignUpApi.kt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package com.isolaatti.sign_up.data
|
||||||
|
|
||||||
|
import com.isolaatti.sign_up.data.dto.CodeValidationDto
|
||||||
|
import com.isolaatti.sign_up.data.dto.DataDto
|
||||||
|
import com.isolaatti.sign_up.data.dto.ResultDto
|
||||||
|
import com.isolaatti.sign_up.data.dto.SignUpWithCodeDto
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.POST
|
||||||
|
|
||||||
|
interface SignUpApi {
|
||||||
|
|
||||||
|
@POST("signUp/get_code")
|
||||||
|
fun getCode(
|
||||||
|
@Header("clientId") apiClientId: String,
|
||||||
|
@Header("clientSecret") apiSecret: String,
|
||||||
|
@Body email: DataDto
|
||||||
|
): Call<ResultDto>
|
||||||
|
|
||||||
|
@POST("signUp/validate_code")
|
||||||
|
fun validateCode(
|
||||||
|
@Header("clientId") apiClientId: String,
|
||||||
|
@Header("clientSecret") apiSecret: String,
|
||||||
|
@Body code: DataDto
|
||||||
|
): Call<CodeValidationDto>
|
||||||
|
|
||||||
|
@POST("signUp/sign_up_with_code")
|
||||||
|
fun signUpWithCode(
|
||||||
|
@Header("clientId") apiClientId: String,
|
||||||
|
@Header("clientSecret") apiSecret: String,
|
||||||
|
@Body dto: SignUpWithCodeDto
|
||||||
|
): Call<ResultDto>
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.isolaatti.sign_up.data
|
||||||
|
|
||||||
|
import com.isolaatti.BuildConfig
|
||||||
|
import com.isolaatti.sign_up.data.dto.DataDto
|
||||||
|
import com.isolaatti.sign_up.data.dto.SignUpWithCodeDto
|
||||||
|
import com.isolaatti.sign_up.domain.SignUpRepository
|
||||||
|
import com.isolaatti.sign_up.domain.entity.GetCodeResult
|
||||||
|
import com.isolaatti.sign_up.domain.entity.SignUpResult
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import retrofit2.awaitResponse
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SignUpRepositoryImpl @Inject constructor(private val signUpApi: SignUpApi): SignUpRepository {
|
||||||
|
override fun getCode(email: String): Flow<Resource<GetCodeResult>> = flow {
|
||||||
|
emit(Resource.Loading())
|
||||||
|
try {
|
||||||
|
val response = signUpApi.getCode(BuildConfig.clientId, BuildConfig.secret, DataDto(email)).awaitResponse()
|
||||||
|
if(response.isSuccessful){
|
||||||
|
response.body()?.let { emit(Resource.Success(GetCodeResult.valueOf(it.result)))}
|
||||||
|
} else {
|
||||||
|
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
|
||||||
|
}
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
emit(Resource.Error(Resource.Error.ErrorType.OtherError, "Could not map response. $e"))
|
||||||
|
} catch(_: Exception) {
|
||||||
|
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun validateCode(code: String): Flow<Resource<Boolean>> = flow {
|
||||||
|
emit(Resource.Loading())
|
||||||
|
try {
|
||||||
|
val response = signUpApi.validateCode(BuildConfig.clientId, BuildConfig.secret, DataDto(code)).awaitResponse()
|
||||||
|
if(response.isSuccessful) {
|
||||||
|
response.body()?.let { emit(Resource.Success(it.valid)) }
|
||||||
|
} else {
|
||||||
|
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun signUpWithCode(
|
||||||
|
username: String,
|
||||||
|
displayName: String,
|
||||||
|
password: String,
|
||||||
|
code: String
|
||||||
|
): Flow<Resource<SignUpResult>> = flow {
|
||||||
|
emit(Resource.Loading())
|
||||||
|
try {
|
||||||
|
val response = signUpApi.signUpWithCode(
|
||||||
|
BuildConfig.clientId,
|
||||||
|
BuildConfig.secret,
|
||||||
|
SignUpWithCodeDto(username, password, displayName, code)
|
||||||
|
).awaitResponse()
|
||||||
|
if(response.isSuccessful){
|
||||||
|
response.body()?.let { GetCodeResult.valueOf(it.result)}
|
||||||
|
} else {
|
||||||
|
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
|
||||||
|
}
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
emit(Resource.Error(Resource.Error.ErrorType.OtherError, "Could not map response. $e"))
|
||||||
|
} catch(_: Exception) {
|
||||||
|
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.isolaatti.sign_up.data.dto
|
||||||
|
|
||||||
|
data class CodeValidationDto(
|
||||||
|
val valid: Boolean
|
||||||
|
)
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.isolaatti.sign_up.data.dto
|
||||||
|
|
||||||
|
data class DataDto(
|
||||||
|
val data: String
|
||||||
|
)
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.isolaatti.sign_up.data.dto
|
||||||
|
|
||||||
|
data class ResultDto(
|
||||||
|
val result: String
|
||||||
|
)
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.isolaatti.sign_up.data.dto
|
||||||
|
|
||||||
|
data class SignUpWithCodeDto(
|
||||||
|
val username: String,
|
||||||
|
val password: String,
|
||||||
|
val displayName: String,
|
||||||
|
val code: String
|
||||||
|
)
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.isolaatti.sign_up.domain
|
||||||
|
|
||||||
|
import com.isolaatti.sign_up.domain.entity.GetCodeResult
|
||||||
|
import com.isolaatti.sign_up.domain.entity.SignUpResult
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface SignUpRepository {
|
||||||
|
fun getCode(email: String): Flow<Resource<GetCodeResult>>
|
||||||
|
fun validateCode(code: String): Flow<Resource<Boolean>>
|
||||||
|
fun signUpWithCode(username: String, displayName: String, password: String, code: String): Flow<Resource<SignUpResult>>
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.isolaatti.sign_up.domain.entity
|
||||||
|
|
||||||
|
enum class GetCodeResult {
|
||||||
|
EmailUsed, Success, EmailValidationError, CodesSentLimitReached
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.isolaatti.sign_up.domain.entity
|
||||||
|
|
||||||
|
enum class SignUpResult {
|
||||||
|
EmailNotAvailable, ValidationProblems, Ok, Error, UsernameUnavailable
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.isolaatti.sign_up.presentation
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.isolaatti.sign_up.domain.SignUpRepository
|
||||||
|
import com.isolaatti.sign_up.domain.entity.GetCodeResult
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import com.isolaatti.utils.Validators
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class GetCodeViewModel @Inject constructor(private val signUpRepository: SignUpRepository) : ViewModel() {
|
||||||
|
|
||||||
|
var email: String = ""
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
|
||||||
|
emailIsValid.value = Validators.isEmailValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val emailIsValid: MutableLiveData<Boolean> = MutableLiveData(false)
|
||||||
|
val response: MutableLiveData<Resource<GetCodeResult>?> = MutableLiveData()
|
||||||
|
|
||||||
|
fun getCode() {
|
||||||
|
if(!Validators.isEmailValid(email)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
signUpRepository.getCode(email).onEach {
|
||||||
|
response.postValue(it)
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.isolaatti.sign_up.presentation
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.isolaatti.sign_up.domain.SignUpRepository
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
|
class SignUpViewModel : ViewModel(){
|
||||||
|
var code: String? = null
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.isolaatti.sign_up.presentation
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.isolaatti.sign_up.domain.SignUpRepository
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class ValidateCodeViewModel @Inject constructor(private val signUpRepository: SignUpRepository) : ViewModel() {
|
||||||
|
var code: String? = null
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
codeIsValid.value = value?.isNotBlank() == true && value.contains(" ") == false
|
||||||
|
}
|
||||||
|
|
||||||
|
val codeIsValid: MutableLiveData<Boolean> = MutableLiveData(false)
|
||||||
|
val result: MutableLiveData<Resource<Boolean>?> = MutableLiveData()
|
||||||
|
fun validateCode() {
|
||||||
|
if(code != null && code!!.isBlank() || code!!.contains(" ")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
viewModelScope.launch {
|
||||||
|
signUpRepository.validateCode(code!!.trim()).onEach {
|
||||||
|
result.postValue(it)
|
||||||
|
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,21 +1,124 @@
|
|||||||
package com.isolaatti.sign_up.ui
|
package com.isolaatti.sign_up.ui
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.isolaatti.R
|
||||||
|
import com.isolaatti.SignUpNavigationDirections
|
||||||
|
import com.isolaatti.common.ErrorMessageViewModel
|
||||||
import com.isolaatti.databinding.FragmentGetCodeBinding
|
import com.isolaatti.databinding.FragmentGetCodeBinding
|
||||||
|
import com.isolaatti.sign_up.domain.entity.GetCodeResult
|
||||||
|
import com.isolaatti.sign_up.presentation.GetCodeViewModel
|
||||||
|
import com.isolaatti.sign_up.presentation.SignUpViewModel
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class GetCodeFragment : Fragment() {
|
class GetCodeFragment : Fragment() {
|
||||||
|
|
||||||
private lateinit var binding: FragmentGetCodeBinding
|
private lateinit var binding: FragmentGetCodeBinding
|
||||||
|
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
||||||
|
private val viewModel: GetCodeViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View {
|
||||||
binding = FragmentGetCodeBinding.inflate(inflater)
|
binding = FragmentGetCodeBinding.inflate(inflater)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
setupListeners()
|
||||||
|
setupObservers()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retry() {
|
||||||
|
// TODO retry here
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
binding.goToCodeButton.setOnClickListener {
|
||||||
|
findNavController().navigate(SignUpNavigationDirections.actionGlobalValidateCodeFragment())
|
||||||
|
}
|
||||||
|
binding.backButton.setOnClickListener {
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
binding.sendButton.setOnClickListener {
|
||||||
|
binding.sendButton.isEnabled = false
|
||||||
|
viewModel.getCode()
|
||||||
|
}
|
||||||
|
binding.textFieldEmail.editText?.doOnTextChanged { text, _, _, _ ->
|
||||||
|
viewModel.email = text.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
errorViewModel.retry.collect {
|
||||||
|
retry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.emailIsValid.observe(viewLifecycleOwner) {
|
||||||
|
binding.sendButton.isEnabled = it
|
||||||
|
}
|
||||||
|
viewModel.response.observe(viewLifecycleOwner) {
|
||||||
|
binding.sendButton.isEnabled = true
|
||||||
|
|
||||||
|
when(it) {
|
||||||
|
is Resource.Error -> {
|
||||||
|
errorViewModel.error.postValue(it.errorType)
|
||||||
|
viewModel.response.value = null
|
||||||
|
}
|
||||||
|
is Resource.Loading -> {
|
||||||
|
viewModel.response.value = null
|
||||||
|
}
|
||||||
|
is Resource.Success -> {
|
||||||
|
viewModel.response.value = null
|
||||||
|
if(it.data == GetCodeResult.Success) {
|
||||||
|
findNavController().navigate(GetCodeFragmentDirections.actionGetCodeFragmentToValidateCodeFragment())
|
||||||
|
return@observe
|
||||||
|
}
|
||||||
|
showResultDialog(it.data!!)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showResultDialog(result: GetCodeResult) {
|
||||||
|
val message = when(result) {
|
||||||
|
GetCodeResult.EmailUsed -> R.string.email_used_when_getting_code
|
||||||
|
GetCodeResult.EmailValidationError -> R.string.invalid_email
|
||||||
|
GetCodeResult.CodesSentLimitReached -> R.string.codes_sent_limit_reached
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(R.string.accept, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,22 @@
|
|||||||
package com.isolaatti.sign_up.ui
|
package com.isolaatti.sign_up.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.isolaatti.databinding.FragmentMakeAccountBinding
|
||||||
|
|
||||||
class MakeAccountFragment : Fragment() {
|
class MakeAccountFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: FragmentMakeAccountBinding
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = FragmentMakeAccountBinding.inflate(inflater)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -3,12 +3,17 @@ package com.isolaatti.sign_up.ui
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.app.ActivityCompat
|
import com.isolaatti.common.IsolaattiBaseActivity
|
||||||
import com.isolaatti.databinding.ActivitySignUpBinding
|
import com.isolaatti.databinding.ActivitySignUpBinding
|
||||||
|
import com.isolaatti.sign_up.presentation.SignUpViewModel
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
class SignUpActivity : AppCompatActivity() {
|
@AndroidEntryPoint
|
||||||
|
class SignUpActivity : IsolaattiBaseActivity() {
|
||||||
private lateinit var binding: ActivitySignUpBinding
|
private lateinit var binding: ActivitySignUpBinding
|
||||||
|
private val viewModel: SignUpViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|||||||
@ -1,6 +1,126 @@
|
|||||||
package com.isolaatti.sign_up.ui
|
package com.isolaatti.sign_up.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.isolaatti.R
|
||||||
|
import com.isolaatti.common.ErrorMessageViewModel
|
||||||
|
import com.isolaatti.databinding.FragmentValidateCodeBinding
|
||||||
|
import com.isolaatti.sign_up.presentation.SignUpViewModel
|
||||||
|
import com.isolaatti.sign_up.presentation.ValidateCodeViewModel
|
||||||
|
import com.isolaatti.utils.Resource
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class ValidateCodeFragment : Fragment() {
|
class ValidateCodeFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: FragmentValidateCodeBinding
|
||||||
|
private val activityViewModel: SignUpViewModel by activityViewModels()
|
||||||
|
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
||||||
|
private val viewModel: ValidateCodeViewModel by viewModels()
|
||||||
|
|
||||||
|
private val loadingDialog: AlertDialog by lazy {
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setMessage(R.string.loading)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = FragmentValidateCodeBinding.inflate(inflater)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
setupListeners()
|
||||||
|
setupObservers()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retry() {
|
||||||
|
// TODO retry here
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
binding.backButton.setOnClickListener {
|
||||||
|
findNavController().popBackStack()
|
||||||
|
}
|
||||||
|
binding.textFieldCode.editText?.doOnTextChanged { text, _, _, _ ->
|
||||||
|
viewModel.code = text.toString()
|
||||||
|
}
|
||||||
|
binding.acceptButton.setOnClickListener {
|
||||||
|
viewModel.validateCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
errorViewModel.retry.collect {
|
||||||
|
retry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.codeIsValid.observe(viewLifecycleOwner) {
|
||||||
|
binding.acceptButton.isEnabled = it
|
||||||
|
}
|
||||||
|
viewModel.result.observe(viewLifecycleOwner) {
|
||||||
|
when(it) {
|
||||||
|
is Resource.Error -> {
|
||||||
|
errorViewModel.error.postValue(it.errorType)
|
||||||
|
}
|
||||||
|
is Resource.Loading -> {
|
||||||
|
showLoading(true)
|
||||||
|
}
|
||||||
|
is Resource.Success -> {
|
||||||
|
showLoading(false)
|
||||||
|
if(it.data!!) {
|
||||||
|
viewModel.result.value = null
|
||||||
|
|
||||||
|
activityViewModel.code = viewModel.code
|
||||||
|
findNavController().navigate(ValidateCodeFragmentDirections.actionValidateCodeFragmentToMakeAccountFragment())
|
||||||
|
} else {
|
||||||
|
showError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showLoading(loading: Boolean) {
|
||||||
|
binding.acceptButton.isEnabled = !loading
|
||||||
|
binding.textFieldCode.isEnabled = !loading
|
||||||
|
if(loading) {
|
||||||
|
loadingDialog.show()
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showError() {
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setMessage(R.string.invalid_code)
|
||||||
|
.setPositiveButton(R.string.accept) {_,_ ->
|
||||||
|
binding.acceptButton.isEnabled = true
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@ package com.isolaatti.utils
|
|||||||
sealed class Resource<T> {
|
sealed class Resource<T> {
|
||||||
class Success<T>(val data: T?): Resource<T>()
|
class Success<T>(val data: T?): Resource<T>()
|
||||||
class Loading<T>: Resource<T>()
|
class Loading<T>: Resource<T>()
|
||||||
class Error<T>(val errorType: ErrorType? = null): Resource<T>() {
|
class Error<T>(val errorType: ErrorType? = null, val message: String? = null): Resource<T>() {
|
||||||
enum class ErrorType {
|
enum class ErrorType {
|
||||||
NetworkError, AuthError, NotFoundError, ServerError, OtherError
|
NetworkError, AuthError, NotFoundError, ServerError, OtherError
|
||||||
}
|
}
|
||||||
|
|||||||
9
app/src/main/java/com/isolaatti/utils/Validators.kt
Normal file
9
app/src/main/java/com/isolaatti/utils/Validators.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package com.isolaatti.utils
|
||||||
|
|
||||||
|
object Validators {
|
||||||
|
fun isEmailValid(email: String): Boolean {
|
||||||
|
val emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\$".toRegex()
|
||||||
|
|
||||||
|
return email.matches(emailRegex)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,10 +25,9 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="24dp"
|
android:layout_margin="24dp"
|
||||||
android:fontFamily="@font/zen_dots_regular"
|
|
||||||
android:text="@string/app_name"
|
android:text="@string/app_name"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textAppearance="?attr/textAppearanceHeadlineLarge" />
|
style="@style/toolbar_text" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@ -20,20 +20,35 @@
|
|||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:layout_marginTop="30dp"
|
android:layout_marginTop="30dp"
|
||||||
style="@style/toolbar_text"/>
|
style="@style/toolbar_text"/>
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:orientation="horizontal"
|
||||||
android:textSize="28sp"
|
android:gravity="center_vertical">
|
||||||
android:text="@string/sign_up"/>
|
<Button
|
||||||
|
android:id="@+id/backButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:icon="@drawable/baseline_arrow_back_24"
|
||||||
|
style="?attr/materialIconButtonStyle" />
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:textSize="28sp"
|
||||||
|
android:lines="2"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/sign_up"/>
|
||||||
|
</LinearLayout>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/get_code_info"
|
android:text="@string/get_code_info"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginHorizontal="16dp"/>
|
android:layout_marginHorizontal="16dp"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/goToCodeButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
@ -42,6 +57,7 @@
|
|||||||
style="@style/Widget.Material3.Button.TextButton"/>
|
style="@style/Widget.Material3.Button.TextButton"/>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/textFieldEmail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="?attr/textInputOutlinedStyle"
|
style="?attr/textInputOutlinedStyle"
|
||||||
@ -54,6 +70,7 @@
|
|||||||
android:maxLines="1" />
|
android:maxLines="1" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/sendButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
|||||||
@ -1,6 +1,118 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/brand"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
style="@style/toolbar_text"/>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:textSize="28sp"
|
||||||
|
android:lines="2"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/let_s_make_your_account"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/textUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="?attr/textInputOutlinedStyle"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:hint="@string/unique_username">
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:maxLines="1" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/textDisplayName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="?attr/textInputOutlinedStyle"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:hint="@string/display_name">
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:maxLines="1" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/create_a_password"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:layout_marginHorizontal="16dp"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="?attr/textInputOutlinedStyle"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:hint="@string/password">
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:maxLines="1" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/before_making_your_account_please_read_these_legal_terms"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"/>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/readTermsAndConditions"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/terms_and_conditions"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"/>
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/privacy_policy"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privacy_policy"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"/>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:text="Go"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@ -1,6 +1,69 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/brand"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
style="@style/toolbar_text"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<Button
|
||||||
|
android:id="@+id/backButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:icon="@drawable/baseline_arrow_back_24"
|
||||||
|
style="?attr/materialIconButtonStyle" />
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:textSize="28sp"
|
||||||
|
android:text="@string/enter_the_code_we_sent_you_by_email"/>
|
||||||
|
</LinearLayout>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/code_extended_description"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/textFieldCode"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="?attr/textInputOutlinedStyle"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:hint="@string/code">
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:maxLines="1" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/acceptButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/accept"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_gravity="center_horizontal"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@ -91,4 +91,23 @@
|
|||||||
<string name="get_code_info">The first step to create an account is to provide your email address. We will send a code that you will need to enter in the next step.</string>
|
<string name="get_code_info">The first step to create an account is to provide your email address. We will send a code that you will need to enter in the next step.</string>
|
||||||
<string name="send">Send</string>
|
<string name="send">Send</string>
|
||||||
<string name="already_have_a_code">Already have a code?</string>
|
<string name="already_have_a_code">Already have a code?</string>
|
||||||
|
<string name="code">Code</string>
|
||||||
|
<string name="code_extended_description">
|
||||||
|
Your account is almost there, you just have to enter the code that we sent to your email.
|
||||||
|
\n\n
|
||||||
|
If you can\'t see it, check your spam folder. If you still can\'t see it, wait a few minutes for the email to arrive.
|
||||||
|
</string>
|
||||||
|
<string name="enter_the_code_we_sent_you_by_email">Enter the code we sent you by email</string>
|
||||||
|
<string name="email_used_when_getting_code">The email address you want to use to create this account has already been used previously.</string>
|
||||||
|
<string name="invalid_code">The code you entered is invalid. Some reasons may be that the code is misspelled or it has already expired.</string>
|
||||||
|
<string name="invalid_email">Email is invalid</string>
|
||||||
|
<string name="codes_sent_limit_reached">It is not possible to send more codes, you have reached the limit. Contact the administrator.</string>
|
||||||
|
<string name="loading">Loading...</string>
|
||||||
|
<string name="unique_username">Unique username</string>
|
||||||
|
<string name="display_name">Display name</string>
|
||||||
|
<string name="create_a_password">Create a fairly password</string>
|
||||||
|
<string name="let_s_make_your_account">Let\'s make your account</string>
|
||||||
|
<string name="before_making_your_account_please_read_these_legal_terms">Before making your account, please read and accept these legal terms.</string>
|
||||||
|
<string name="terms_and_conditions">Terms and conditions</string>
|
||||||
|
<string name="privacy_policy">Privacy policy</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
x
Reference in New Issue
Block a user