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 @@ -130,6 +130,7 @@ data class AppSpacing(
@Immutable
data class AppPadding(
val none: Dp = 0.dp,
val tiny:Dp=2.dp,
val extraSmall: Dp = 4.dp,
val small: Dp = 8.dp,
val medium: Dp = 12.dp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,6 @@ data class Client(
val gender: Gender? = null,

val groups: List<Group> = emptyList(),

val emailAddress: String? = null,
) : Parcelable
1 change: 1 addition & 0 deletions core/ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ kotlin{
implementation(libs.jb.composeNavigation)
implementation(libs.filekit.compose)
implementation(libs.filekit.core)
implementation(libs.filekit.coil)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2025 Mobile Byte Sensei
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/mobilebytesensei/financiera-bienestar/blob/dev/LICENSE
*/
package org.mifos.mobile.core.ui.utils

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import coil3.ImageLoader
import coil3.PlatformContext
import coil3.memory.MemoryCache
import coil3.request.ImageRequest
import coil3.util.DebugLogger
import io.github.vinceglb.filekit.coil.addPlatformFileSupport

internal val LocalAppImageLoader = compositionLocalOf<ImageLoader?> { null }

@Composable
fun rememberImageLoader(context: PlatformContext): ImageLoader {
return LocalAppImageLoader.current ?: rememberDefaultImageLoader(context)
}

@Composable
internal fun rememberDefaultImageLoader(context: PlatformContext): ImageLoader {
return remember(context) {
ImageLoader.Builder(context)
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(context, 0.25)
.build()
}
.components {
addPlatformFileSupport()
}
.logger(DebugLogger())
.build()
}
}
8 changes: 8 additions & 0 deletions feature/settings/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ kotlin {
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(projects.core.datastore)

implementation(libs.coil.kt)
implementation(libs.coil.kt.compose)
implementation(libs.coil.network.ktor)

implementation(libs.filekit.core)
implementation(libs.filekit.compose)
implementation(libs.filekit.dialog.compose)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,71 @@
<!-- Change Language -->
<string name="feature_settings_language">Language</string>
<string name="feature_settings_change_language">Change Language</string>

<!-- Profile Screen -->
<!-- Screen titles and navigation -->
<string name="feature_settings_profile_topbar_title">Profile</string>

<!-- Profile Form Validation errors -->
<string name="profile_name_empty_error">Name cannot be empty</string>
<string name="profile_name_too_short_error">Name must be at least 2 characters long</string>
<string name="profile_name_too_long_error">Name cannot exceed 50 characters</string>
<string name="profile_name_invalid_format_error">Name can only contain letters, spaces, hyphens, and apostrophes</string>

<string name="profile_email_empty_error">Email address cannot be empty</string>
<string name="profile_email_invalid_format_error">Please enter a valid email address</string>

<string name="profile_mobile_empty_error">Phone number cannot be empty</string>
<string name="profile_mobile_too_short_error">Phone number is too short (minimum 9 digits)</string>
<string name="profile_mobile_too_long_error">Phone number is too long (maximum 13 characters)</string>
<string name="profile_mobile_invalid_format_error">Please enter a valid Spanish phone number</string>

<!-- API result messages -->
<string name="profile_load_failed">Failed to load profile information. Please try again.</string>
<string name="profile_update_success">Profile updated successfully!</string>
<string name="profile_update_failed">Failed to update profile. Please try again.</string>
<string name="profile_too_many_attempts">Too many failed attempts. Please try again later.</string>

<!-- Image update messages -->
<string name="profile_image_update_success">Profile picture updated successfully!</string>
<string name="profile_image_update_failed">Failed to update profile picture. Please try again.</string>
<string name="profile_image_delete_failed">Failed to delete profile picture. Please try again.</string>

<!-- Dialog messages -->
<string name="profile_update_success_message">Your profile has been updated with the latest information.</string>
<string name="profile_update_dialog_button">Continue</string>
<string name="profile_updating_message">Updating your profile...</string>

<!-- Error dialog -->
<string name="profile_error_dialog_title">Update Failed</string>
<string name="profile_error_dialog_retry">Retry</string>
<string name="profile_error_dialog_cancel">Cancel</string>

<!-- Unsaved changes dialog -->
<string name="profile_unsaved_changes_title">Unsaved Changes</string>
<string name="profile_unsaved_changes_message">You have unsaved changes. Do you want to discard them and leave?</string>
<string name="profile_unsaved_changes_discard">Discard</string>
<string name="profile_unsaved_changes_stay">Keep Editing</string>

<!-- Loading states -->
<string name="profile_loading_message">Loading profile...</string>

<!-- Additional error messages -->
<string name="feature_settings_profile_error_empty_name">Name cannot be empty</string>
<string name="feature_settings_profile_error_invalid_email">Please enter a valid email address</string>
<string name="feature_settings_profile_error_empty_mobile">Phone number cannot be empty</string>

<!-- Profile image section -->
<string name="feature_settings_profile_update_photo">Update Photo</string>
<string name="feature_settings_profile_delete_photo">Delete Photo</string>
<string name="feature_settings_profile_content_description_profile_icon">Profile picture</string>

<!-- Submit button -->
<string name="feature_settings_profile_submit_changes">Save Changes</string>

<!-- Form labels -->
<string name="feature_settings_profile_label_full_name">Full Name</string>
<string name="feature_settings_profile_label_email">Email Address</string>
<string name="feature_settings_profile_label_customer_account">Customer Account</string>
<string name="feature_settings_profile_label_phone_number">Phone Number</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,14 @@ sealed class SettingsItems(
route = Constants.LANGUAGE,
)

@Serializable
data object Theme : SettingsItems(
title = Res.string.feature_settings_action_theme,
subTitle = Res.string.feature_settings_action_theme_tip,
icon = MifosIcons.DarkTheme,
route = Constants.THEME,
)
//TODO: Uncomment once we get valid dark theme colours by ui/ux theme
// @Serializable
// data object Theme : SettingsItems(
// title = Res.string.feature_settings_action_theme,
// subTitle = Res.string.feature_settings_action_theme_tip,
// icon = MifosIcons.DarkTheme,
// route = Constants.THEME,
// )

@Serializable
data object Endpoint : SettingsItems(
Expand Down Expand Up @@ -142,7 +143,7 @@ internal val settingsItems: ImmutableList<SettingsItems> = persistentListOf(
SettingsItems.Password,
SettingsItems.AuthPasscode,
SettingsItems.Language,
SettingsItems.Theme,
// SettingsItems.Theme,
SettingsItems.Endpoint,
SettingsItems.AboutUs,
SettingsItems.FAQ,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import org.mifos.mobile.feature.settings.faq.FaqViewModel
import org.mifos.mobile.feature.settings.language.LanguageViewModel
import org.mifos.mobile.feature.settings.passcode.UpdatePasscodeViewModel
import org.mifos.mobile.feature.settings.password.ChangePasswordViewModel
import org.mifos.mobile.feature.settings.profile.UpdateProfileViewModel
import org.mifos.mobile.feature.settings.settings.SettingsViewModel

val SettingsModule = module {
Expand All @@ -24,4 +25,5 @@ val SettingsModule = module {
viewModelOf(::UpdatePasscodeViewModel)
viewModelOf(::FaqViewModel)
viewModelOf(::LanguageViewModel)
viewModelOf(::UpdateProfileViewModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.mifos.mobile.feature.settings.help.helpDestination
import org.mifos.mobile.feature.settings.language.languageDestination
import org.mifos.mobile.feature.settings.passcode.updatePasscodeDestination
import org.mifos.mobile.feature.settings.password.changePasswordDestination
import org.mifos.mobile.feature.settings.profile.profileDestination
import org.mifos.mobile.feature.settings.settings.SettingsRoute
import org.mifos.mobile.feature.settings.settings.settingsDestination

Expand Down Expand Up @@ -66,6 +67,9 @@ fun NavGraphBuilder.settingsGraph(
changePasswordDestination(
onBackClick = navController::popBackStack,
)
profileDestination(
onBackClick = navController::popBackStack
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.mifos.mobile.feature.settings.profile

import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import org.mifos.mobile.core.ui.composableWithPushTransitions
import org.mifos.mobile.feature.settings.componenets.SettingsItems

internal fun NavController.navigateToProfile(navOptions: NavOptions? = null) =
navigate(SettingsItems.Profile, navOptions)

internal fun NavGraphBuilder.profileDestination(
onBackClick: () -> Unit,
) {
composableWithPushTransitions<SettingsItems.Profile> {
UpdateProfileScreen(
navigateBack = onBackClick,
)
}
}
Loading
Loading