fix: dep fix & add input
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package com.approagency.drug
|
||||
|
||||
import android.app.Application
|
||||
import com.approagency.drug.di.appModule
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.core.context.startKoin
|
||||
|
||||
class DrugApp : Application(){
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
startKoin {
|
||||
androidContext(this@DrugApp)
|
||||
modules(appModule)
|
||||
printLogger()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface DrugApiService {
|
||||
@GET("/drugs/search")
|
||||
@GET("drugs/search")
|
||||
suspend fun getDrugs(
|
||||
@Query("q")query: String?,
|
||||
@Query("per_page")perPage:Int? = 20,
|
||||
@@ -17,7 +17,7 @@ interface DrugApiService {
|
||||
): DrugListResponse
|
||||
|
||||
|
||||
@GET("/drugs/{cod}")
|
||||
@GET("drugs/{cod}")
|
||||
suspend fun getDrugDetail(
|
||||
@Path("cod") cod: Int
|
||||
): DrugModels
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.approagency.drug.di
|
||||
|
||||
|
||||
import android.app.Application
|
||||
import com.approagency.drug.data.remote.DrugApiService
|
||||
import com.approagency.drug.data.repository.DrugRepositoryImpl
|
||||
import com.approagency.drug.domain.repository.DrugRepository
|
||||
import com.approagency.drug.domain.usecase.GetDrugSearchUseCase
|
||||
@@ -19,7 +20,9 @@ val appModule= module {
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
}
|
||||
|
||||
single<DrugApiService> {
|
||||
get<Retrofit>().create(DrugApiService::class.java)
|
||||
}
|
||||
|
||||
//repo
|
||||
single<DrugRepository> {
|
||||
@@ -34,6 +37,7 @@ val appModule= module {
|
||||
}
|
||||
|
||||
//view model
|
||||
viewModel { (app: Application) ->
|
||||
HomeViewModel(app, get())}
|
||||
viewModel {
|
||||
HomeViewModel(get())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.approagency.drug.presentation.common
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vada.caller.ui.theme.dime
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CustomModalBottomSheet(
|
||||
modifier: Modifier = Modifier,
|
||||
sheetState: SheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
|
||||
scope: CoroutineScope = rememberCoroutineScope(),
|
||||
onDismiss: (() -> Unit)? = null,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = {
|
||||
onDismiss?.invoke()
|
||||
},
|
||||
sheetState = sheetState,
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(topStart = MaterialTheme.dime.lg, topEnd = MaterialTheme.dime.lg)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.approagency.drug.presentation.common
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
||||
|
||||
@Composable
|
||||
|
||||
fun CustomBox(
|
||||
modifier: Modifier? = Modifier,
|
||||
child: @Composable ()-> Unit
|
||||
) {
|
||||
if (modifier != null) {
|
||||
Box(
|
||||
modifier = modifier.clip(shape = MaterialTheme.shapes.large).background(
|
||||
color = MaterialTheme.colorScheme.surfaceContainer
|
||||
)
|
||||
) {
|
||||
child()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.approagency.drug.presentation.common
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import com.vada.caller.ui.theme.dime
|
||||
|
||||
@Composable
|
||||
fun CustomModalDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
Dialog(
|
||||
onDismissRequest = onDismissRequest
|
||||
){
|
||||
Surface(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
color = MaterialTheme.colorScheme.surface,
|
||||
tonalElevation = MaterialTheme.dime.sm
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(MaterialTheme.dime.lg),
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.dime.lg),
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.approagency.drug.presentation.common
|
||||
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object SnackbarManager {
|
||||
private var snackbarHostState: SnackbarHostState? = null
|
||||
private var coroutineScope: CoroutineScope? = null
|
||||
|
||||
fun init(scope: CoroutineScope, hostState: SnackbarHostState) {
|
||||
coroutineScope = scope
|
||||
snackbarHostState = hostState
|
||||
}
|
||||
|
||||
fun showMessage(message: String) {
|
||||
coroutineScope?.launch {
|
||||
snackbarHostState?.showSnackbar(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.vada.caller.presentation.common
|
||||
|
||||
sealed interface UiState<out T> {
|
||||
object Loading : UiState<Nothing>
|
||||
data class Success<T>(val data: T) : UiState<T>
|
||||
data class Error(val message: String) : UiState<Nothing>
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.approagency.drug.presentation.common
|
||||
|
||||
import android.content.res.Resources.Theme
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun Loading() {
|
||||
CircularProgressIndicator(
|
||||
color = MaterialTheme.colorScheme.onPrimary,
|
||||
modifier = Modifier,
|
||||
strokeWidth = 1.dp
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.approagency.drug.presentation.common
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun PrimaryButton(
|
||||
text: String,
|
||||
isLoading: Boolean?,
|
||||
onClick: () -> Unit,
|
||||
height: Int? = null
|
||||
) {
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary
|
||||
),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
modifier = Modifier.fillMaxWidth().height(height?.dp ?: 50.dp),
|
||||
onClick = {
|
||||
onClick()
|
||||
},
|
||||
) {
|
||||
if (isLoading == true) {
|
||||
Loading()
|
||||
} else {
|
||||
Text(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,38 @@
|
||||
package com.approagency.drug.presentation.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.approagency.drug.domain.model.DrugSearchParams
|
||||
import com.approagency.drug.presentation.common.PrimaryButton
|
||||
import com.approagency.drug.presentation.viewModel.DrugSearchState
|
||||
import com.approagency.drug.presentation.viewModel.HomeViewModel
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@@ -10,6 +41,69 @@ import org.koin.androidx.compose.koinViewModel
|
||||
fun HomeScreen(
|
||||
modifier: Modifier,
|
||||
viewModel: HomeViewModel = koinViewModel()
|
||||
){
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
HomeContent(
|
||||
state = state,
|
||||
onSearch = { value -> viewModel.searchDrugs(DrugSearchParams(query = value)) },
|
||||
onRetry = {
|
||||
viewModel.clearError()
|
||||
},
|
||||
onDrugClick = { drugId -> println(drugId) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeContent(
|
||||
state: DrugSearchState,
|
||||
onSearch: (String) -> Unit,
|
||||
onRetry: () -> Unit,
|
||||
onDrugClick: (String) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var search by remember { mutableStateOf("") }
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
horizontalAlignment = Alignment.Start
|
||||
) {
|
||||
Column {
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
|
||||
OutlinedTextField(
|
||||
value = search,
|
||||
shape = MaterialTheme.shapes.large,
|
||||
onValueChange = { value ->
|
||||
search = value
|
||||
},
|
||||
label = { Text("جستجوی دارو") },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
||||
trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
if (search.isNotBlank()) {
|
||||
onSearch(search)
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Search,
|
||||
contentDescription = "Search"
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
PrimaryButton(
|
||||
text = "جستجو",
|
||||
height = 40,
|
||||
|
||||
isLoading = state.isLoading,
|
||||
onClick = {
|
||||
if (search.isNotBlank()) {
|
||||
onSearch(search)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.vada.caller.ui.theme
|
||||
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
|
||||
data class Dime (
|
||||
val xxs: Dp = 2.dp,
|
||||
val xs: Dp = 4.dp,
|
||||
val sm: Dp = 8.dp,
|
||||
val md: Dp = 12.dp,
|
||||
val lg: Dp = 16.dp,
|
||||
val xl: Dp = 20.dp,
|
||||
val xxl: Dp = 24.dp,
|
||||
|
||||
|
||||
val iconSm: Dp = 20.dp,
|
||||
val iconMd: Dp = 24.dp,
|
||||
val iconLg: Dp = 32.dp,
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.vada.caller.ui.theme
|
||||
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
|
||||
val LocalDime = staticCompositionLocalOf { Dime() }
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.vada.caller.ui.theme
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
val MaterialTheme.dime: Dime
|
||||
@Composable
|
||||
get() =LocalDime.current
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.fabirt.podcastapp.ui.theme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
val Shapes = Shapes(
|
||||
small = RoundedCornerShape(4.dp),
|
||||
medium = RoundedCornerShape(12.dp),
|
||||
large = RoundedCornerShape(16.dp),
|
||||
extraLarge = RoundedCornerShape(20.dp)
|
||||
)
|
||||
@@ -4,12 +4,17 @@ import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.fabirt.podcastapp.ui.theme.Shapes
|
||||
import com.vada.caller.ui.theme.Dime
|
||||
import com.vada.caller.ui.theme.LocalDime
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
@@ -50,9 +55,14 @@ fun DrugTheme(
|
||||
else -> LightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
CompositionLocalProvider(
|
||||
LocalDime provides Dime()
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = AppTypography,
|
||||
content = content,
|
||||
shapes = Shapes,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
package com.approagency.drug.ui.theme
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import com.approagency.drug.R
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.Font
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
val Dana = FontFamily(
|
||||
Font(R.font.dana_regular),
|
||||
Font(R.font.dana_regular, weight = FontWeight.Light),
|
||||
Font(R.font.dana_medium, weight = FontWeight.Medium),
|
||||
Font(R.font.dana_bold, weight = FontWeight.Bold),
|
||||
)
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
@@ -15,20 +23,98 @@ val Typography = Typography(
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
)
|
||||
|
||||
val AppTypography = Typography(
|
||||
displayLarge = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 57.sp,
|
||||
lineHeight = 64.sp,
|
||||
letterSpacing = (-0.25).sp
|
||||
),
|
||||
displayMedium = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 45.sp,
|
||||
lineHeight = 52.sp
|
||||
),
|
||||
displaySmall = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 36.sp,
|
||||
lineHeight = 44.sp
|
||||
),
|
||||
headlineLarge = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 40.sp
|
||||
),
|
||||
headlineMedium = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 36.sp
|
||||
),
|
||||
headlineSmall = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 24.sp,
|
||||
lineHeight = 32.sp
|
||||
),
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
lineHeight = 28.sp
|
||||
),
|
||||
titleMedium = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp
|
||||
),
|
||||
titleSmall = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp
|
||||
),
|
||||
bodyMedium = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
bodySmall = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.Light,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
labelLarge = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
labelMedium = TextStyle(
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontFamily = Dana,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
lineHeight = 16.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
@@ -1,5 +1,5 @@
|
||||
package com.approagency.drug.utils
|
||||
|
||||
object Config {
|
||||
const val BASE_URL = "https://drug.approagency.ir/api"
|
||||
const val BASE_URL = "https://drug.approagency.ir/api/"
|
||||
}
|
||||
Reference in New Issue
Block a user