Untitled

 avatar
unknown
java
a year ago
21 kB
7
Indexable
package com.phonepe.scrip_detail.factor_analysis.ui


import android.app.Activity
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.phonepe.ape.atoms.textview.ApeText
import com.phonepe.ape.theme.ApeTheme
import com.phonepe.scrip_detail.R
import com.phonepe.scrip_detail.bottomsheet.viewmodel.ScripDetailViewModel
import com.phonepe.scrip_detail.factor_analysis.models.FactorRatingVM
import com.phonepe.scrip_detail.factor_analysis.models.FactorState
import com.phonepe.scrip_detail.factor_analysis.models.FactorTab
import com.phonepe.scrip_detail.factor_analysis.models.FactorsOverviewVM
import com.phonepe.scrip_detail.factor_analysis.models.ScripDetailFactorAnalysisState
import com.phonepe.scrip_detail.factor_analysis.models.ScripDetailsFactorComparisonVM
import com.phonepe.scrip_detail.factor_analysis.models.ScripDetailsFactorsAnalystsSentimentVM
import com.phonepe.scrip_detail.factor_analysis.models.toFactorState
import com.phonepe.scrip_detail.factor_analysis.ui.rive.RadarGraphRive
import com.phonepe.scrip_detail.factor_analysis.viewmodel.ScripDetailsFactorAnalysisViewModel
import com.phonepe.scrip_detail.factor_analysis.viewmodel.ScripDetailsMomentumFactorViewModel
import com.phonepe.scrip_detail.hilt.ViewModelFactoryProvider
import com.phonepe.scrip_detail.widgets.LoadingView
import com.phonepe.stockbroking.common.loadState.UnableToFetchData
import dagger.hilt.android.EntryPointAccessors


const val STATE_MACHINE = "State Machine1"
const val SELECTED_STATE_MACHINE = "State"
private val verticalPadding = 21.dp
private val topPadding = 10.dp

@RequiresApi(Build.VERSION_CODES.R)
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ScripDetailsFactorAnalysisTab(
    scripDetailsViewModel: ScripDetailViewModel,
    instrumentId: String,
    boltId: Long,
    radarGraphSize: Dp = 300.dp,
) {

    val viewModel: ScripDetailsFactorAnalysisViewModel<FactorsOverviewVM> =
        scripDetailsFactorsOverviewViewModel(
            instrumentId,
            "${instrumentId}1"
        )

    val uiState: ScripDetailFactorAnalysisState<FactorsOverviewVM> by viewModel.factorElementState.collectAsStateWithLifecycle()
    val factorRatings by viewModel.factorRatings.collectAsStateWithLifecycle()

    when (uiState) {
        is ScripDetailFactorAnalysisState.FactorElements -> {
            val factorElement = uiState as ScripDetailFactorAnalysisState.FactorElements
            SuccessView(
                radarGraphSize,
                factorElement,
                factorRatings,
                scripDetailsViewModel,
                instrumentId,
                boltId
            )
        }

        is ScripDetailFactorAnalysisState.IsError -> {
            UnableToFetchData(
                modifier = Modifier.fillMaxSize(),
                onClickRetry = { viewModel.loadFactorElement() },
                title = "",
                troubleFetchingContent = ""
            )
        }

        ScripDetailFactorAnalysisState.IsLoading -> {
            LoadingView(modifier = Modifier.fillMaxSize())
        }
    }
}

