Skip to content

Commit

Permalink
Merge pull request #303 from PermanentOrg/feature/VSP-1447
Browse files Browse the repository at this point in the history
Feature/vsp 1447
  • Loading branch information
flaviahandrea-vsp authored Oct 2, 2024
2 parents 5d840fa + d1e3c24 commit b42ebbf
Show file tree
Hide file tree
Showing 17 changed files with 723 additions and 193 deletions.
3 changes: 0 additions & 3 deletions app/src/main/java/org/permanent/permanent/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class Constants {
const val MEDIA_TYPE_OCTET_STREAM = "application/octet-stream"
const val AUTH_TYPE_MFA_VALIDATION = "type.auth.mfaValidation"
const val AUTH_TYPE_PHONE = "type.auth.phone"
const val AUTH_REQUEST_SCOPE = "offline_access"
const val ERROR_MFA_TOKEN = "warning.auth.mfaToken"
const val ERROR_INVALID_VERIFICATION_CODE = "warning.auth.token_does_not_match"
const val ERROR_EXPIRED_VERIFICATION_CODE = "warning.auth.token_expired"
Expand All @@ -40,8 +39,6 @@ class Constants {
const val ERROR_PASSWORD_NO_MATCH = "warning.registration.password_match"
const val ERROR_PASSWORD_OLD_INCORRECT = "warning.auth.bad_old_password"
const val SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED"
const val FILE_DELETED_SUCCESSFULLY = "Record(s) have been deleted."
const val FOLDER_DELETED_SUCCESSFULLY = "Folder has been deleted."
// This is also used in manifest
const val FILE_PROVIDER_NAME = ".fileprovider"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,8 @@ class NetworkClient(private var okHttpClient: OkHttpClient?, context: Context) {

fun addRemoveTags(tags: Tags): Call<ResponseVO> = stelaAccountService.addRemoveTags(tags)

// fun getTwoFAMethod(): Call<ResponseVO> = stelaAccountService.getTwoFAMethod()

fun getPaymentIntent(
accountId: Int,
accountEmail: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ interface StelaAccountService {

@PUT("api/v2/account/tags")
fun addRemoveTags(@Body tags: Tags): Call<ResponseVO>

// @GET("api/v2/idpuser")
// fun getTwoFAMethod(): Call<ResponseVO>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ import org.permanent.permanent.network.IResponseListener
interface StelaAccountRepository {

fun addRemoveTags(tags: Tags, listener: IResponseListener)

// fun getTwoFAMethod(listener: IResponseListener)
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,30 @@ class StelaAccountRepositoryImpl(context: Context) : StelaAccountRepository {
}
})
}

// override fun getTwoFAMethod(listener: IResponseListener) {
// NetworkClient.instance().getTwoFAMethod().enqueue(object : Callback<ResponseVO> {
//
// override fun onResponse(call: Call<ResponseVO>, response: Response<ResponseVO>) {
// if (response.isSuccessful) {
// val responseBody = response.body()
// if (responseBody != null) {
// listener.onSuccess("")
// } else {
// listener.onFailed(appContext.getString(R.string.generic_error))
// }
// } else {
// try {
// listener.onFailed(response.errorBody().toString())
// } catch (e: Exception) {
// listener.onFailed(e.message)
// }
// }
// }
//
// override fun onFailure(call: Call<ResponseVO>, t: Throwable) {
// listener.onFailed(t.message)
// }
// })
// }
}
Original file line number Diff line number Diff line change
@@ -1,69 +1,128 @@
package org.permanent.permanent.ui.composeComponents

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import org.permanent.permanent.R

@Composable
fun CustomSnackbar(
message: String, buttonText: String, onButtonClick: () -> Unit, modifier: Modifier = Modifier
modifier: Modifier = Modifier,
isForError: Boolean = true,
message: String,
buttonText: String,
onButtonClick: () -> Unit
) {
Box(
modifier = modifier
.fillMaxWidth()
.background(
color = colorResource(id = R.color.errorLight),
shape = RoundedCornerShape(size = 12.dp)
)
.padding(24.dp), contentAlignment = Alignment.Center
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxWidth()
var visible by remember { mutableStateOf(false) }

// LaunchedEffect ensures animations happen sequentially when the message changes
LaunchedEffect(message) {
if (message.isNotEmpty()) {
visible = false // Start by hiding the old Snackbar
delay(300) // Wait for exit animation to complete
visible = true // Then show the new Snackbar
} else visible = false
}

AnimatedVisibility(visible = visible,
enter = slideInVertically(initialOffsetY = { fullHeight -> fullHeight } // Slide in from bottom
) + fadeIn(), // Fade in as well
exit = slideOutVertically(targetOffsetY = { fullHeight -> fullHeight } // Slide out to bottom
) + fadeOut(), // Fade out as well
modifier = modifier) {
Box(
modifier = modifier
.fillMaxWidth()
.background(
color = colorResource(id = if (isForError) R.color.errorLight else R.color.successLight),
shape = RoundedCornerShape(size = 12.dp)
), contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = R.drawable.ic_error_cercle),
contentDescription = "error",
modifier = Modifier.size(16.dp)
)
Row(
verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = if (isForError) R.drawable.ic_error_cercle else R.drawable.ic_done_white),
contentDescription = "error",
colorFilter = ColorFilter.tint(
if (isForError) colorResource(id = R.color.error500) else colorResource(
id = R.color.successDark
)
),
modifier = Modifier
.padding(start = 24.dp)
.size(16.dp)
)

Text(
text = message,
color = colorResource(id = R.color.error500),
modifier = Modifier.weight(1f),
fontFamily = FontFamily(Font(R.font.open_sans_regular_ttf)),
fontSize = 14.sp,
lineHeight = 24.sp
)
Spacer(modifier = Modifier.width(8.dp))

TextButton(onClick = onButtonClick) {
Text(
text = buttonText,
color = colorResource(id = R.color.blue900),
fontFamily = FontFamily(Font(R.font.open_sans_semibold_ttf)),
text = message,
color = if (isForError) colorResource(id = R.color.error500) else colorResource(
id = R.color.successDark
),
modifier = Modifier.weight(1f),
fontFamily = FontFamily(Font(R.font.open_sans_regular_ttf)),
fontSize = 14.sp,
lineHeight = 24.sp
)

if (isForError) {
Box(modifier = Modifier
.clickable { onButtonClick() }
.padding(top = 24.dp, bottom = 24.dp, end = 24.dp, start = 8.dp)) {
Text(
text = buttonText,
color = colorResource(id = R.color.blue900),
fontFamily = FontFamily(Font(R.font.open_sans_semibold_ttf)),
fontSize = 14.sp,
lineHeight = 24.sp
)
}
} else {
Box(modifier = Modifier
.clickable { onButtonClick() }
.padding(top = 24.dp, bottom = 24.dp, end = 24.dp, start = 8.dp),
contentAlignment = Alignment.Center) {
Image(
painter = painterResource(id = R.drawable.ic_close_white),
contentDescription = "Close",
colorFilter = ColorFilter.tint(colorResource(id = R.color.blue200)),
modifier = Modifier.size(18.dp)
)
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.permanent.permanent.ui.composeComponents

import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
import org.permanent.permanent.R

@Composable
fun DigitTextField(
value: String,
onValueChange: (String) -> Unit,
focusRequester: FocusRequester,
previousFocusRequester: FocusRequester?, // Add previous focus requester for backspace handling
nextFocusRequester: FocusRequester?, // Keep next focus requester to move forward
modifier: Modifier = Modifier
) {
TextField(
value = value,
onValueChange = { newValue ->
// Only allow numeric input and overwrite current value
if (newValue.length == 1 && newValue.all { it.isDigit() }) {
onValueChange(newValue)

// Move to the next text field if not null
nextFocusRequester?.requestFocus()
} else if (newValue.isEmpty()) {
onValueChange("") // Handle deletion (clear value)
}
},
modifier = modifier
.focusRequester(focusRequester)
.onKeyEvent { keyEvent ->
if (keyEvent.key == Key.Backspace && keyEvent.type == KeyEventType.KeyUp) {
// Handle backspace: clear the current field and move to the previous one
onValueChange("") // Clear current field
previousFocusRequester?.requestFocus() // Move to the previous field
true // Consume the event
} else {
false // Let other events be handled normally
}
},
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = if (nextFocusRequester == null) ImeAction.Done else ImeAction.Next
),
textStyle = TextStyle(
fontSize = 24.sp,
lineHeight = 32.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight(400),
),
colors = TextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedContainerColor = colorResource(id = R.color.whiteUltraTransparent),
unfocusedContainerColor = colorResource(id = R.color.whiteUltraTransparent),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
cursorColor = colorResource(id = R.color.blue400),
),
maxLines = 1
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ import org.permanent.permanent.ui.PreferencesHelper
import org.permanent.permanent.ui.activities.MainActivity
import org.permanent.permanent.ui.archiveOnboarding.ArchiveOnboardingActivity
import org.permanent.permanent.ui.login.compose.AuthenticationContainer
import org.permanent.permanent.viewmodels.LoginFragmentViewModel
import org.permanent.permanent.viewmodels.AuthenticationViewModel

class AuthenticationFragment : PermanentBaseFragment() {
private lateinit var viewModel: LoginFragmentViewModel
private lateinit var viewModel: AuthenticationViewModel
private lateinit var prefsHelper: PreferencesHelper

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
viewModel = ViewModelProvider(this)[LoginFragmentViewModel::class.java]
viewModel = ViewModelProvider(this)[AuthenticationViewModel::class.java]

prefsHelper = PreferencesHelper(
requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
Expand All @@ -44,15 +45,25 @@ import org.permanent.permanent.R
import org.permanent.permanent.ui.composeComponents.ButtonColor
import org.permanent.permanent.ui.composeComponents.CircularProgressIndicator
import org.permanent.permanent.ui.composeComponents.CustomTextButton
import org.permanent.permanent.viewmodels.LoginFragmentViewModel
import org.permanent.permanent.viewmodels.AuthenticationViewModel

@Composable
fun AuthenticationContainer(
viewModel: LoginFragmentViewModel
viewModel: AuthenticationViewModel
) {
val pagerState = rememberPagerState(
initialPage = AuthPage.SIGN_IN.value,
pageCount = { AuthPage.values().size })

val navigateToPage by viewModel.navigateToPage.collectAsState()

LaunchedEffect(navigateToPage) {
navigateToPage?.let { page ->
pagerState.animateScrollToPage(page.value)
viewModel.clearPageNavigation()
}
}

val isTablet = viewModel.isTablet()

val isBusyState by viewModel.isBusyState.collectAsState()
Expand Down Expand Up @@ -96,11 +107,9 @@ fun AuthenticationContainer(
}

AuthPage.CODE_VERIFICATION.value -> {
// CodeVerificationPage(
// viewModel = viewModel,
// isTablet = isTablet,
// pagerState = pagerState
// )
CodeVerificationPage(
viewModel = viewModel
)
}

AuthPage.SIGN_UP.value -> {
Expand Down Expand Up @@ -139,7 +148,7 @@ private fun LeftSideView(

Box(
modifier = Modifier
.width(2 * oneThirdOfScreenDp + horizontalPaddingDp)
.width(2 * oneThirdOfScreenDp)
.fillMaxHeight()
) {
Image(
Expand Down
Loading

0 comments on commit b42ebbf

Please sign in to comment.