Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
7 changes: 7 additions & 0 deletions .run/mifospay-android.run.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="mifospay-android" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
<module name="mobile-wallet.mifospay-android" />
<option name="ANDROID_RUN_CONFIGURATION_SCHEMA_VERSION" value="1" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
<option name="DEPLOY_AS_INSTANT" value="false" />
<option name="ARTIFACT_NAME" value="" />
<option name="PM_INSTALL_OPTIONS" value="" />
<option name="ALL_USERS" value="false" />
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
<option name="ALLOW_ASSUME_VERIFIED" value="false" />
<option name="CLEAR_APP_STORAGE" value="false" />
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" />
<option name="RESTORE_ENABLED" value="false" />
<option name="RESTORE_FILE" value="" />
<option name="RESTORE_FRESH_INSTALL_ONLY" value="false" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
Expand Down Expand Up @@ -57,6 +63,7 @@
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY" value="" />
<option name="ACTIVITY_CLASS" value="" />
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
Expand Down
2 changes: 1 addition & 1 deletion .run/mifospay-ios.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="mifospay-ios" type="KmmRunConfiguration" factoryName="iOS Application" CONFIG_VERSION="1" XCODE_PROJECT="$PROJECT_DIR$/mifospay-ios/iosApp.xcodeproj">
<configuration default="false" name="mifospay-ios" type="KmmRunConfiguration" factoryName="iOS Application" CONFIG_VERSION="1" XCODE_PROJECT="$PROJECT_DIR$/mifospay-ios/iosApp.xcodeproj" XCODE_CONFIGURATION="Debug" XCODE_SCHEME="iosApp">
<method v="2">
<option name="com.jetbrains.kmm.ios.BuildIOSAppTask" enabled="true" />
</method>
Expand Down
6 changes: 6 additions & 0 deletions build-logic/convention/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
`kotlin-dsl`
alias(libs.plugins.dokka)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

group = "org.mifospay.buildlogic"
Expand Down Expand Up @@ -29,6 +30,7 @@ dependencies {
compileOnly(libs.ktlint.gradlePlugin)
compileOnly(libs.spotless.gradle)
implementation(libs.truth)
implementation(libs.dokka.gradle.plugin)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use compileOnly

}

