├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── drawable │ │ │ │ ├── call.png │ │ │ │ ├── img1.png │ │ │ │ ├── img2.png │ │ │ │ ├── img3.png │ │ │ │ ├── list.png │ │ │ │ ├── map.png │ │ │ │ ├── clock.png │ │ │ │ ├── email.png │ │ │ │ ├── header.png │ │ │ │ ├── mappin.png │ │ │ │ ├── doctor_pic.png │ │ │ │ ├── doctor_pic2.png │ │ │ │ ├── video_call.png │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── font │ │ │ │ ├── montserrat_light.ttf │ │ │ │ ├── montserrat_medium.ttf │ │ │ │ ├── montserrat_regular.ttf │ │ │ │ └── montserrat_semibold.ttf │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── values-night │ │ │ │ └── themes.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── mohammadsianaki │ │ │ │ └── doctorbooking │ │ │ │ ├── util │ │ │ │ ├── ResourceAlias.kt │ │ │ │ ├── Extenstions.kt │ │ │ │ └── Navigation.kt │ │ │ │ ├── model │ │ │ │ ├── SpecialityModel.kt │ │ │ │ └── DoctorModel.kt │ │ │ │ ├── ui │ │ │ │ ├── theme │ │ │ │ │ ├── Theme.kt │ │ │ │ │ ├── Color.kt │ │ │ │ │ └── Type.kt │ │ │ │ ├── components │ │ │ │ │ ├── AppBar.kt │ │ │ │ │ ├── SectionTextHeader.kt │ │ │ │ │ └── SearchBox.kt │ │ │ │ ├── DashboardViewModel.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── dashboard │ │ │ │ │ ├── SpecialistCard.kt │ │ │ │ │ ├── Doctors.kt │ │ │ │ │ └── Dashboard.kt │ │ │ │ └── detail │ │ │ │ │ └── DoctorDetail.kt │ │ │ │ └── data │ │ │ │ └── DataFactory.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── mohammadsianaki │ │ │ └── doctorbooking │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── github │ │ └── mohammadsianaki │ │ └── doctorbooking │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── .idea ├── .gitignore ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── encodings.xml ├── compiler.xml ├── misc.xml ├── jarRepositories.xml └── $CACHE_FILE$ ├── art └── design.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── README.md ├── gradle.properties ├── .gitignore ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "DoctorBooking" 2 | include ':app' 3 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /art/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/art/design.png -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DoctorBooking 3 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/call.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/img1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/img2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/img3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/list.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/map.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/email.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/header.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/mappin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/mappin.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/doctor_pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/doctor_pic.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/doctor_pic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/doctor_pic2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/video_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/drawable/video_call.png -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/font/montserrat_light.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/font/montserrat_medium.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/font/montserrat_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/font/montserrat_semibold.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohammadSianaki/Compose-Doctor-Booking/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/util/ResourceAlias.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.util 2 | 3 | import com.github.mohammadsianaki.doctorbooking.R 4 | 5 | typealias Drawables = R.drawable -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 28 20:39:36 IRST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-rc-6-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/util/Extenstions.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.util 2 | 3 | import kotlinx.coroutines.flow.MutableStateFlow 4 | import kotlinx.coroutines.flow.StateFlow 5 | 6 | fun MutableStateFlow.asStateFlow(): StateFlow = this -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Compose-Doctor-Booking 2 | A sample app built with Jetpack Compose 3 | 4 | # Credit 5 | https://dribbble.com/shots/10484486-Flutter-Doctor-App-UI?utm_source=pinterest&utm_campaign=pinterest_shot&utm_content=Flutter+Doctor+App+UI&utm_medium=Social_Share#shot-description 6 | 7 | ![alt text](https://github.com/mohammadsianaki/Compose-Doctor-Booking/blob/master/art/design.png?raw=true) 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/model/SpecialityModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.model 2 | 3 | import androidx.annotation.DrawableRes 4 | import androidx.compose.ui.graphics.Color 5 | 6 | data class SpecialityModel( 7 | @DrawableRes val image: Int, 8 | val speciality: String, 9 | val numberOfDoctors: Int, 10 | val backgroundColor: Color, 11 | ) -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.theme 2 | 3 | import androidx.compose.material.MaterialTheme 4 | import androidx.compose.runtime.Composable 5 | 6 | @Composable 7 | fun AppTheme(content: @Composable () -> Unit) { 8 | MaterialTheme( 9 | colors = AppColors, 10 | typography = AppTypography, 11 | content = content 12 | ) 13 | } -------------------------------------------------------------------------------- /app/src/test/java/com/github/mohammadsianaki/doctorbooking/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/model/DoctorModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.model 2 | 3 | import androidx.annotation.DrawableRes 4 | 5 | data class DoctorModel( 6 | val name: String = "", 7 | val speciality: String = "", 8 | @DrawableRes val profile: Int, 9 | @DrawableRes val secondaryProfile: Int, 10 | val telephone: String = "", 11 | val address:String = "", 12 | val daily:String ="", 13 | val about: String = "" 14 | ) 15 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.theme 2 | 3 | import androidx.compose.material.lightColors 4 | import androidx.compose.ui.graphics.Color 5 | 6 | val LightOrange = Color(0xfffbb97c) 7 | val DarkOrange = Color(0xfffba14d) 8 | val Red300 = Color(0xFFEA6D7E) 9 | 10 | val AppColors = lightColors( 11 | primary = LightOrange, 12 | secondary = LightOrange, 13 | primaryVariant = LightOrange, 14 | onSecondary = Color.Black, 15 | error = Red300, 16 | onError = Color.Black 17 | ) -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/github/mohammadsianaki/doctorbooking/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.github.mohammadsianaki.doctorbooking", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/components/AppBar.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.components 2 | 3 | import androidx.compose.foundation.Icon 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.material.IconButton 6 | import androidx.compose.material.TopAppBar 7 | import androidx.compose.material.icons.Icons 8 | import androidx.compose.material.icons.filled.ArrowBack 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.graphics.Color 12 | import androidx.compose.ui.unit.dp 13 | 14 | @Composable 15 | fun AppBar(showBackButton: Boolean = false, onBack: () -> Unit = {}) { 16 | TopAppBar( 17 | modifier = Modifier.padding(0.dp), 18 | elevation = 0.dp, 19 | backgroundColor = Color.White, 20 | ) { 21 | IconButton(onClick = onBack, enabled = showBackButton) { 22 | if (showBackButton) { 23 | Icon(asset = Icons.Default.ArrowBack) 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/util/Navigation.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.util 2 | 3 | import androidx.annotation.MainThread 4 | import androidx.compose.runtime.getValue 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.compose.runtime.setValue 7 | import androidx.lifecycle.ViewModel 8 | import com.github.mohammadsianaki.doctorbooking.model.DoctorModel 9 | 10 | 11 | sealed class Screen { 12 | object Home : Screen() 13 | data class DoctorInfo(val doctorModel: DoctorModel) : Screen() 14 | } 15 | 16 | class NavigationViewModel : ViewModel() { 17 | var currentScreen by mutableStateOf(Screen.Home) 18 | private set 19 | 20 | @MainThread 21 | fun onBackPressed(): Boolean { 22 | return if (currentScreen != Screen.Home) { 23 | currentScreen = Screen.Home 24 | true 25 | } else { 26 | false 27 | } 28 | } 29 | 30 | @MainThread 31 | fun navigateTo(screen: Screen) { 32 | currentScreen = screen 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/components/SectionTextHeader.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.components 2 | 3 | import androidx.compose.foundation.Text 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.material.EmphasisAmbient 6 | import androidx.compose.material.ProvideEmphasis 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.graphics.Color 10 | import androidx.compose.ui.text.TextStyle 11 | import androidx.compose.ui.text.font.FontWeight 12 | import androidx.compose.ui.unit.dp 13 | import androidx.compose.ui.unit.sp 14 | 15 | @Composable 16 | fun EmphasizedText( 17 | text: String, 18 | modifier: Modifier? = null, 19 | textStyle: TextStyle? = null 20 | ) { 21 | ProvideEmphasis(emphasis = EmphasisAmbient.current.high) { 22 | Text( 23 | modifier = modifier ?: Modifier.padding(16.dp), 24 | text = text, style = textStyle ?: TextStyle( 25 | color = Color(0xDD000000).copy(alpha = 0.8f), 26 | fontSize = 25.sp, 27 | fontWeight = FontWeight.SemiBold 28 | ) 29 | ) 30 | } 31 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/$CACHE_FILE$: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/DashboardViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.github.mohammadsianaki.doctorbooking.data.DataFactory 6 | import com.github.mohammadsianaki.doctorbooking.model.DoctorModel 7 | import com.github.mohammadsianaki.doctorbooking.model.SpecialityModel 8 | import com.github.mohammadsianaki.doctorbooking.util.asStateFlow 9 | import kotlinx.coroutines.flow.MutableStateFlow 10 | import kotlinx.coroutines.flow.collect 11 | import kotlinx.coroutines.flow.combine 12 | import kotlinx.coroutines.launch 13 | 14 | class DashboardViewModel : ViewModel() { 15 | private val _viewState = MutableStateFlow(DashboardViewState()) 16 | val viwState = _viewState.asStateFlow() 17 | 18 | private val selectedCategory = MutableStateFlow(0) 19 | private val categories = DataFactory.getCategories() 20 | private val doctors = DataFactory.getDoctors() 21 | 22 | init { 23 | viewModelScope.launch { 24 | combine( 25 | categories, 26 | selectedCategory, 27 | doctors 28 | ) { categories, selectedCategory, doctors -> 29 | DashboardViewState( 30 | doctors = doctors, 31 | categories = categories, 32 | selectedCategory = selectedCategory 33 | ) 34 | }.collect { 35 | _viewState.value = it 36 | } 37 | } 38 | } 39 | 40 | fun onCategorySelected(index: Int) { 41 | selectedCategory.value = index 42 | } 43 | } 44 | 45 | 46 | data class DashboardViewState( 47 | val doctors: List = emptyList(), 48 | val categories: List = emptyList(), 49 | val selectedCategory: Int = 0 50 | ) 51 | 52 | data class Category( 53 | val name: String = "", 54 | val specialists: List = emptyList() 55 | ) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | ### Android template 17 | # Built application files 18 | *.apk 19 | *.aar 20 | *.ap_ 21 | *.aab 22 | 23 | # Files for the ART/Dalvik VM 24 | *.dex 25 | 26 | # Java class files 27 | *.class 28 | 29 | # Generated files 30 | bin/ 31 | gen/ 32 | out/ 33 | # Uncomment the following line in case you need and you don't have the release build type files in your app 34 | # release/ 35 | 36 | # Gradle files 37 | .gradle/ 38 | build/ 39 | 40 | # Local configuration file (sdk path, etc) 41 | local.properties 42 | 43 | # Proguard folder generated by Eclipse 44 | proguard/ 45 | 46 | # Log Files 47 | *.log 48 | 49 | # Android Studio Navigation editor temp files 50 | .navigation/ 51 | 52 | # Android Studio captures folder 53 | captures/ 54 | 55 | # IntelliJ 56 | *.iml 57 | .idea/workspace.xml 58 | .idea/tasks.xml 59 | .idea/gradle.xml 60 | .idea/assetWizardSettings.xml 61 | .idea/dictionaries 62 | .idea/libraries 63 | # Android Studio 3 in .gitignore file. 64 | .idea/caches 65 | .idea/modules.xml 66 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 67 | .idea/navEditor.xml 68 | 69 | # Keystore files 70 | # Uncomment the following lines if you do not want to check your keystore files in. 71 | #*.jks 72 | #*.keystore 73 | 74 | # External native build folder generated in Android Studio 2.2 and later 75 | .externalNativeBuild 76 | .cxx/ 77 | 78 | # Google Services (e.g. APIs or Firebase) 79 | # google-services.json 80 | 81 | # Freeline 82 | freeline.py 83 | freeline/ 84 | freeline_project_description.json 85 | 86 | # fastlane 87 | fastlane/report.xml 88 | fastlane/Preview.html 89 | fastlane/screenshots 90 | fastlane/test_output 91 | fastlane/readme.md 92 | 93 | # Version control 94 | vcs.xml 95 | 96 | # lint 97 | lint/intermediates/ 98 | lint/generated/ 99 | lint/outputs/ 100 | lint/tmp/ 101 | # lint/reports/ 102 | 103 | # Android Profiling 104 | *.hprof 105 | 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import androidx.compose.animation.Crossfade 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.platform.setContent 8 | import androidx.lifecycle.ViewModelProvider 9 | import com.github.mohammadsianaki.doctorbooking.ui.dashboard.HomeScreen 10 | import com.github.mohammadsianaki.doctorbooking.ui.detail.DoctorInfoScreen 11 | import com.github.mohammadsianaki.doctorbooking.ui.theme.AppTheme 12 | import com.github.mohammadsianaki.doctorbooking.util.NavigationViewModel 13 | import com.github.mohammadsianaki.doctorbooking.util.Screen 14 | 15 | class MainActivity : AppCompatActivity() { 16 | private lateinit var navigationViewModel: NavigationViewModel 17 | private lateinit var dashboardViewModel: DashboardViewModel 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | navigationViewModel = ViewModelProvider(this)[NavigationViewModel::class.java] 21 | dashboardViewModel = ViewModelProvider(this)[DashboardViewModel::class.java] 22 | setContent { 23 | DoctorBookingApp(navigationViewModel, dashboardViewModel) 24 | } 25 | } 26 | 27 | override fun onBackPressed() { 28 | if (!navigationViewModel.onBackPressed()) { 29 | super.onBackPressed() 30 | } 31 | } 32 | 33 | @Composable 34 | fun DoctorBookingApp( 35 | navigationViewModel: NavigationViewModel, 36 | dashboardViewModel: DashboardViewModel 37 | ) { 38 | AppTheme { 39 | AppContent(navigationViewModel) 40 | } 41 | } 42 | 43 | @Composable 44 | fun AppContent(navigationViewModel: NavigationViewModel) { 45 | Crossfade(current = navigationViewModel.currentScreen) { screen -> 46 | when (screen) { 47 | is Screen.Home -> HomeScreen(navigationViewModel::navigateTo, dashboardViewModel) 48 | is Screen.DoctorInfo -> DoctorInfoScreen( 49 | navigationViewModel::onBackPressed, 50 | screen.doctorModel 51 | ) 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/dashboard/SpecialistCard.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.dashboard 2 | 3 | import androidx.compose.foundation.Box 4 | import androidx.compose.foundation.ContentGravity 5 | import androidx.compose.foundation.Image 6 | import androidx.compose.foundation.Text 7 | import androidx.compose.foundation.layout.padding 8 | import androidx.compose.foundation.layout.preferredHeight 9 | import androidx.compose.foundation.layout.preferredWidth 10 | import androidx.compose.foundation.lazy.LazyRowFor 11 | import androidx.compose.foundation.shape.RoundedCornerShape 12 | import androidx.compose.material.Card 13 | import androidx.compose.runtime.Composable 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.layout.ContentScale 17 | import androidx.compose.ui.res.imageResource 18 | import androidx.compose.ui.text.TextStyle 19 | import androidx.compose.ui.unit.dp 20 | import androidx.compose.ui.unit.sp 21 | import com.github.mohammadsianaki.doctorbooking.model.SpecialityModel 22 | 23 | 24 | @Composable 25 | fun SpecialityList(specialityModels: List) { 26 | Box(Modifier.preferredHeight(250.dp)) { 27 | LazyRowFor(items = specialityModels) { item -> 28 | SpecialityCard(specialityModel = item) 29 | } 30 | } 31 | } 32 | 33 | 34 | @Composable 35 | fun SpecialityCard(specialityModel: SpecialityModel) { 36 | Card( 37 | shape = RoundedCornerShape(24.dp), 38 | backgroundColor = specialityModel.backgroundColor, 39 | modifier = Modifier.padding(16.dp).preferredWidth(150.dp), 40 | elevation = 4.dp 41 | ) { 42 | Box( 43 | modifier = Modifier.padding(horizontal = 16.dp), 44 | gravity = ContentGravity.TopStart 45 | ) { 46 | Text( 47 | modifier = Modifier.padding(top = 16.dp), 48 | text = specialityModel.speciality, 49 | style = TextStyle(color = Color.White, fontSize = 20.sp) 50 | ) 51 | Text( 52 | modifier = Modifier.padding(top = 8.dp), 53 | text = "${specialityModel.numberOfDoctors} Doctors", 54 | style = TextStyle( 55 | color = Color.White, 56 | fontSize = 13.sp 57 | ) 58 | ) 59 | Image( 60 | modifier = Modifier.preferredHeight(160.dp), 61 | asset = imageResource(id = specialityModel.image), 62 | contentScale = ContentScale.Fit, 63 | ) 64 | } 65 | 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/data/DataFactory.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.data 2 | 3 | import androidx.compose.ui.graphics.Color 4 | import com.github.mohammadsianaki.doctorbooking.model.DoctorModel 5 | import com.github.mohammadsianaki.doctorbooking.model.SpecialityModel 6 | import com.github.mohammadsianaki.doctorbooking.ui.Category 7 | import com.github.mohammadsianaki.doctorbooking.util.Drawables 8 | import kotlinx.coroutines.flow.MutableStateFlow 9 | 10 | object DataFactory { 11 | 12 | private fun getSpeciality() = mutableListOf().apply { 13 | add( 14 | SpecialityModel( 15 | numberOfDoctors = 10, 16 | speciality = "Cough and Cold", 17 | backgroundColor = Color(0xffFBB97C), 18 | image = Drawables.img1 19 | ) 20 | ) 21 | add( 22 | SpecialityModel( 23 | numberOfDoctors = 17, 24 | speciality = "Heart Specialist", 25 | backgroundColor = Color(0xffF69383), 26 | image = Drawables.img2 27 | ) 28 | ) 29 | 30 | add( 31 | SpecialityModel( 32 | numberOfDoctors = 27, 33 | speciality = "Diabetes Care", 34 | backgroundColor = Color(0xffEACBCB), 35 | image = Drawables.img3 36 | ) 37 | ) 38 | } 39 | 40 | fun getCategories(): MutableStateFlow> { 41 | return MutableStateFlow(mutableListOf().apply { 42 | add( 43 | Category("Adults", getSpeciality()) 44 | ) 45 | add(Category("Childrens")) 46 | add(Category("Womens")) 47 | add(Category("Mens")) 48 | }) 49 | } 50 | 51 | fun getDoctors(): MutableStateFlow> { 52 | return MutableStateFlow(mutableListOf().apply { 53 | add( 54 | DoctorModel( 55 | name = "Dr. Stefani Albert", 56 | speciality = "Heart Specialist", 57 | profile = Drawables.doctor_pic, 58 | secondaryProfile = Drawables.doctor_pic2, 59 | telephone = "+98 4000", 60 | address = "House # 2, Road # 5, Green Road Dhanmondi, Dhaka, Bangladesh", 61 | daily = "Monday - Friday Open till 7 Pm", 62 | about = "Dr. Stefeni Albert is a cardiologist in Nashville & affiliated with multiple hospitals in the area.He received his medical degree from Duke University School of Medicine and has been in practice for more than 20 years. " 63 | ) 64 | ) 65 | }) 66 | } 67 | } -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdkVersion 30 8 | buildToolsVersion "30.0.0" 9 | 10 | defaultConfig { 11 | applicationId "com.github.mohammadsianaki.doctorbooking" 12 | minSdkVersion 21 13 | targetSdkVersion 30 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | 31 | kotlinOptions { 32 | jvmTarget = '1.8' 33 | allWarningsAsErrors = true 34 | } 35 | 36 | buildFeatures { 37 | compose true 38 | } 39 | 40 | composeOptions { 41 | kotlinCompilerVersion kotlin_version 42 | kotlinCompilerExtensionVersion compose_version 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 48 | implementation 'com.google.android.material:material:1.2.1' 49 | implementation "androidx.appcompat:appcompat:1.3.0-alpha02" 50 | implementation "androidx.palette:palette-ktx:1.0.0" 51 | implementation "androidx.core:core-ktx:1.5.0-alpha02" 52 | 53 | 54 | implementation "androidx.compose.runtime:runtime:$compose_version" 55 | implementation "androidx.compose.foundation:foundation:${compose_version}" 56 | implementation "androidx.compose.foundation:foundation-layout:${compose_version}" 57 | implementation "androidx.compose.ui:ui:${compose_version}" 58 | implementation "androidx.compose.material:material:${compose_version}" 59 | implementation "androidx.compose.material:material-icons-extended:${compose_version}" 60 | implementation "androidx.ui:ui-tooling:${compose_version}" 61 | implementation "androidx.ui:ui-test:${compose_version}" 62 | 63 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" 64 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" 65 | implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" 66 | 67 | // testImplementation 'junit:junit:4.+' 68 | // androidTestImplementation 'androidx.test.ext:junit:1.1.2' 69 | // androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 70 | implementation "dev.chrisbanes.accompanist:accompanist-coil:0.2.1" 71 | } 72 | 73 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { 74 | kotlinOptions { 75 | // Treat all Kotlin warnings as errors 76 | allWarningsAsErrors = false 77 | freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn' 78 | // Enable experimental coroutines APIs, including Flow 79 | freeCompilerArgs += '-Xopt-in=kotlin.Experimental' 80 | freeCompilerArgs += '-Xallow-jvm-ir-dependencies' 81 | // Set JVM target to 1.8 82 | jvmTarget = "1.8" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/components/SearchBox.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.components 2 | 3 | import androidx.compose.foundation.* 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.RoundedCornerShape 6 | import androidx.compose.material.Surface 7 | import androidx.compose.material.icons.Icons 8 | import androidx.compose.material.icons.filled.Search 9 | import androidx.compose.material.icons.outlined.Search 10 | import androidx.compose.runtime.* 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.graphics.Color 14 | import androidx.compose.ui.text.input.ImeAction 15 | import androidx.compose.ui.text.input.TextFieldValue 16 | import androidx.compose.ui.unit.dp 17 | import androidx.ui.tooling.preview.Preview 18 | import com.github.mohammadsianaki.doctorbooking.ui.theme.AppTheme 19 | 20 | @Composable 21 | fun Search(query: TextFieldValue) { 22 | var queryState by remember { mutableStateOf(query) } 23 | SearchBox( 24 | queryState = queryState, 25 | onValueChanged = { 26 | queryState = it 27 | }, 28 | modifier = Modifier.padding(16.dp) 29 | ) 30 | } 31 | 32 | @OptIn(ExperimentalFoundationApi::class) 33 | @Composable 34 | private fun SearchBox( 35 | queryState: TextFieldValue, 36 | onValueChanged: (TextFieldValue) -> Unit, 37 | modifier: Modifier = Modifier 38 | ) { 39 | Surface(modifier = modifier, color = Color(0xffEFEFEF), shape = RoundedCornerShape(10.dp)) { 40 | Stack(Modifier.fillMaxSize()) { 41 | if (queryState.text.isEmpty()) { 42 | SearchHint() 43 | } 44 | Row(Modifier.preferredHeightIn(56.dp).padding(horizontal = 16.dp)) { 45 | Icon( 46 | Icons.Default.Search, 47 | modifier = Modifier.wrapContentWidth().gravity(Alignment.CenterVertically) 48 | .padding(end = 8.dp) 49 | ) 50 | 51 | BaseTextField( 52 | value = queryState, 53 | onValueChange = { onValueChanged.invoke(it) }, 54 | textStyle = currentTextStyle(), 55 | imeAction = ImeAction.Search, 56 | onImeActionPerformed = { /* todo */ }, 57 | modifier = Modifier.weight(3f).gravity(Alignment.CenterVertically) 58 | ) 59 | } 60 | } 61 | } 62 | } 63 | 64 | @Composable 65 | private fun SearchHint() { 66 | Row( 67 | verticalGravity = Alignment.CenterVertically, 68 | modifier = Modifier.fillMaxSize().preferredHeightIn(56.dp).padding(horizontal = 16.dp) 69 | ) { 70 | Icon( 71 | asset = Icons.Outlined.Search, 72 | tint = Color(0xFF9E9E9E) 73 | ) 74 | Spacer(Modifier.preferredWidth(8.dp)) 75 | Text( 76 | text = "Search", 77 | color = Color(0xFF9E9E9E) 78 | ) 79 | } 80 | } 81 | 82 | @ExperimentalFoundationApi 83 | @Preview 84 | @Composable 85 | fun SearchBoxPreview() { 86 | AppTheme { 87 | SearchBox(queryState = TextFieldValue("Mohammad"), {}) 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.theme 2 | 3 | import androidx.compose.material.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.FontWeight 6 | import androidx.compose.ui.text.font.font 7 | import androidx.compose.ui.text.font.fontFamily 8 | import androidx.compose.ui.unit.sp 9 | import com.github.mohammadsianaki.doctorbooking.R 10 | 11 | private val Montserrat = fontFamily( 12 | font(R.font.montserrat_light, FontWeight.Light), 13 | font(R.font.montserrat_regular, FontWeight.Normal), 14 | font(R.font.montserrat_medium, FontWeight.Medium), 15 | font(R.font.montserrat_semibold, FontWeight.SemiBold) 16 | ) 17 | 18 | 19 | val AppTypography = Typography( 20 | h1 = TextStyle( 21 | fontFamily = Montserrat, 22 | fontSize = 96.sp, 23 | fontWeight = FontWeight.Light, 24 | lineHeight = 117.sp, 25 | letterSpacing = (-1.5).sp 26 | ), 27 | h2 = TextStyle( 28 | fontFamily = Montserrat, 29 | fontSize = 60.sp, 30 | fontWeight = FontWeight.Light, 31 | lineHeight = 73.sp, 32 | letterSpacing = (-0.5).sp 33 | ), 34 | h3 = TextStyle( 35 | fontFamily = Montserrat, 36 | fontSize = 48.sp, 37 | fontWeight = FontWeight.Normal, 38 | lineHeight = 59.sp 39 | ), 40 | h4 = TextStyle( 41 | fontFamily = Montserrat, 42 | fontSize = 30.sp, 43 | fontWeight = FontWeight.SemiBold, 44 | lineHeight = 37.sp 45 | ), 46 | h5 = TextStyle( 47 | fontFamily = Montserrat, 48 | fontSize = 24.sp, 49 | fontWeight = FontWeight.SemiBold, 50 | lineHeight = 29.sp 51 | ), 52 | h6 = TextStyle( 53 | fontFamily = Montserrat, 54 | fontSize = 20.sp, 55 | fontWeight = FontWeight.SemiBold, 56 | lineHeight = 24.sp 57 | ), 58 | subtitle1 = TextStyle( 59 | fontFamily = Montserrat, 60 | fontSize = 16.sp, 61 | fontWeight = FontWeight.SemiBold, 62 | lineHeight = 20.sp, 63 | letterSpacing = 0.5.sp 64 | ), 65 | subtitle2 = TextStyle( 66 | fontFamily = Montserrat, 67 | fontSize = 14.sp, 68 | fontWeight = FontWeight.Medium, 69 | lineHeight = 17.sp, 70 | letterSpacing = 0.1.sp 71 | ), 72 | body1 = TextStyle( 73 | fontFamily = Montserrat, 74 | fontSize = 16.sp, 75 | fontWeight = FontWeight.Medium, 76 | lineHeight = 20.sp, 77 | letterSpacing = 0.15.sp 78 | ), 79 | body2 = TextStyle( 80 | fontFamily = Montserrat, 81 | fontSize = 14.sp, 82 | fontWeight = FontWeight.SemiBold, 83 | lineHeight = 20.sp, 84 | letterSpacing = 0.25.sp 85 | ), 86 | button = TextStyle( 87 | fontFamily = Montserrat, 88 | fontSize = 14.sp, 89 | fontWeight = FontWeight.SemiBold, 90 | lineHeight = 16.sp, 91 | letterSpacing = 1.25.sp 92 | ), 93 | caption = TextStyle( 94 | fontFamily = Montserrat, 95 | fontSize = 12.sp, 96 | fontWeight = FontWeight.SemiBold, 97 | lineHeight = 16.sp, 98 | letterSpacing = 0.sp 99 | ), 100 | overline = TextStyle( 101 | fontFamily = Montserrat, 102 | fontSize = 12.sp, 103 | fontWeight = FontWeight.SemiBold, 104 | lineHeight = 16.sp, 105 | letterSpacing = 1.sp 106 | ) 107 | ) 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/dashboard/Doctors.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.dashboard 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import androidx.compose.foundation.ContentGravity 6 | import androidx.compose.foundation.Image 7 | import androidx.compose.foundation.Text 8 | import androidx.compose.foundation.clickable 9 | import androidx.compose.foundation.layout.* 10 | import androidx.compose.foundation.lazy.LazyColumnFor 11 | import androidx.compose.foundation.shape.RoundedCornerShape 12 | import androidx.compose.material.Button 13 | import androidx.compose.material.Card 14 | import androidx.compose.runtime.Composable 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.graphics.Color 17 | import androidx.compose.ui.platform.ContextAmbient 18 | import androidx.compose.ui.res.imageResource 19 | import androidx.compose.ui.text.TextStyle 20 | import androidx.compose.ui.text.font.FontWeight 21 | import androidx.compose.ui.unit.dp 22 | import androidx.compose.ui.unit.sp 23 | import com.github.mohammadsianaki.doctorbooking.model.DoctorModel 24 | import com.github.mohammadsianaki.doctorbooking.util.Screen 25 | 26 | 27 | @Composable 28 | fun DoctorsList(doctors: List, onItemClicked: (Screen) -> Unit) { 29 | LazyColumnFor(items = doctors, modifier = Modifier.fillMaxWidth().padding(16.dp)) { item -> 30 | DoctorCard(item, onItemClicked) 31 | } 32 | } 33 | 34 | @Composable 35 | fun DoctorCard(doctor: DoctorModel, onItemClicked: (Screen) -> Unit = {}) { 36 | Card( 37 | modifier = Modifier.fillMaxWidth().clickable(onClick = { 38 | onItemClicked.invoke(Screen.DoctorInfo(doctor)) 39 | }), 40 | shape = RoundedCornerShape(20.dp), 41 | backgroundColor = Color(0xffFFEEE0), 42 | elevation = 0.dp 43 | ) { 44 | Row( 45 | modifier = Modifier.padding(vertical = 8.dp), 46 | horizontalArrangement = Arrangement.SpaceEvenly, 47 | verticalGravity = ContentGravity.CenterVertically 48 | ) { 49 | Image( 50 | asset = imageResource(id = doctor.profile), 51 | modifier = Modifier.preferredSize(56.dp) 52 | ) 53 | Column( 54 | modifier = Modifier.padding(start = 0.dp, end = 16.dp, top = 8.dp, bottom = 8.dp), 55 | ) { 56 | Text( 57 | text = doctor.name, style = TextStyle( 58 | color = Color(0xffFC9535), 59 | fontSize = 19.sp 60 | ) 61 | ) 62 | Text( 63 | text = doctor.speciality, style = TextStyle( 64 | fontSize = 15.sp 65 | ) 66 | ) 67 | } 68 | val context = ContextAmbient.current 69 | Button( 70 | modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), 71 | onClick = { 72 | context.startActivity( 73 | Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", doctor.telephone, null)) 74 | ) 75 | }, 76 | backgroundColor = Color(0xffFBB97C) 77 | ) { 78 | Text( 79 | text = "Call", style = TextStyle( 80 | color = Color.White, 81 | fontWeight = FontWeight.W500, 82 | fontSize = 13.sp 83 | ) 84 | ) 85 | } 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 20 | 22 | 23 | 135 | 136 | 138 | 139 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/dashboard/Dashboard.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.dashboard 2 | 3 | import androidx.compose.foundation.ScrollableColumn 4 | import androidx.compose.foundation.ScrollableRow 5 | import androidx.compose.foundation.Text 6 | import androidx.compose.foundation.clickable 7 | import androidx.compose.foundation.layout.* 8 | import androidx.compose.foundation.shape.RoundedCornerShape 9 | import androidx.compose.material.* 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.runtime.collectAsState 12 | import androidx.compose.runtime.getValue 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.graphics.RectangleShape 17 | import androidx.compose.ui.text.TextStyle 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.text.input.TextFieldValue 20 | import androidx.compose.ui.unit.dp 21 | import androidx.compose.ui.unit.sp 22 | import com.github.mohammadsianaki.doctorbooking.model.DoctorModel 23 | import com.github.mohammadsianaki.doctorbooking.ui.Category 24 | import com.github.mohammadsianaki.doctorbooking.ui.DashboardViewModel 25 | import com.github.mohammadsianaki.doctorbooking.ui.components.AppBar 26 | import com.github.mohammadsianaki.doctorbooking.ui.components.EmphasizedText 27 | import com.github.mohammadsianaki.doctorbooking.ui.components.Search 28 | import com.github.mohammadsianaki.doctorbooking.ui.theme.LightOrange 29 | import com.github.mohammadsianaki.doctorbooking.util.Screen 30 | 31 | @Composable 32 | fun HomeScreen( 33 | navigateTo: (Screen) -> Unit, 34 | dashboardViewModel: DashboardViewModel 35 | ) { 36 | val viewState by dashboardViewModel.viwState.collectAsState() 37 | Scaffold( 38 | topBar = { AppBar() }, 39 | ) { _ -> 40 | ScrollableColumn( 41 | modifier = Modifier.fillMaxSize(), 42 | horizontalGravity = Alignment.Start, 43 | verticalArrangement = Arrangement.Top 44 | ) { 45 | SearchSection() 46 | CategorySection( 47 | viewState.categories, 48 | viewState.selectedCategory, 49 | dashboardViewModel::onCategorySelected 50 | ) 51 | DoctorsSection(viewState.doctors, navigateTo) 52 | } 53 | } 54 | } 55 | 56 | @Composable 57 | fun SearchSection() { 58 | ProvideEmphasis(emphasis = EmphasisAmbient.current.high) { 59 | Text( 60 | modifier = Modifier.padding(16.dp), 61 | text = "Find Your \nConsultation", style = TextStyle( 62 | color = Color(0xDD000000).copy(alpha = 0.8f), 63 | fontWeight = FontWeight.SemiBold, 64 | fontSize = 30.sp, 65 | ) 66 | ) 67 | } 68 | Search(query = TextFieldValue("")) 69 | } 70 | 71 | @Composable 72 | fun CategorySection( 73 | categories: List, 74 | selectedCategory: Int, 75 | onCategorySelected: (index: Int) -> Unit 76 | ) { 77 | EmphasizedText(text = "Categories") 78 | DashboardCategoryTabs(categories = categories, selectedCategory, onCategorySelected) 79 | SpecialityList(specialityModels = categories[selectedCategory].specialists) 80 | } 81 | 82 | 83 | @Composable 84 | fun DashboardCategoryTabs( 85 | categories: List, 86 | selectedIndex: Int, 87 | onCategorySelected: (index: Int) -> Unit 88 | ) { 89 | 90 | ScrollableRow(modifier = Modifier.preferredHeightIn(minHeight = 56.dp)) { 91 | Spacer(Modifier.preferredWidth(8.dp)) 92 | categories.forEachIndexed { index, category -> 93 | FilterChip( 94 | filter = category, 95 | selected = selectedIndex == index, 96 | modifier = Modifier.gravity(Alignment.CenterVertically), 97 | onCategorySelected = onCategorySelected, 98 | index = index 99 | ) 100 | Spacer(Modifier.preferredWidth(8.dp)) 101 | } 102 | } 103 | } 104 | 105 | @Composable 106 | fun FilterChip( 107 | filter: Category, 108 | modifier: Modifier = Modifier, 109 | selected: Boolean, 110 | onCategorySelected: (index: Int) -> Unit, 111 | index: Int 112 | ) { 113 | Surface( 114 | modifier = modifier 115 | .preferredHeight(28.dp) 116 | .clickable(onClick = { onCategorySelected(index) }, indication = null), 117 | color = if (selected) LightOrange else Color.Transparent, 118 | contentColor = if (selected) Color.White else Color.Black, 119 | shape = if (selected) RoundedCornerShape(15.dp) else RectangleShape 120 | ) { 121 | Text( 122 | text = filter.name, 123 | style = MaterialTheme.typography.caption, 124 | maxLines = 1, 125 | modifier = Modifier.padding( 126 | horizontal = 20.dp, 127 | vertical = 6.dp 128 | ) 129 | ) 130 | } 131 | } 132 | 133 | @Composable 134 | fun DoctorsSection(doctors: List, navigateTo: (Screen) -> Unit) { 135 | EmphasizedText(text = "Doctors") 136 | DoctorsList(doctors = doctors, navigateTo) 137 | } 138 | 139 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/mohammadsianaki/doctorbooking/ui/detail/DoctorDetail.kt: -------------------------------------------------------------------------------- 1 | package com.github.mohammadsianaki.doctorbooking.ui.detail 2 | 3 | import androidx.compose.foundation.* 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.RoundedCornerShape 6 | import androidx.compose.material.IconButton 7 | import androidx.compose.material.Scaffold 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.ui.Alignment 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.graphics.Color 12 | import androidx.compose.ui.layout.ContentScale 13 | import androidx.compose.ui.res.imageResource 14 | import androidx.compose.ui.text.TextStyle 15 | import androidx.compose.ui.text.font.FontWeight 16 | import androidx.compose.ui.unit.dp 17 | import androidx.compose.ui.unit.sp 18 | import com.github.mohammadsianaki.doctorbooking.model.DoctorModel 19 | import com.github.mohammadsianaki.doctorbooking.ui.components.AppBar 20 | import com.github.mohammadsianaki.doctorbooking.ui.components.EmphasizedText 21 | import com.github.mohammadsianaki.doctorbooking.util.Drawables 22 | 23 | 24 | @Composable 25 | fun DoctorInfoScreen(onBack: () -> Unit, doctorModel: DoctorModel) { 26 | Scaffold( 27 | topBar = { AppBar(true, onBack) }, 28 | ) { 29 | ScrollableColumn { 30 | ProfileSection(doctorModel) 31 | AboutSection(doctorModel) 32 | ActivitySection() 33 | } 34 | } 35 | } 36 | 37 | @Composable 38 | fun ProfileSection(doctorModel: DoctorModel) { 39 | Row( 40 | Modifier 41 | .wrapContentHeight() 42 | .padding(horizontal = 32.dp, vertical = 16.dp) 43 | ) { 44 | Image( 45 | modifier = Modifier.preferredHeight(220.dp), 46 | asset = imageResource(id = doctorModel.secondaryProfile), 47 | contentScale = ContentScale.Fit, 48 | ) 49 | Box { 50 | EmphasizedText( 51 | text = doctorModel.name, textStyle = TextStyle( 52 | color = Color(0xDD000000).copy(alpha = 0.8f), 53 | fontSize = 32.sp 54 | ), 55 | modifier = Modifier.padding(start = 16.dp, top = 16.dp) 56 | ) 57 | Text( 58 | text = doctorModel.speciality, 59 | fontSize = 16.sp, 60 | color = Color(0xFF9E9E9E), 61 | modifier = Modifier.padding(start = 16.dp) 62 | ) 63 | Row( 64 | Modifier.padding(top = 32.dp).fillMaxWidth().gravity(Alignment.Bottom), 65 | horizontalArrangement = Arrangement.SpaceEvenly 66 | ) { 67 | IconButton( 68 | onClick = {}, 69 | enabled = false, 70 | modifier = Modifier.background( 71 | color = Color(0xffFFECDD), 72 | shape = RoundedCornerShape(10.dp) 73 | ) 74 | ) { 75 | Icon(asset = imageResource(id = Drawables.email), tint = Color(0xfffbb97c)) 76 | } 77 | IconButton( 78 | onClick = {}, 79 | enabled = false, 80 | modifier = Modifier.background( 81 | color = Color(0xffFEF2F0), 82 | shape = RoundedCornerShape(10.dp) 83 | ) 84 | ) { 85 | Icon(asset = imageResource(id = Drawables.call),tint = Color(0xfffc747d)) 86 | } 87 | IconButton( 88 | onClick = {}, 89 | enabled = false, 90 | modifier = Modifier.background( 91 | color = Color(0xffEBECEF), 92 | shape = RoundedCornerShape(10.dp) 93 | ) 94 | ) { 95 | Icon(asset = imageResource(id = Drawables.video_call),tint = Color(0xffa7aab9)) 96 | } 97 | } 98 | } 99 | } 100 | } 101 | 102 | @Composable 103 | fun AboutSection(doctorModel: DoctorModel) { 104 | Text( 105 | text = "About", 106 | style = TextStyle(fontSize = 22.sp), 107 | modifier = Modifier.padding(start = 32.dp, top = 16.dp) 108 | ) 109 | Text( 110 | text = doctorModel.about, 111 | style = TextStyle(color = Color(0xFF9E9E9E), fontSize = 16.sp), 112 | modifier = Modifier.padding(horizontal = 32.dp, vertical = 16.dp), 113 | ) 114 | Row(Modifier.padding(horizontal = 32.dp, vertical = 16.dp)) { 115 | Column(Modifier.fillMaxHeight().weight(1f)) { 116 | Row { 117 | Image( 118 | asset = imageResource(id = Drawables.mappin), 119 | Modifier.gravity(Alignment.CenterVertically) 120 | ) 121 | Column(Modifier.padding(start = 16.dp)) { 122 | Text( 123 | text = "Address", style = TextStyle( 124 | color = Color.Black.copy(alpha = 0.7f), 125 | fontSize = 20.sp 126 | ) 127 | ) 128 | Text( 129 | text = doctorModel.address, 130 | style = TextStyle(color = Color.Gray) 131 | ) 132 | } 133 | } 134 | Row(modifier = Modifier.padding(top = 16.dp)) { 135 | Image( 136 | asset = imageResource(id = Drawables.clock), 137 | Modifier.gravity(Alignment.CenterVertically) 138 | ) 139 | Column(Modifier.padding(start = 16.dp)) { 140 | Text( 141 | text = "Daily Practice", style = TextStyle( 142 | color = Color.Black.copy(alpha = 0.7f), 143 | fontSize = 20.sp 144 | ) 145 | ) 146 | Text( 147 | text = doctorModel.daily, 148 | style = TextStyle(color = Color.Gray) 149 | ) 150 | } 151 | } 152 | } 153 | Image( 154 | asset = imageResource(id = Drawables.map), 155 | modifier = Modifier.fillMaxHeight().weight(1f) 156 | ) 157 | } 158 | } 159 | 160 | @Composable 161 | fun ActivitySection() { 162 | Text( 163 | text = "Activity", style = TextStyle( 164 | color = Color(0xff242424), 165 | fontSize = 28.sp, 166 | fontWeight = FontWeight.SemiBold 167 | ), 168 | modifier = Modifier.padding(horizontal = 32.dp) 169 | ) 170 | Row(horizontalArrangement = Arrangement.SpaceEvenly) { 171 | ActivityCard( 172 | text = "List of Schedule", 173 | backgroundColor = Color(0xffFCCA9B), 174 | imageBackgroundColor = Color(0xffFBB97C), 175 | modifier = Modifier.padding(start = 16.dp, end = 8.dp, top = 24.dp, bottom = 24.dp) 176 | .preferredHeight(100.dp) 177 | ) 178 | 179 | ActivityCard( 180 | text = "Doctor's Daily Post", 181 | backgroundColor = Color(0xffA5A5A5), 182 | imageBackgroundColor = Color(0xffBBBBBB), 183 | modifier = Modifier.padding(start = 8.dp, end = 16.dp, top = 24.dp, bottom = 24.dp) 184 | .preferredHeight(100.dp) 185 | ) 186 | } 187 | } 188 | 189 | @Composable 190 | fun ActivityCard( 191 | text: String, 192 | backgroundColor: Color, 193 | imageBackgroundColor: Color, 194 | modifier: Modifier = Modifier 195 | ) { 196 | Box( 197 | backgroundColor = backgroundColor, 198 | shape = RoundedCornerShape(20.dp), 199 | modifier = modifier 200 | ) { 201 | Row( 202 | modifier = Modifier.fillMaxHeight(), 203 | horizontalArrangement = Arrangement.Center, 204 | verticalGravity = ContentGravity.CenterVertically 205 | ) { 206 | Image( 207 | asset = imageResource(id = Drawables.list), modifier = Modifier 208 | .padding(end = 8.dp, start = 16.dp, top = 16.dp, bottom = 16.dp).background( 209 | color = imageBackgroundColor, 210 | shape = RoundedCornerShape(16.dp) 211 | ).padding(8.dp) 212 | ) 213 | Text( 214 | text = text, style = TextStyle( 215 | color = Color.White, 216 | fontSize = 17.sp 217 | ), 218 | modifier = Modifier.padding(end = 16.dp, start = 8.dp, top = 16.dp, bottom = 16.dp) 219 | ) 220 | } 221 | } 222 | } --------------------------------------------------------------------------------