@Composable
private fun SuccessView(
    size: Dp,
    overviewElement: ScripDetailFactorAnalysisState.FactorElements<FactorsOverviewVM>,
    factorRatings: Map<FactorState, FactorRatingVM>,
    scripDetailsViewModel: ScripDetailViewModel,
    instrumentId: String,
    boltId: Long,
) {
    var selectedSection by rememberSaveable {
        mutableStateOf(FactorState.OVERVIEW)
    }

    LazyColumn(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {

        overviewElement.data.spiderChartItems?.let { spiderChartItems ->
            item {
                RadarGraphRive(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(size),
                    stateMachine = STATE_MACHINE,
                    selectedStateMachine = SELECTED_STATE_MACHINE,
                    data = spiderChartItems,
                    selectedTab = FactorTab.OVERVIEW
                ) {
                    selectedSection = it.toFactorState()
                }
            }
        }


        item {
            ScrollableFactorRow(selectedSection.index, factorRatings, onIndexChanged = {
                selectedSection = FactorState.fromIndex(it)
            })
        }

        item {
            when (selectedSection) {
                FactorState.OVERVIEW -> ScripDetailsFactorOverviewContent(
                    factors = overviewElement.data.summaryItems!!,
                    modifier = Modifier.fillMaxWidth(),
                )

                FactorState.MOMENTUM -> {
                    val viewModel: ScripDetailsMomentumFactorViewModel = scripDetailsMomentumFactorViewModel(
                        instrumentId,
                        boltId,
                        "${instrumentId}6"
                    )
                    ScripDetailsMomentumFactorContent(
                        momentumFactorviewModel = viewModel,
                        factorRatingVM = factorRatings[FactorState.MOMENTUM],
                        scripDetailsViewModel = scripDetailsViewModel
                    )
                }

                FactorState.QUALITY -> {
                    val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> =
                        scripDetailsQualityFactorViewModel(
                            instrumentId,
                            "${instrumentId}2"
                        )
                    ScripDetailsFactorKeyMetricsContent(
                        factorName = stringResource(id = R.string.quality),
                        factorDescription = stringResource(id = R.string.dummy_desc),
                        scripName = "ABC Comp.",
                        viewModel = viewModel,
                        factorRating = factorRatings[FactorState.QUALITY],
                    )
                }

                FactorState.SENTIMENT -> {
                    val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorsAnalystsSentimentVM> =
                        scripDetailsAnalystsSentimentFactorViewModel(
                            instrumentId,
                            "${instrumentId}3"
                        )
                    ScripDetailsSentimentFactorContent(
                        viewModel = viewModel,
                        factorRatingVM = factorRatings[FactorState.SENTIMENT],
                    )
                }

                FactorState.RISK -> {
                    val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> =
                        scripDetailsRiskFactorViewModel(
                            instrumentId,
                            "${instrumentId}4"
                        )
                    ScripDetailsFactorKeyMetricsContent(
                        factorName = stringResource(id = R.string.risk),
                        factorDescription = stringResource(id = R.string.dummy_desc),
                        scripName = "ABC Comp.",
                        viewModel = viewModel,
                        factorRating = factorRatings[FactorState.RISK],
                    )
                }

                FactorState.VALUE -> {
                    val viewModel: ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> =
                        scripDetailsValueFactorViewModel(
                            instrumentId,
                            "${instrumentId}5"
                        )
                    ScripDetailsFactorKeyMetricsContent(
                        factorName = stringResource(id = R.string.value),
                        factorDescription = stringResource(id = R.string.dummy_desc),
                        scripName = "ABC Comp.",
                        viewModel = viewModel,
                        factorRating = factorRatings[FactorState.VALUE],
                    )
                }
            }
        }
    }
}

@Composable
fun scripDetailsFactorsOverviewViewModel(
    instrumentId: String,
    key: String
): ScripDetailsFactorAnalysisViewModel<FactorsOverviewVM> {
    val factory = EntryPointAccessors.fromActivity(
        LocalContext.current as Activity,
        ViewModelFactoryProvider::class.java
    ).scripDetailsFactorsOverviewViewModelFactory()

    return viewModel(
        factory = ScripDetailsFactorAnalysisViewModel.provideFactory(
            assistedFactory = factory,
            factorTab = FactorTab.OVERVIEW,
            instrumentId
        ), key = key
    )
}

@Composable
fun scripDetailsValueFactorViewModel(
    instrumentId: String,
    key: String
): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> {
    val factory = EntryPointAccessors.fromActivity(
        LocalContext.current as Activity,
        ViewModelFactoryProvider::class.java
    ).scripDetailsFactorsComparisonViewModelFactory()

    return viewModel(
        factory = ScripDetailsFactorAnalysisViewModel.provideFactory(
            assistedFactory = factory,
            factorTab = FactorTab.VALUE,
            instrumentId = instrumentId
        ), key = key
    )
}

@Composable
fun scripDetailsQualityFactorViewModel(
    instrumentId: String,
    key: String
): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> {
    val factory = EntryPointAccessors.fromActivity(
        LocalContext.current as Activity,
        ViewModelFactoryProvider::class.java
    ).scripDetailsFactorsComparisonViewModelFactory()

    return viewModel(
        factory = ScripDetailsFactorAnalysisViewModel.provideFactory(
            assistedFactory = factory,
            factorTab = FactorTab.QUALITY,
            instrumentId = instrumentId
        ), key = key
    )
}

@Composable
fun scripDetailsRiskFactorViewModel(
    instrumentId: String,
    key: String
): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorComparisonVM> {
    val factory = EntryPointAccessors.fromActivity(
        LocalContext.current as Activity,
        ViewModelFactoryProvider::class.java
    ).scripDetailsFactorsComparisonViewModelFactory()

    return viewModel(
        factory = ScripDetailsFactorAnalysisViewModel.provideFactory(
            assistedFactory = factory,
            factorTab = FactorTab.RISK,
            instrumentId = instrumentId
        ), key = key
    )
}

@Composable
fun scripDetailsAnalystsSentimentFactorViewModel(
    instrumentId: String,
    key: String
): ScripDetailsFactorAnalysisViewModel<ScripDetailsFactorsAnalystsSentimentVM> {
    val factory = EntryPointAccessors.fromActivity(
        LocalContext.current as Activity,
        ViewModelFactoryProvider::class.java
    ).scripDetailsFactorsAnalystsSentimentsViewModelFactory()

    return viewModel(
        factory = ScripDetailsFactorAnalysisViewModel.provideFactory(
            assistedFactory = factory,
            factorTab = FactorTab.SENTIMENT,
            instrumentId = instrumentId
        ), key = key
    )
}

@Composable
fun scripDetailsMomentumFactorViewModel(
    instrumentId: String,
    boltId: Long,
    key: String
): ScripDetailsMomentumFactorViewModel {
    val factory = EntryPointAccessors.fromActivity(
        LocalContext.current as Activity,
        ViewModelFactoryProvider::class.java
    ).scripDetailsMomentumFactorViewModel()

    return viewModel(
        factory = ScripDetailsMomentumFactorViewModel.provideFactory(
            assistedFactory = factory,
            instrumentId = instrumentId,
            boltId = boltId
        ), key = key
    )
}


@Composable
fun ScrollableFactorRow(
    selectedSection: Int,
    factorRatings: Map<FactorState, FactorRatingVM>,
    onIndexChanged: (Int) -> Unit
) {
    val scrollState = rememberScrollState()
    Row(
        modifier = Modifier
            .horizontalScroll(scrollState)
            .padding(horizontal = ApeTheme.spacing.spacingMedium)
    ) {
        FactorTab.entries.forEachIndexed { index, tab ->
            if (selectedSection == index) {
                SelectedTab(tab, factorRatings[tab.toFactorState()])
            } else {
                UnSelectedTab(tab, factorRatings[tab.toFactorState()]) {
                    onIndexChanged(index)
                }
            }
        }
    }
}

@Composable
fun SelectedTab(tab: FactorTab, factorRatingVM: FactorRatingVM?) {
    if (tab == FactorTab.OVERVIEW) {
        SelectedOverviewTab(tab.displayName)
    } else {
        SelectedFactorTab(tab, factorRatingVM)
    }
}

@Composable
private fun SelectedFactorTab(
    tab: FactorTab,
    factorRatingVM: FactorRatingVM?
) {
    Card(
        shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium),
        border = BorderStroke(2.dp, ApeTheme.colors.borderBrandPrimary),
        modifier = Modifier
            .padding(horizontal = ApeTheme.spacing.spacingMediumSmall)
            .width(100.dp),
        colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.specialBackgroundBrandPrimary)
    ) {
        Column(
            modifier = Modifier.padding(
                ApeTheme.spacing.spacingMedium
            ),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {

            ApeText(
                text = tab.displayName,
                style = ApeTheme.typography.bodyTerStrong.copy(color = ApeTheme.colors.textBrandPrimary),
            )

            factorRatingVM?.let { vm ->
                val factorRatingStyle =
                    ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textBrandPrimary)
                val maxFactorRatingStyle =
                    ApeTheme.typography.bodyTer.copy(color = ApeTheme.colors.textBrandPrimary)
                val ratingText = buildAnnotatedString {
                    withStyle(style = factorRatingStyle.toSpanStyle()) {
                        append(vm.factorRating.toString())
                    }
                    withStyle(style = maxFactorRatingStyle.toSpanStyle()) {
                        append("/${vm.maxFactorRating}")
                    }
                }
                ApeText(
                    text = ratingText,
                    modifier = Modifier.padding(
                        top = ApeTheme.spacing.spacingSmall,
                    )
                )
            } ?: run {
                ApeText(
                    text = "N/A",
                    style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textBrandPrimary),
                    modifier = Modifier.padding(
                        top = topPadding,
                    )
                )
            }
        }
    }
}