tasks {
Expand Down Expand Up @@ -91,5 +93,9 @@ gradlePlugin {
implementationClass = "MifosGitHooksConventionPlugin"
description = "Installs git hooks for the project"
}
register("featureLibrary") {
Copy link
Collaborator

@niyajali niyajali Apr 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this plugin we no need such plugin for dokka

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

id = "mifospay.feature.library"
implementationClass = "FeatureLibraryPlugin"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class CMPFeatureConventionPlugin : Plugin<Project> {
apply("mifospay.kmp.koin")
apply("org.jetbrains.kotlin.plugin.compose")
apply("org.jetbrains.compose")
apply("org.jetbrains.dokka")
apply(KMPLibraryPlugin::class.java)
Copy link
Collaborator

@niyajali niyajali Apr 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this plugin apply(KMPLibraryPlugin::class.java)

}

dependencies {
Expand Down
19 changes: 19 additions & 0 deletions build-logic/convention/src/main/kotlin/FeatureLibraryPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.dokka.gradle.DokkaTask

class FeatureLibraryPlugin : Plugin<Project> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create an extension function instead of a class if required, something like this. and as I can see by applying the plugin on every core & feature module is sufficient to generate dokka docs.

import org.gradle.api.Project
import org.jetbrains.dokka.gradle.DokkaTask
import java.net.URI

/**
 * Configures Dokka documentation settings for a feature module.
 * This extension function replaces the FeatureLibraryPlugin class by directly
 * applying the same configuration to the target Project.
 */
fun Project.configureFeatureDocumentation() {
    // Configure all Dokka tasks in this project
    tasks.withType(DokkaTask::class.java).configureEach {
        // Set the output directory to the build/dokka folder
        outputDirectory.set(layout.buildDirectory.dir("dokka"))
        
        // Set the module name to "feature"
        moduleName.set("feature")
        
        // Configure each source set
        dokkaSourceSets.configureEach {
            sourceLink {
                // Set the local directory to the src folder
                localDirectory.set(file("src"))
                
                // Set the remote URL to the GitHub repository
                remoteUrl.set(URI("https://github.com/openMF/mobile-wallet.git").toURL())
                
                // Set the line suffix for deep linking to specific lines
                remoteLineSuffix.set("#L")
            }
        }
    }
}

override fun apply(target: Project) {
target.tasks.withType(DokkaTask::class.java).configureEach {
outputDirectory.set(target.layout.buildDirectory.dir("dokka"))
moduleName.set("feature")
dokkaSourceSets.configureEach {
sourceLink {
localDirectory.set(target.file("src"))
remoteUrl.set(java.net.URI("https://github.com/openMF/mobile-wallet.git").toURL())
remoteLineSuffix.set("#L")
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ class KMPLibraryConventionPlugin: Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply(KMPLibraryPlugin::class.java)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you adding this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

apply("com.android.library")
apply("org.jetbrains.kotlin.multiplatform")
apply("mifospay.kmp.koin")
apply("mifos.detekt.plugin")
apply("mifos.spotless.plugin")
apply("org.jetbrains.dokka")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sufficient for docs generation

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok I will look into it

}

configureKotlinMultiplatform()
Expand Down
26 changes: 26 additions & 0 deletions build-logic/convention/src/main/kotlin/KMPLibraryPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.withType

class KMPLibraryPlugin : Plugin<Project> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this, if required create an extension function and call it where it's required like we did configureKotlinMultiplatform() or configureKotlinAndroid

override fun apply(target: Project) {
target.plugins.apply("org.jetbrains.kotlin.multiplatform")
target.plugins.apply("org.jetbrains.dokka")

target.tasks.withType<org.jetbrains.dokka.gradle.DokkaTask>().configureEach {
outputDirectory.set(target.layout.buildDirectory.dir("dokka"))
dokkaSourceSets.configureEach {
if (name == "commonMain" || name == "androidMain") {
includeNonPublic.set(true)
skipDeprecated.set(true)
reportUndocumented.set(true)
jdkVersion.set(8)
}
}
}

target.extensions.configure(org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension::class.java) {
// Add your existing KMP configuration here
}
}
}
22 changes: 20 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ plugins {
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.wire) apply false
alias(libs.plugins.ktorfit) apply false
alias(libs.plugins.dokka) apply false
}

object DynamicVersion {
Expand All @@ -57,7 +58,6 @@ tasks.register("printModulePaths") {
}
}
}

// Configuration for CMP module dependency graph
moduleGraphAssert {
configurations += setOf("commonMainImplementation", "commonMainApi")
Expand All @@ -66,4 +66,22 @@ moduleGraphAssert {
configurations += setOf("jsMainImplementation", "jsMainApi")
configurations += setOf("nativeMainImplementation", "nativeMainApi")
configurations += setOf("wasmJsMainImplementation", "wasmJsMainApi")
}
}

subprojects {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://kotlinlang.org/docs/dokka-gradle.html#multi-project-configuration

subprojects {
apply(plugin = "org.jetbrains.dokka")

// configure only the HTML task
tasks.dokkaHtmlPartial {
    outputDirectory.set(layout.buildDirectory.dir("docs/partial"))
}

// configure all format tasks at once
tasks.withType<DokkaTaskPartial>().configureEach {
    dokkaSourceSets.configureEach {
        includes.from("README.md")
    }
}

}

plugins.withId("org.jetbrains.dokka") {
tasks.withType<org.jetbrains.dokka.gradle.DokkaTask>().configureEach {
outputDirectory.set(layout.buildDirectory.dir("dokka"))
dokkaSourceSets {
configureEach {
if (name == "commonMain" || name == "androidMain" || name == "desktopMain" || name == "jsMain" || name == "nativeMain") {
includeNonPublic.set(true)
skipDeprecated.set(true)
reportUndocumented.set(true)
jdkVersion.set(8)
}
}
}
}
}
}
1 change: 1 addition & 0 deletions core/analytics/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ plugins {
alias(libs.plugins.mifospay.kmp.library)
alias(libs.plugins.jetbrainsCompose)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.dokka)
}

android {
Expand Down
4 changes: 3 additions & 1 deletion feature/accounts/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
plugins {
alias(libs.plugins.mifospay.cmp.feature)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.dokka)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove these plugins alias(libs.plugins.dokka) and alias(libs.plugins.mifospay.feature.library)

alias(libs.plugins.mifospay.feature.library)
}

android {
Expand All @@ -27,4 +29,4 @@ kotlin {
implementation(libs.kotlinx.serialization.json)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import org.mifospay.feature.accounts.AccountAction.Internal.DeleteBeneficiary
import org.mifospay.feature.accounts.AccountEvent.OnAddEditSavingsAccount
import org.mifospay.feature.accounts.beneficiary.BeneficiaryAddEditType
import org.mifospay.feature.accounts.savingsaccount.SavingsAddEditType

@OptIn(ExperimentalCoroutinesApi::class)
class AccountViewModel(
private val userRepository: UserPreferencesRepository,
Expand All @@ -51,6 +50,9 @@ class AccountViewModel(
)
},
) {
/**
* Exposes the account and beneficiary list as a [StateFlow] of [AccountState.ViewState].
*/
val accountState = repository.getAccountAndBeneficiaryList(state.clientId)
.mapLatest {
when (it) {
Expand All @@ -67,6 +69,9 @@ class AccountViewModel(
initialValue = AccountState.ViewState.Loading,
)

/**
* Handles [AccountAction] and triggers corresponding [AccountEvent] or state updates.
*/
override fun handleAction(action: AccountAction) {
when (action) {
is AccountAction.CreateSavingsAccount -> {
Expand Down Expand Up @@ -124,6 +129,9 @@ class AccountViewModel(
}
}

/**
* Handles updating the default account in [userRepository].
*/
private fun handleSetDefaultAccount(action: AccountAction.SetDefaultAccount) {
viewModelScope.launch {
userRepository.updateDefaultAccount(
Expand All @@ -138,6 +146,9 @@ class AccountViewModel(
sendEvent(AccountEvent.ShowToast("Default account updated"))
}

/**
* Sends a delete request for the given beneficiary ID and shows a loading dialog.
*/
private fun handleDeleteBeneficiary(action: DeleteBeneficiary) {
mutableStateFlow.update { it.copy(dialogState = AccountState.DialogState.Loading) }

Expand All @@ -148,6 +159,9 @@ class AccountViewModel(
}
}

/**
* Handles the result of deleting a beneficiary and updates dialog state accordingly.
*/
private fun handleBeneficiaryDeleteResult(action: BeneficiaryDeleteResultReceived) {
when (action.result) {
is DataState.Success -> {
Expand Down Expand Up @@ -175,36 +189,52 @@ class AccountViewModel(
}
}

/**
* Represents the state of the account screen.
*/
data class AccountState(
val clientId: Long,
val defaultAccountId: Long? = null,
val dialogState: DialogState? = null,
) {
/**
* Defines various dialog UI states.
*/
sealed interface DialogState {
/** Represents a loading dialog. */
data object Loading : DialogState

/** Represents an error dialog with a message. */
data class Error(val message: String) : DialogState

/** Dialog shown before deleting a beneficiary. */
data class DeleteBeneficiary(
val title: StringResource,
val message: StringResource,
val onConfirm: () -> Unit,
) : DialogState
}

/**
* UI state representing the screen's visual content.
*/
sealed interface ViewState {
val hasFab: Boolean

val isPullToRefreshEnabled: Boolean

/** Loading view state. */
data object Loading : ViewState {
override val hasFab: Boolean get() = false
override val isPullToRefreshEnabled: Boolean get() = false
}

/** Error view state with a message. */
data class Error(val message: String) : ViewState {
override val hasFab: Boolean get() = false
override val isPullToRefreshEnabled: Boolean get() = false
}

/** Content view state with account and beneficiary info. */
data class Content(
val accounts: List<Account>,
val beneficiaries: List<Beneficiary>,
Expand All @@ -215,26 +245,32 @@ data class AccountState(
}
}

/**
* Events that can be sent by [AccountViewModel] to update the UI.
*/
sealed interface AccountEvent {
data class OnAddEditSavingsAccount(val type: SavingsAddEditType) : AccountEvent
data class OnNavigateToAccountDetail(val accountId: Long) : AccountEvent
data class OnAddOrEditTPTBeneficiary(val type: BeneficiaryAddEditType) : AccountEvent

data class ShowToast(val message: String) : AccountEvent
}

/**
* Actions that can be triggered from the UI to be handled by [AccountViewModel].
*/
sealed interface AccountAction {
data object AddTPTBeneficiary : AccountAction
data class EditBeneficiary(val beneficiary: Beneficiary) : AccountAction
data class DeleteBeneficiary(val beneficiaryId: Long) : AccountAction

data object CreateSavingsAccount : AccountAction
data class EditSavingsAccount(val accountId: Long) : AccountAction
data class ViewAccountDetails(val accountId: Long) : AccountAction
data class SetDefaultAccount(val accountId: Long, val accountNo: String) : AccountAction

data object DismissDialog : AccountAction

/**
* Internal-only actions used within the view model.
*/
sealed interface Internal : AccountAction {
data class DeleteBeneficiary(val beneficiaryId: Long) : Internal
data class BeneficiaryDeleteResultReceived(val result: DataState<String>) : Internal
Expand Down
6 changes: 5 additions & 1 deletion feature/auth/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ plugins {
alias(libs.plugins.mifospay.cmp.feature)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.dokka)
alias(libs.plugins.mifospay.feature.library)

}

android {
Expand Down Expand Up @@ -44,4 +47,5 @@ kotlin {
implementation(libs.play.services.auth)
}
}
}
}

Loading
Loading