@Composable
private fun SelectedOverviewTab(
    displayName: String
) {
    Card(
        shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium),
        border = BorderStroke(2.dp, ApeTheme.colors.borderBrandPrimary),
        modifier = Modifier
            .padding(horizontal = ApeTheme.spacing.spacingMediumSmall)
            .width(100.dp),
        colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.specialBackgroundBrandPrimary)
    ) {
        Column(
            modifier = Modifier.padding(
                horizontal = ApeTheme.spacing.spacingMedium,
                vertical = verticalPadding
            ),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {

            ApeText(
                text = displayName,
                style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textBrandPrimary),
            )
        }
    }
}

@Composable
fun UnSelectedTab(tab: FactorTab, factorRatingVM: FactorRatingVM?, onClick: () -> Unit) {
    if (tab == FactorTab.OVERVIEW) {
        UnSelectedOverviewTab(onClick, tab.displayName)
    } else {
        UnSelectedFactorTab(onClick, tab, factorRatingVM)
    }
}

@Composable
private fun UnSelectedFactorTab(
    onClick: () -> Unit,
    tab: FactorTab,
    factorRatingVM: FactorRatingVM?
) {
    Card(
        shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium),
        border = BorderStroke(2.dp, ApeTheme.colors.borderLite),
        modifier = Modifier
            .padding(horizontal = ApeTheme.spacing.spacingMediumSmall)
            .width(100.dp)
            .clickable {
                onClick()
            },
        colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.backgroundLiteDefault)
    ) {
        Column(
            modifier = Modifier.padding(
                ApeTheme.spacing.spacingMedium
            ),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            ApeText(
                text = tab.displayName,
                style = ApeTheme.typography.bodyTer.copy(color = ApeTheme.colors.textSecondary)
            )

            factorRatingVM?.let { vm ->
                val factorRatingStyle =
                    ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textSecondary)
                val maxFactorRatingStyle =
                    ApeTheme.typography.bodyTer.copy(color = ApeTheme.colors.textSecondary)
                val ratingText = buildAnnotatedString {
                    withStyle(style = factorRatingStyle.toSpanStyle()) {
                        append(vm.factorRating.toString())
                    }
                    withStyle(style = maxFactorRatingStyle.toSpanStyle()) {
                        append("/${vm.maxFactorRating}")
                    }
                }
                ApeText(
                    text = ratingText,
                    modifier = Modifier.padding(
                        top = ApeTheme.spacing.spacingSmall,
                    )
                )
            } ?: run {
                ApeText(
                    text = "N/A",
                    style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textSecondary),
                    modifier = Modifier.padding(
                        top = topPadding,
                    )
                )
            }
        }
    }
}

@Composable
private fun UnSelectedOverviewTab(
    onClick: () -> Unit,
    displayName: String
) {
    Card(
        shape = RoundedCornerShape(ApeTheme.spacing.spacingMedium),
        border = BorderStroke(2.dp, ApeTheme.colors.borderLite),
        modifier = Modifier
            .padding(horizontal = ApeTheme.spacing.spacingMediumSmall)
            .width(100.dp)
            .clickable {
                onClick()
            },
        colors = CardDefaults.cardColors(containerColor = ApeTheme.colors.backgroundLiteDefault)
    ) {
        Column(
            modifier = Modifier.padding(
                horizontal = ApeTheme.spacing.spacingMedium,
                vertical = verticalPadding
            ),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            ApeText(
                text = displayName,
                style = ApeTheme.typography.bodySecondaryStrong.copy(color = ApeTheme.colors.textSecondary)
            )
        }
    }
}
Editor is loading...
Leave a Comment