├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── devsadeq
│ │ └── composecinematicketsreservations
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── devsadeq
│ │ │ └── composecinematicketsreservations
│ │ │ ├── CinemaApplication.kt
│ │ │ ├── ui
│ │ │ ├── composable
│ │ │ │ ├── ActorsImages.kt
│ │ │ │ ├── AppChip.kt
│ │ │ │ ├── BlurBackground.kt
│ │ │ │ ├── CustomButton.kt
│ │ │ │ ├── DayItem.kt
│ │ │ │ ├── DetailsBackgroundImage.kt
│ │ │ │ ├── DetailsBottomSheet.kt
│ │ │ │ ├── DetailsDescription.kt
│ │ │ │ ├── DetailsHeader.kt
│ │ │ │ ├── HomeFilterChips.kt
│ │ │ │ ├── HomeOverview.kt
│ │ │ │ ├── HomePager.kt
│ │ │ │ ├── MovieCategories.kt
│ │ │ │ ├── MovieDetailsTitle.kt
│ │ │ │ ├── MovieInfoText.kt
│ │ │ │ ├── MovieItem.kt
│ │ │ │ ├── MovieStatistics.kt
│ │ │ │ ├── ReservationDays.kt
│ │ │ │ ├── ReservationFooter.kt
│ │ │ │ ├── ReservationPriceAndSubmitButton.kt
│ │ │ │ ├── ReservationScreenHeader.kt
│ │ │ │ ├── ReservationSeats.kt
│ │ │ │ ├── ReservationTimes.kt
│ │ │ │ ├── RoundedBannerImage.kt
│ │ │ │ ├── SeatItem.kt
│ │ │ │ ├── SeatPair.kt
│ │ │ │ ├── SeatStatusIndicator.kt
│ │ │ │ ├── SeatsGrid.kt
│ │ │ │ ├── SeatsIndicators.kt
│ │ │ │ └── TimeItem.kt
│ │ │ ├── main
│ │ │ │ ├── AppNavGraph.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── MainScreen.kt
│ │ │ │ └── Screen.kt
│ │ │ ├── screen
│ │ │ │ ├── cart
│ │ │ │ │ └── CartScreen.kt
│ │ │ │ ├── details
│ │ │ │ │ └── DetailsScreen.kt
│ │ │ │ ├── home
│ │ │ │ │ └── HomeScreen.kt
│ │ │ │ ├── profile
│ │ │ │ │ └── ProfileScreen.kt
│ │ │ │ ├── reservation
│ │ │ │ │ └── ReservationScreen.kt
│ │ │ │ └── search
│ │ │ │ │ └── SearchScreen.kt
│ │ │ └── theme
│ │ │ │ ├── Color.kt
│ │ │ │ ├── Theme.kt
│ │ │ │ └── Type.kt
│ │ │ └── viewmodel
│ │ │ ├── details
│ │ │ ├── DetailsUIState.kt
│ │ │ └── DetailsViewModel.kt
│ │ │ ├── home
│ │ │ ├── HomeUIState.kt
│ │ │ └── HomeViewModel.kt
│ │ │ └── reservation
│ │ │ ├── ReservationUIState.kt
│ │ │ └── ReservationViewModel.kt
│ └── res
│ │ ├── drawable
│ │ ├── actor_1.jpg
│ │ ├── actor_2.jpg
│ │ ├── actor_3.webp
│ │ ├── actor_4.jpg
│ │ ├── actor_5.jpg
│ │ ├── actor_6.jpg
│ │ ├── actor_7.jpg
│ │ ├── actor_8.jpg
│ │ ├── banner.jpg
│ │ ├── ic_clock.xml
│ │ ├── ic_close_circle.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_play.xml
│ │ ├── ic_profile.xml
│ │ ├── ic_search.xml
│ │ ├── ic_ticket.xml
│ │ ├── ic_video_play.xml
│ │ ├── movie1.png
│ │ ├── movie2.png
│ │ ├── movie3.png
│ │ ├── seat.xml
│ │ └── seat_belt.xml
│ │ ├── font
│ │ ├── opensans_medium.ttf
│ │ └── opensans_regular.ttf
│ │ ├── mipmap-anydpi
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── devsadeq
│ └── composecinematicketsreservations
│ └── ExampleUnitTest.kt
├── build.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle files
2 | .gradle/
3 | build/
4 |
5 | # Local configuration file (sdk path, etc)
6 | local.properties
7 |
8 | # Log/OS Files
9 | *.log
10 |
11 | # Android Studio generated files and folders
12 | captures/
13 | .externalNativeBuild/
14 | .cxx/
15 | *.apk
16 | output.json
17 |
18 | # IntelliJ
19 | *.iml
20 | .idea/
21 | misc.xml
22 | deploymentTargetDropDown.xml
23 | render.experimental.xml
24 |
25 | # Keystore files
26 | *.jks
27 | *.keystore
28 |
29 | # Google Services (e.g. APIs or Firebase)
30 | google-services.json
31 |
32 | # Android Profiling
33 | *.hprof
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Compose Cinema Tickets Reservations App🎬
2 |
3 | Welcome to the Compose Cinema Tickets Reservations app! This app lets you book cinema tickets with ease, using the awesome power of Jetpack Compose. It has 3 screens.
4 |
5 | ### Features:
6 | - **Animated Slider:** Enjoy a cool animated slider that gives you sneak peeks into the most exciting movies.
7 | - **Intuitive Seat Selection:** Easily pick your seats for the movie you want to watch. You can select multiple seats at once.
8 | - **Smooth Animations:** Experience seamless and smooth interactions with our app's animations.
9 |
10 | ## Demo Video 📽️
11 | To see the app in action, check out the demo video [here](https://youtube.com/shorts/iiZLfVxJowc?feature=share)!
12 |
13 | ## Screenshots 📸
14 |
19 |
20 | ## Keywords
21 | Jetpack Compose, Cinema Tickets, Reservations, Animated Slider, Seat Selection, User-Friendly, Smooth Animations, Android App, Blockbuster Movies, Booking Experience, UI Interactions.
22 |
23 | ## Contact
24 | - Email: dev.sadeq@gmail.com
25 | - Linkedin: [@devsadeq](https://www.linkedin.com/in/devsadeq/)
26 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | @Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
2 | plugins {
3 | alias(libs.plugins.androidApplication)
4 | alias(libs.plugins.kotlinAndroid)
5 | alias(libs.plugins.kotlinKapt)
6 | alias(libs.plugins.hilt)
7 | }
8 |
9 | android {
10 | namespace = "com.devsadeq.composecinematicketsreservations"
11 | compileSdk = 33
12 |
13 | defaultConfig {
14 | applicationId = "com.devsadeq.composecinematicketsreservations"
15 | minSdk = 28
16 | targetSdk = 33
17 | versionCode = 1
18 | versionName = "1.0"
19 |
20 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
21 | vectorDrawables {
22 | useSupportLibrary = true
23 | }
24 | }
25 |
26 | buildTypes {
27 | release {
28 | isMinifyEnabled = false
29 | proguardFiles(
30 | getDefaultProguardFile("proguard-android-optimize.txt"),
31 | "proguard-rules.pro"
32 | )
33 | }
34 | }
35 | compileOptions {
36 | sourceCompatibility = JavaVersion.VERSION_17
37 | targetCompatibility = JavaVersion.VERSION_17
38 | }
39 | kotlinOptions {
40 | jvmTarget = "17"
41 | }
42 | buildFeatures {
43 | compose = true
44 | }
45 | composeOptions {
46 | kotlinCompilerExtensionVersion = "1.4.3"
47 | }
48 | packaging {
49 | resources {
50 | excludes += "/META-INF/{AL2.0,LGPL2.1}"
51 | }
52 | }
53 | }
54 |
55 | dependencies {
56 |
57 | implementation(libs.core.ktx)
58 | implementation(libs.lifecycle.runtime.ktx)
59 | implementation(libs.activity.compose)
60 | implementation(platform(libs.compose.bom))
61 | implementation(libs.ui)
62 | implementation(libs.ui.graphics)
63 | implementation(libs.ui.tooling.preview)
64 | implementation(libs.material3)
65 | testImplementation(libs.junit)
66 | androidTestImplementation(libs.androidx.test.ext.junit)
67 | androidTestImplementation(libs.espresso.core)
68 | androidTestImplementation(platform(libs.compose.bom))
69 | androidTestImplementation(libs.ui.test.junit4)
70 | debugImplementation(libs.ui.tooling)
71 | debugImplementation(libs.ui.test.manifest)
72 |
73 | implementation(libs.lifecycle.viewmodel)
74 | implementation(libs.hilt.android)
75 | implementation(libs.hilt.navigation)
76 | kapt(libs.hilt.android.compiler)
77 | implementation(libs.coil.compose)
78 | implementation(libs.compose.ui.util)
79 | implementation(libs.navigation.compose)
80 | implementation(libs.compose.material)
81 | implementation(libs.hilt.navigation.compose)
82 | }
--------------------------------------------------------------------------------
/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/androidTest/java/com/devsadeq/composecinematicketsreservations/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations
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.devsadeq.composecinematicketsreservations", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/CinemaApplication.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 | @HiltAndroidApp
7 | class CinemaApplication : Application()
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ActorsImages.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.PaddingValues
6 | import androidx.compose.foundation.layout.Spacer
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.foundation.layout.size
9 | import androidx.compose.foundation.layout.width
10 | import androidx.compose.foundation.lazy.LazyRow
11 | import androidx.compose.foundation.shape.RoundedCornerShape
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.layout.ContentScale
16 | import androidx.compose.ui.res.painterResource
17 | import androidx.compose.ui.unit.dp
18 |
19 | @Composable
20 | fun ActorsImages(
21 | actors: List
22 | ) {
23 | LazyRow(
24 | modifier = Modifier.padding(vertical = 16.dp),
25 | horizontalArrangement = Arrangement.Center,
26 | contentPadding = PaddingValues(horizontal = 24.dp),
27 | ) {
28 | items(10) {
29 | Image(
30 | painter = painterResource(actors[it]),
31 | contentDescription = null,
32 | modifier = Modifier
33 | .size(80.dp)
34 | .clip(RoundedCornerShape(100.dp)),
35 | contentScale = ContentScale.Crop,
36 | )
37 | Spacer(modifier = Modifier.width(6.dp))
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/AppChip.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.BorderStroke
4 | import androidx.compose.foundation.layout.PaddingValues
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material.Chip
8 | import androidx.compose.material.ChipDefaults
9 | import androidx.compose.material.ExperimentalMaterialApi
10 | import androidx.compose.material3.Text
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.text.TextStyle
15 | import androidx.compose.ui.unit.dp
16 | import androidx.compose.ui.unit.sp
17 | import com.devsadeq.composecinematicketsreservations.ui.theme.Grey
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.Orange
19 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
20 |
21 |
22 | @OptIn(ExperimentalMaterialApi::class)
23 | @Composable
24 | fun AppChip(
25 | label: String,
26 | onClick: () -> Unit,
27 | modifier: Modifier = Modifier,
28 | enabled: Boolean = false,
29 | labelPadding: PaddingValues = PaddingValues(8.dp),
30 | borderColor: Color = Grey,
31 | labelStyle: TextStyle = TextStyle(
32 | fontSize = 14.sp,
33 | letterSpacing = 0.15.sp,
34 | color = White
35 | )
36 | ) {
37 | Chip(
38 | onClick = onClick,
39 | modifier = modifier,
40 | shape = RoundedCornerShape(50.dp),
41 | colors = ChipDefaults.chipColors(
42 | backgroundColor = Orange,
43 | disabledBackgroundColor = Color.Transparent,
44 | ),
45 | enabled = enabled,
46 | border = if (enabled.not()) BorderStroke(1.dp, borderColor) else null,
47 | ) {
48 | Text(
49 | text = label,
50 | modifier = Modifier.padding(labelPadding),
51 | style = labelStyle,
52 | )
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/BlurBackground.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.fillMaxSize
5 | import androidx.compose.foundation.layout.offset
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.draw.blur
9 | import androidx.compose.ui.res.painterResource
10 | import androidx.compose.ui.unit.dp
11 |
12 | @Composable
13 | fun BlurBackground(
14 | image: Int
15 | ) {
16 | Image(
17 | painter = painterResource(image),
18 | contentDescription = null,
19 | modifier = Modifier
20 | .fillMaxSize()
21 | .blur(80.dp)
22 | .offset(y = (-300).dp)
23 | )
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/CustomButton.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Row
4 | import androidx.compose.foundation.layout.Spacer
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.foundation.layout.size
7 | import androidx.compose.foundation.layout.width
8 | import androidx.compose.material3.Button
9 | import androidx.compose.material3.ButtonDefaults
10 | import androidx.compose.material3.Icon
11 | import androidx.compose.material3.Text
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.res.painterResource
15 | import androidx.compose.ui.res.stringResource
16 | import androidx.compose.ui.text.font.FontWeight
17 | import androidx.compose.ui.unit.dp
18 | import androidx.compose.ui.unit.sp
19 | import com.devsadeq.composecinematicketsreservations.R
20 | import com.devsadeq.composecinematicketsreservations.ui.theme.Orange
21 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
22 |
23 | @Composable
24 | fun CustomButton(
25 | icon: Int = R.drawable.ic_ticket,
26 | text: String = stringResource(R.string.booking),
27 | modifier: Modifier = Modifier,
28 | onClick: () -> Unit = {}
29 | ) {
30 | Button(
31 | onClick = onClick,
32 | modifier = modifier,
33 | colors = ButtonDefaults.buttonColors(
34 | containerColor = Orange
35 | )
36 | ) {
37 | Row(
38 | modifier = Modifier.padding(8.dp)
39 | ) {
40 | Icon(
41 | painter = painterResource(icon),
42 | contentDescription = null,
43 | tint = White,
44 | modifier = Modifier.size(28.dp)
45 | )
46 | Spacer(modifier = Modifier.width(8.dp))
47 | Text(
48 | text,
49 | color = White,
50 | fontSize = 18.sp,
51 | fontWeight = FontWeight.Medium
52 | )
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/DayItem.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.shape.RoundedCornerShape
8 | import androidx.compose.material3.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.draw.clip
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.text.font.FontWeight
15 | import androidx.compose.ui.unit.dp
16 | import androidx.compose.ui.unit.sp
17 | import com.devsadeq.composecinematicketsreservations.ui.theme.Black
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.Grey
19 | import com.devsadeq.composecinematicketsreservations.ui.theme.LightGrey
20 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
21 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
22 |
23 |
24 | @Composable
25 | fun DayItem(
26 | dayOfMonth: Int,
27 | dayOfWeek: String,
28 | isSelected: Boolean = false,
29 | ) {
30 | Column(
31 | modifier = Modifier
32 | .border(1.dp, if (isSelected) Grey else LightGrey, RoundedCornerShape(24.dp))
33 | .clip(RoundedCornerShape(24.dp))
34 | .background(if (isSelected) Grey else Color.Transparent)
35 | .padding(vertical = 12.dp, horizontal = 16.dp),
36 | horizontalAlignment = Alignment.CenterHorizontally,
37 | ) {
38 | Text(
39 | text = dayOfMonth.toString(),
40 | fontSize = 24.sp,
41 | fontWeight = FontWeight.Medium,
42 | color = if (isSelected) White else Black
43 | )
44 | Text(
45 | text = dayOfWeek,
46 | color = if (isSelected) White else Grey,
47 | fontSize = 12.sp,
48 | fontWeight = FontWeight.Medium,
49 | fontFamily = OpenSans,
50 | )
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/DetailsBackgroundImage.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.fillMaxSize
5 | import androidx.compose.foundation.layout.offset
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.layout.ContentScale
9 | import androidx.compose.ui.res.painterResource
10 | import androidx.compose.ui.unit.dp
11 | import com.devsadeq.composecinematicketsreservations.R
12 |
13 | @Composable
14 | fun DetailsBackgroundImage(modifier: Modifier = Modifier) {
15 | Image(
16 | painter = painterResource(R.drawable.movie2),
17 | contentDescription = null,
18 | modifier = modifier
19 | .fillMaxSize()
20 | .offset(y = (-200).dp),
21 | contentScale = ContentScale.FillWidth,
22 | )
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/DetailsBottomSheet.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material3.Card
8 | import androidx.compose.material3.CardDefaults
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.draw.clip
13 | import androidx.compose.ui.unit.dp
14 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
15 | import com.devsadeq.composecinematicketsreservations.viewmodel.details.DetailsUIState
16 |
17 | @Composable
18 | fun DetailsBottomSheet(
19 | state: DetailsUIState,
20 | onReserveClicked: () -> Unit,
21 | modifier: Modifier = Modifier
22 | ) {
23 | Card(
24 | modifier = modifier
25 | .fillMaxWidth()
26 | .clip(
27 | RoundedCornerShape(
28 | topStart = 40.dp,
29 | topEnd = 40.dp,
30 | bottomStart = 0.dp,
31 | bottomEnd = 0.dp
32 | )
33 | ),
34 | colors = CardDefaults.cardColors(containerColor = White)
35 | ) {
36 | Column(
37 | modifier = Modifier
38 | .fillMaxWidth()
39 | .padding(vertical = 24.dp),
40 | horizontalAlignment = Alignment.CenterHorizontally,
41 | ) {
42 | MovieStatistics()
43 | MovieTitle()
44 | MovieCategories()
45 | ActorsImages(state.actors)
46 | MovieDescription()
47 | CustomButton(onClick = onReserveClicked, modifier = Modifier.padding(top = 24.dp))
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/DetailsDescription.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.material3.Text
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.res.stringResource
9 | import androidx.compose.ui.text.font.FontWeight
10 | import androidx.compose.ui.text.style.TextAlign
11 | import androidx.compose.ui.text.style.TextOverflow
12 | import androidx.compose.ui.unit.dp
13 | import androidx.compose.ui.unit.sp
14 | import com.devsadeq.composecinematicketsreservations.R
15 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
16 |
17 |
18 | @Composable
19 | fun MovieDescription() {
20 | Text(
21 | stringResource(R.string.details_description),
22 | modifier = Modifier
23 | .fillMaxWidth()
24 | .padding(horizontal = 24.dp),
25 | fontFamily = OpenSans,
26 | fontWeight = FontWeight.Medium,
27 | maxLines = 3,
28 | textAlign = TextAlign.Center,
29 | overflow = TextOverflow.Ellipsis,
30 | fontSize = 14.sp,
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/DetailsHeader.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.layout.Arrangement
6 | import androidx.compose.foundation.layout.Box
7 | import androidx.compose.foundation.layout.Column
8 | import androidx.compose.foundation.layout.Row
9 | import androidx.compose.foundation.layout.Spacer
10 | import androidx.compose.foundation.layout.fillMaxHeight
11 | import androidx.compose.foundation.layout.fillMaxSize
12 | import androidx.compose.foundation.layout.fillMaxWidth
13 | import androidx.compose.foundation.layout.height
14 | import androidx.compose.foundation.layout.padding
15 | import androidx.compose.foundation.layout.size
16 | import androidx.compose.foundation.shape.RoundedCornerShape
17 | import androidx.compose.material3.Icon
18 | import androidx.compose.material3.IconButton
19 | import androidx.compose.material3.Text
20 | import androidx.compose.runtime.Composable
21 | import androidx.compose.ui.Alignment
22 | import androidx.compose.ui.Modifier
23 | import androidx.compose.ui.draw.clip
24 | import androidx.compose.ui.res.painterResource
25 | import androidx.compose.ui.res.stringResource
26 | import androidx.compose.ui.text.style.TextAlign
27 | import androidx.compose.ui.unit.dp
28 | import androidx.compose.ui.unit.sp
29 | import com.devsadeq.composecinematicketsreservations.R
30 | import com.devsadeq.composecinematicketsreservations.ui.theme.Orange
31 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
32 |
33 |
34 | @Composable
35 | fun DetailsHeader(
36 | onCloseClicked: () -> Unit
37 | ) {
38 | Column(
39 | modifier = Modifier.fillMaxHeight(),
40 | horizontalAlignment = Alignment.CenterHorizontally,
41 | ) {
42 | Row(
43 | modifier = Modifier
44 | .fillMaxWidth()
45 | .padding(vertical = 24.dp, horizontal = 18.dp),
46 | horizontalArrangement = Arrangement.SpaceBetween,
47 | verticalAlignment = Alignment.CenterVertically,
48 | ) {
49 | Box(
50 | modifier = Modifier
51 | .clip(RoundedCornerShape(30.dp))
52 | .background(White.copy(alpha = 0.3f))
53 | .clickable { onCloseClicked() }
54 | ) {
55 | Icon(
56 | painter = painterResource(R.drawable.ic_close_circle),
57 | contentDescription = null,
58 | modifier = Modifier
59 | .padding(8.dp)
60 | .size(28.dp),
61 | tint = White,
62 | )
63 | }
64 | Box(
65 | modifier = Modifier
66 | .clip(RoundedCornerShape(30.dp))
67 | .background(White.copy(alpha = 0.3f))
68 | ) {
69 | Row(
70 | modifier = Modifier
71 | .padding(8.dp)
72 | .align(Alignment.TopCenter),
73 | verticalAlignment = Alignment.CenterVertically,
74 | ) {
75 | Icon(
76 | painter = painterResource(R.drawable.ic_clock),
77 | contentDescription = null,
78 | modifier = Modifier
79 | .padding(end = 4.dp)
80 | .size(18.dp),
81 | tint = White,
82 | )
83 | Text(
84 | stringResource(R.string._2h_23m),
85 | modifier = Modifier.padding(end = 4.dp),
86 | color = White,
87 | textAlign = TextAlign.Center,
88 | fontSize = 14.sp
89 | )
90 | }
91 | }
92 | }
93 | Spacer(modifier = Modifier.height(110.dp))
94 | IconButton(
95 | onClick = {},
96 | modifier = Modifier.size(65.dp),
97 | ) {
98 | Box(
99 | modifier = Modifier
100 | .fillMaxSize()
101 | .clip(RoundedCornerShape(100.dp))
102 | .background(Orange),
103 | contentAlignment = Alignment.Center
104 | ) {
105 | Icon(
106 | painter = painterResource(id = R.drawable.ic_play),
107 | tint = White,
108 | contentDescription = "",
109 | modifier = Modifier.size(30.dp)
110 | )
111 | }
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/HomeFilterChips.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.Spacer
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.layout.height
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.layout.width
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.res.stringResource
13 | import androidx.compose.ui.unit.dp
14 | import com.devsadeq.composecinematicketsreservations.R
15 |
16 |
17 | @Composable
18 | fun HomeFilterChips(modifier: Modifier = Modifier) {
19 | Row(
20 | modifier = modifier
21 | .fillMaxWidth()
22 | .padding(top = 36.dp, bottom = 28.dp),
23 | horizontalArrangement = Arrangement.Center
24 | ) {
25 | AppChip(
26 | label = stringResource(R.string.now_showing),
27 | onClick = {},
28 | enabled = true,
29 | modifier = Modifier.height(40.dp)
30 | )
31 | Spacer(modifier = Modifier.width(8.dp))
32 | AppChip(
33 | label = stringResource(R.string.coming_soon),
34 | onClick = {},
35 | enabled = false,
36 | modifier = Modifier.height(40.dp)
37 | )
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/HomeOverview.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.ExperimentalFoundationApi
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.PaddingValues
7 | import androidx.compose.foundation.layout.Row
8 | import androidx.compose.foundation.layout.Spacer
9 | import androidx.compose.foundation.layout.fillMaxWidth
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.foundation.layout.size
12 | import androidx.compose.foundation.layout.width
13 | import androidx.compose.foundation.pager.PagerState
14 | import androidx.compose.material3.Icon
15 | import androidx.compose.material3.MaterialTheme
16 | import androidx.compose.material3.Text
17 | import androidx.compose.runtime.Composable
18 | import androidx.compose.ui.Alignment
19 | import androidx.compose.ui.Modifier
20 | import androidx.compose.ui.res.painterResource
21 | import androidx.compose.ui.text.font.FontWeight
22 | import androidx.compose.ui.text.style.TextAlign
23 | import androidx.compose.ui.unit.dp
24 | import androidx.compose.ui.unit.sp
25 | import com.devsadeq.composecinematicketsreservations.R
26 | import com.devsadeq.composecinematicketsreservations.ui.theme.DarkGrey
27 | import com.devsadeq.composecinematicketsreservations.ui.theme.Grey
28 | import com.devsadeq.composecinematicketsreservations.ui.theme.LightGrey
29 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
30 | import com.devsadeq.composecinematicketsreservations.viewmodel.home.HomeUIState
31 |
32 |
33 | @OptIn(ExperimentalFoundationApi::class)
34 | @Composable
35 | fun HomeOverview(
36 | state: HomeUIState,
37 | pagerState: PagerState,
38 | ) {
39 | Column(
40 | modifier = Modifier.padding(vertical = 36.dp, horizontal = 60.dp),
41 | horizontalAlignment = Alignment.CenterHorizontally,
42 | ) {
43 | Row(
44 | verticalAlignment = Alignment.CenterVertically,
45 | ) {
46 | Icon(
47 | painter = painterResource(R.drawable.ic_clock),
48 | contentDescription = null,
49 | tint = Grey,
50 | modifier = Modifier.size(16.dp)
51 | )
52 | Text(
53 | text = state.movies[pagerState.settledPage].duration,
54 | fontWeight = FontWeight.Medium,
55 | fontSize = 14.sp,
56 | modifier = Modifier.padding(start = 4.dp),
57 | )
58 | }
59 | Text(
60 | text = state.movies[pagerState.settledPage].title.replaceFirstChar { it.uppercase() },
61 | fontFamily = OpenSans,
62 | fontWeight = FontWeight.Medium,
63 | fontSize = 24.sp,
64 | modifier = Modifier.padding(vertical = 8.dp),
65 | textAlign = TextAlign.Center,
66 | lineHeight = 32.sp
67 | )
68 | Row(
69 | modifier = Modifier
70 | .fillMaxWidth(),
71 | horizontalArrangement = Arrangement.Center,
72 | ) {
73 | state.movies[pagerState.settledPage].genres.forEach { genre ->
74 | AppChip(
75 | label = genre,
76 | onClick = {},
77 | labelPadding = PaddingValues(2.dp),
78 | borderColor = LightGrey,
79 | labelStyle = MaterialTheme.typography.labelMedium.copy(
80 | fontSize = 14.sp,
81 | letterSpacing = 0.15.sp,
82 | color = DarkGrey,
83 | fontWeight = FontWeight.Bold
84 | )
85 | )
86 | Spacer(modifier = Modifier.width(4.dp))
87 | }
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/HomePager.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.animation.core.animateFloatAsState
4 | import androidx.compose.foundation.ExperimentalFoundationApi
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.layout.PaddingValues
7 | import androidx.compose.foundation.pager.HorizontalPager
8 | import androidx.compose.foundation.pager.PagerState
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.draw.scale
12 | import androidx.compose.ui.unit.dp
13 | import com.devsadeq.composecinematicketsreservations.viewmodel.home.HomeUIState
14 |
15 | @OptIn(ExperimentalFoundationApi::class)
16 | @Composable
17 | fun HomePager(
18 | images: List,
19 | modifier: Modifier = Modifier,
20 | pagerState: PagerState,
21 | onItemClicked: () -> Unit
22 | ) {
23 | HorizontalPager(
24 | pageCount = images.size,
25 | contentPadding = PaddingValues(horizontal = 60.dp),
26 | pageSpacing = (-15).dp,
27 | state = pagerState,
28 | ) { page ->
29 | val scale = animateFloatAsState(
30 | targetValue = if (page == pagerState.currentPage) 1.0f else 0.8f,
31 | label = ""
32 | ).value
33 |
34 | MovieItem(
35 | image = images[page].imageRes,
36 | modifier = modifier
37 | .scale(scale)
38 | .clickable { onItemClicked() }
39 | )
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/MovieCategories.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.PaddingValues
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.Spacer
6 | import androidx.compose.foundation.layout.width
7 | import androidx.compose.foundation.layout.wrapContentSize
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.res.stringResource
11 | import androidx.compose.ui.text.TextStyle
12 | import androidx.compose.ui.text.font.FontWeight
13 | import androidx.compose.ui.unit.dp
14 | import androidx.compose.ui.unit.sp
15 | import com.devsadeq.composecinematicketsreservations.R
16 | import com.devsadeq.composecinematicketsreservations.ui.theme.DarkGrey
17 | import com.devsadeq.composecinematicketsreservations.ui.theme.LightGrey
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
19 |
20 |
21 | @Composable
22 | fun MovieCategories() {
23 | Row(
24 | modifier = Modifier.wrapContentSize(),
25 | ) {
26 | AppChip(
27 | label = stringResource(R.string.fantasy),
28 | onClick = {},
29 | labelPadding = PaddingValues(2.dp),
30 | borderColor = LightGrey,
31 | labelStyle = TextStyle().copy(
32 | fontFamily = OpenSans,
33 | fontSize = 16.sp,
34 | letterSpacing = 0.15.sp,
35 | color = DarkGrey,
36 | fontWeight = FontWeight.SemiBold
37 | )
38 | )
39 | Spacer(modifier = Modifier.width(4.dp))
40 | AppChip(
41 | label = stringResource(R.string.adventure),
42 | onClick = {},
43 | labelPadding = PaddingValues(2.dp),
44 | borderColor = LightGrey,
45 | labelStyle = TextStyle().copy(
46 | fontFamily = OpenSans,
47 | fontSize = 16.sp,
48 | letterSpacing = 0.15.sp,
49 | color = DarkGrey,
50 | fontWeight = FontWeight.SemiBold
51 | )
52 | )
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/MovieDetailsTitle.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.padding
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.res.stringResource
8 | import androidx.compose.ui.text.font.FontWeight
9 | import androidx.compose.ui.text.style.TextAlign
10 | import androidx.compose.ui.unit.dp
11 | import androidx.compose.ui.unit.sp
12 | import com.devsadeq.composecinematicketsreservations.R
13 |
14 | @Composable
15 | fun MovieTitle() {
16 | Text(
17 | text = stringResource(R.string.fantastic_beasts_the_secrets_of_dumbledore).replaceFirstChar { it.uppercase() },
18 | fontWeight = FontWeight.Medium,
19 | fontSize = 28.sp,
20 | lineHeight = 38.sp,
21 | modifier = Modifier.padding(vertical = 16.dp, horizontal = 24.dp),
22 | textAlign = TextAlign.Center,
23 | )
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/MovieInfoText.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.material3.Text
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.text.font.FontWeight
10 | import androidx.compose.ui.text.style.TextAlign
11 | import androidx.compose.ui.unit.sp
12 | import com.devsadeq.composecinematicketsreservations.ui.theme.Black
13 | import com.devsadeq.composecinematicketsreservations.ui.theme.Grey
14 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
15 |
16 | @Composable
17 | fun DetailsInfoText(
18 | title: String,
19 | subtitle: String,
20 | isRating: Boolean = false,
21 | ) {
22 | Column(
23 | horizontalAlignment = Alignment.CenterHorizontally,
24 | ) {
25 | Row(
26 | horizontalArrangement = Arrangement.Center,
27 | ) {
28 | Text(
29 | title,
30 | fontSize = 20.sp,
31 | fontWeight = FontWeight.Medium,
32 | color = Black,
33 | textAlign = TextAlign.Center,
34 | fontFamily = OpenSans
35 | )
36 | if (isRating) Text(
37 | "/10",
38 | fontSize = 20.sp,
39 | fontWeight = FontWeight.Medium,
40 | color = Grey,
41 | fontFamily = OpenSans
42 | )
43 | }
44 | Text(
45 | subtitle,
46 | fontSize = 16.sp,
47 | fontWeight = FontWeight.Normal,
48 | color = Grey,
49 | textAlign = TextAlign.Center,
50 | fontFamily = OpenSans
51 | )
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/MovieItem.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.height
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.draw.clip
10 | import androidx.compose.ui.layout.ContentScale
11 | import androidx.compose.ui.res.painterResource
12 | import androidx.compose.ui.tooling.preview.Preview
13 | import androidx.compose.ui.unit.dp
14 | import com.devsadeq.composecinematicketsreservations.R
15 |
16 | @Composable
17 | fun MovieItem(
18 | image: Int,
19 | modifier: Modifier = Modifier,
20 | ) {
21 | Image(
22 | painter = painterResource(image),
23 | contentDescription = null,
24 | modifier = modifier
25 | .fillMaxWidth()
26 | .height(550.dp)
27 | .clip(RoundedCornerShape(30.dp)),
28 | contentScale = ContentScale.Crop,
29 | )
30 | }
31 |
32 | @Preview(showBackground = true)
33 | @Composable
34 | fun MovieItemPreview() {
35 | MovieItem(image = R.drawable.movie1)
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/MovieStatistics.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.res.stringResource
10 | import androidx.compose.ui.unit.dp
11 | import com.devsadeq.composecinematicketsreservations.R
12 |
13 | @Composable
14 | fun MovieStatistics() {
15 | Row(
16 | modifier = Modifier
17 | .fillMaxWidth()
18 | .padding(horizontal = 24.dp),
19 | horizontalArrangement = Arrangement.SpaceEvenly,
20 | ) {
21 | DetailsInfoText(stringResource(R.string._6_8), stringResource(R.string.imdb), true)
22 | DetailsInfoText(stringResource(R.string._36), stringResource(R.string.rotten_tomatoes))
23 | DetailsInfoText(stringResource(R.string._4), stringResource(R.string.ign), true)
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ReservationDays.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.PaddingValues
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.lazy.LazyRow
7 | import androidx.compose.foundation.lazy.items
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.unit.dp
11 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.ReservationUIState
12 |
13 | @Composable
14 | fun ReservationDays(state: ReservationUIState) {
15 | LazyRow(
16 | modifier = Modifier.fillMaxWidth(),
17 | contentPadding = PaddingValues(horizontal = 18.dp, vertical = 5.dp),
18 | horizontalArrangement = Arrangement.spacedBy(4.dp),
19 | ) {
20 | items(state.days) {
21 | DayItem(
22 | dayOfMonth = it.dayOfMonth,
23 | dayOfWeek = it.dayOfWeek,
24 | isSelected = it.isSelected
25 | )
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ReservationFooter.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material3.Card
8 | import androidx.compose.material3.CardDefaults
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.draw.clip
13 | import androidx.compose.ui.unit.dp
14 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
15 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.ReservationUIState
16 |
17 | @Composable
18 | fun ReservationScreenFooter(
19 | state: ReservationUIState,
20 | modifier: Modifier = Modifier,
21 | ) {
22 | Card(
23 | modifier = modifier
24 | .fillMaxWidth()
25 | .clip(
26 | RoundedCornerShape(
27 | topStart = 40.dp,
28 | topEnd = 40.dp,
29 | bottomStart = 0.dp,
30 | bottomEnd = 0.dp
31 | )
32 | ),
33 | colors = CardDefaults.cardColors(
34 | containerColor = White
35 | )
36 | ) {
37 | Column(
38 | modifier = Modifier
39 | .fillMaxWidth()
40 | .padding(vertical = 30.dp),
41 | horizontalAlignment = Alignment.CenterHorizontally,
42 | ) {
43 | ReservationDays(state)
44 | ReservationTimes(state)
45 | ReservationPriceAndSubmitButton()
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ReservationPriceAndSubmitButton.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.material3.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.res.stringResource
13 | import androidx.compose.ui.text.font.FontWeight
14 | import androidx.compose.ui.tooling.preview.Preview
15 | import androidx.compose.ui.unit.dp
16 | import androidx.compose.ui.unit.sp
17 | import com.devsadeq.composecinematicketsreservations.R
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.Black
19 | import com.devsadeq.composecinematicketsreservations.ui.theme.DarkGrey
20 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
21 |
22 | @Composable
23 | fun ReservationPriceAndSubmitButton() {
24 | Row(
25 | modifier = Modifier
26 | .fillMaxWidth()
27 | .padding(horizontal = 16.dp)
28 | .padding(top = 20.dp, bottom = 10.dp),
29 | verticalAlignment = Alignment.CenterVertically,
30 | horizontalArrangement = Arrangement.SpaceBetween,
31 | ) {
32 | Column {
33 | Text(
34 | text = stringResource(R.string._100_00),
35 | fontSize = 36.sp,
36 | fontWeight = FontWeight.Medium,
37 | fontFamily = OpenSans,
38 | color = Black
39 | )
40 | Text(
41 | text = stringResource(R.string._4_tickets),
42 | fontSize = 14.sp,
43 | fontWeight = FontWeight.Normal,
44 | fontFamily = OpenSans,
45 | color = DarkGrey
46 | )
47 | }
48 | CustomButton(
49 | icon = R.drawable.ic_ticket,
50 | text = stringResource(R.string.buy_tickets),
51 | )
52 | }
53 | }
54 |
55 | @Preview
56 | @Composable
57 | fun ReservationPriceAndSubmitButtonPreview() {
58 | ReservationPriceAndSubmitButton()
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ReservationScreenHeader.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.foundation.layout.size
9 | import androidx.compose.foundation.shape.RoundedCornerShape
10 | import androidx.compose.material3.Icon
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.draw.clip
14 | import androidx.compose.ui.res.painterResource
15 | import androidx.compose.ui.unit.dp
16 | import com.devsadeq.composecinematicketsreservations.R
17 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
18 |
19 |
20 | @Composable
21 | fun ReservationScreenHeader(modifier: Modifier, onCloseClicked: () -> Unit) {
22 | Column(
23 | modifier = modifier.padding(vertical = 16.dp, horizontal = 16.dp),
24 | ) {
25 | Box(
26 | modifier = Modifier
27 | .clip(RoundedCornerShape(30.dp))
28 | .background(White.copy(alpha = 0.3f))
29 | .clickable { onCloseClicked() }
30 | ) {
31 | Icon(
32 | painter = painterResource(R.drawable.ic_close_circle),
33 | contentDescription = null,
34 | modifier = Modifier
35 | .padding(8.dp)
36 | .size(28.dp),
37 | tint = White,
38 | )
39 | }
40 | RoundedBannerImage()
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ReservationSeats.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.SeatUIState
7 |
8 | @Composable
9 | fun ReservationScreenSeats(
10 | seatsPairs: List>,
11 | onSeatClick: (id: Int) -> Unit,
12 | modifier: Modifier = Modifier
13 | ) {
14 | Column(
15 | modifier = modifier
16 | ) {
17 | SeatsGrid(seatsPairs = seatsPairs, onSeatClick = onSeatClick)
18 | SeatsIndicators()
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/ReservationTimes.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.PaddingValues
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.lazy.LazyRow
7 | import androidx.compose.foundation.lazy.items
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.unit.dp
11 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.ReservationUIState
12 |
13 | @Composable
14 | fun ReservationTimes(state: ReservationUIState) {
15 | LazyRow(
16 | modifier = Modifier.fillMaxWidth(),
17 | contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
18 | horizontalArrangement = Arrangement.spacedBy(4.dp),
19 | ) {
20 | items(state.times) {
21 | TimeItem(it.time, it.isSelected)
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/RoundedBannerImage.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.height
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.draw.drawWithContent
10 | import androidx.compose.ui.graphics.Path
11 | import androidx.compose.ui.graphics.drawscope.clipPath
12 | import androidx.compose.ui.graphics.graphicsLayer
13 | import androidx.compose.ui.layout.ContentScale
14 | import androidx.compose.ui.res.painterResource
15 | import androidx.compose.ui.unit.dp
16 | import com.devsadeq.composecinematicketsreservations.R
17 |
18 | @Composable
19 | fun RoundedBannerImage(modifier: Modifier = Modifier) {
20 | Image(
21 | painter = painterResource(id = R.drawable.banner),
22 | contentDescription = "",
23 | modifier = modifier
24 | .fillMaxWidth()
25 | .height(170.dp)
26 | .padding(16.dp)
27 | .drawWithContent {
28 | val path = Path().apply {
29 | val yRatio = 0.35f
30 | moveTo(0f, size.height * yRatio)
31 | lineTo(0f, size.height)
32 | quadraticBezierTo(
33 | size.width / 2,
34 | size.height * 0.6f,
35 | size.width,
36 | size.height
37 | )
38 | lineTo(size.width, size.height * yRatio)
39 | quadraticBezierTo(
40 | size.width / 2,
41 | 0f,
42 | 0f,
43 | size.height * yRatio,
44 | )
45 | }
46 | clipPath(path = path) {
47 | this@drawWithContent.drawContent()
48 | }
49 | }
50 | .graphicsLayer { this.rotationX = rotationX },
51 | contentScale = ContentScale.FillWidth
52 | )
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/SeatItem.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.clickable
4 | import androidx.compose.foundation.layout.size
5 | import androidx.compose.material.Icon
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.res.painterResource
9 | import androidx.compose.ui.unit.dp
10 | import com.devsadeq.composecinematicketsreservations.R
11 | import com.devsadeq.composecinematicketsreservations.ui.theme.DarkGrey
12 | import com.devsadeq.composecinematicketsreservations.ui.theme.Orange
13 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
14 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.SeatUIState
15 |
16 | @Composable
17 | fun SeatItem(
18 | seatUIState: SeatUIState,
19 | onSeatClick: (id: Int) -> Unit
20 | ) {
21 | Icon(
22 | painterResource(R.drawable.seat),
23 | contentDescription = null,
24 | tint = when {
25 | seatUIState.isReserved -> DarkGrey
26 | seatUIState.isSelected -> Orange
27 | else -> White
28 | },
29 | modifier = Modifier
30 | .size(36.dp)
31 | .clickable(enabled = !seatUIState.isReserved) {
32 | onSeatClick(seatUIState.id)
33 | }
34 | )
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/SeatPair.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.foundation.layout.Spacer
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.height
9 | import androidx.compose.foundation.layout.padding
10 | import androidx.compose.foundation.layout.width
11 | import androidx.compose.material.Icon
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.ui.Alignment
14 | import androidx.compose.ui.Modifier
15 | import androidx.compose.ui.res.painterResource
16 | import androidx.compose.ui.unit.dp
17 | import com.devsadeq.composecinematicketsreservations.R
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.DarkGrey
19 | import com.devsadeq.composecinematicketsreservations.ui.theme.LightOrange
20 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.SeatUIState
21 |
22 |
23 | @Composable
24 | fun SeatPair(
25 | seatPair: Pair,
26 | modifier: Modifier = Modifier,
27 | onSeatClick: (id: Int) -> Unit
28 | ) {
29 | Box(
30 | modifier = modifier,
31 | contentAlignment = Alignment.Center
32 | ) {
33 | Icon(
34 | painter = painterResource(R.drawable.seat_belt), contentDescription = null,
35 | tint = if (seatPair.first.isSelected && seatPair.second.isSelected) LightOrange else DarkGrey,
36 | modifier = Modifier
37 | .fillMaxWidth()
38 | .height(45.dp)
39 | .padding(top = 6.dp),
40 | )
41 | Row(
42 | modifier = Modifier.fillMaxWidth(),
43 | horizontalArrangement = Arrangement.Center
44 | ) {
45 | SeatItem(seatPair.first, onSeatClick = onSeatClick)
46 | Spacer(modifier = Modifier.width(4.dp))
47 | SeatItem(seatPair.second, onSeatClick = onSeatClick)
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/SeatStatusIndicator.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.foundation.layout.Spacer
7 | import androidx.compose.foundation.layout.size
8 | import androidx.compose.foundation.layout.width
9 | import androidx.compose.foundation.shape.CircleShape
10 | import androidx.compose.material3.Text
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.draw.clip
15 | import androidx.compose.ui.graphics.Color
16 | import androidx.compose.ui.text.font.FontWeight
17 | import androidx.compose.ui.unit.dp
18 | import androidx.compose.ui.unit.sp
19 | import com.devsadeq.composecinematicketsreservations.ui.theme.Grey
20 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
21 |
22 |
23 | @Composable
24 | fun SeatStatusIndicator(
25 | label: String,
26 | color: Color
27 | ) {
28 | Row(
29 | verticalAlignment = Alignment.CenterVertically
30 | ) {
31 | Box(
32 | modifier = Modifier
33 | .size(14.dp)
34 | .clip(shape = CircleShape)
35 | .background(color)
36 | )
37 | Spacer(modifier = Modifier.width(8.dp))
38 | Text(
39 | text = label,
40 | color = Grey,
41 | fontFamily = OpenSans,
42 | fontWeight = FontWeight.Medium,
43 | fontSize = 14.sp
44 | )
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/SeatsGrid.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.PaddingValues
5 | import androidx.compose.foundation.layout.padding
6 | import androidx.compose.foundation.lazy.grid.GridCells
7 | import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.draw.rotate
11 | import androidx.compose.ui.unit.dp
12 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.SeatUIState
13 |
14 | @Composable
15 | fun SeatsGrid(
16 | seatsPairs: List>,
17 | onSeatClick: (id: Int) -> Unit
18 | ) {
19 | val leftSeatsIndexes = listOf(0, 3, 6, 9, 12)
20 | val rightSeatsIndexes = listOf(2, 5, 8, 11, 14)
21 |
22 | LazyVerticalGrid(
23 | columns = GridCells.Fixed(3),
24 | contentPadding = PaddingValues(0.dp),
25 | verticalArrangement = Arrangement.spacedBy(8.dp),
26 | ) {
27 | items(seatsPairs.size) { index ->
28 | when (index) {
29 | in leftSeatsIndexes -> SeatPair(
30 | seatsPairs[index],
31 | modifier = Modifier.rotate(10f),
32 | onSeatClick = onSeatClick
33 | )
34 |
35 | in rightSeatsIndexes -> SeatPair(
36 | seatsPairs[index],
37 | modifier = Modifier.rotate(-10f),
38 | onSeatClick = onSeatClick
39 | )
40 |
41 | else -> SeatPair(
42 | seatsPairs[index],
43 | modifier = Modifier.padding(top = 9.dp),
44 | onSeatClick = onSeatClick
45 | )
46 | }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/SeatsIndicators.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.res.stringResource
10 | import androidx.compose.ui.unit.dp
11 | import com.devsadeq.composecinematicketsreservations.R
12 | import com.devsadeq.composecinematicketsreservations.ui.theme.DarkGrey
13 | import com.devsadeq.composecinematicketsreservations.ui.theme.Orange
14 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
15 |
16 | @Composable
17 | fun SeatsIndicators() {
18 | Row(
19 | modifier = Modifier
20 | .fillMaxWidth()
21 | .padding(30.dp),
22 | horizontalArrangement = Arrangement.SpaceBetween,
23 | ) {
24 | SeatStatusIndicator(stringResource(R.string.available), color = White)
25 | SeatStatusIndicator(stringResource(R.string.taken), color = DarkGrey)
26 | SeatStatusIndicator(stringResource(R.string.selected), color = Orange)
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/composable/TimeItem.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.composable
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.shape.RoundedCornerShape
8 | import androidx.compose.material3.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.draw.clip
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.text.font.FontWeight
15 | import androidx.compose.ui.unit.dp
16 | import androidx.compose.ui.unit.sp
17 | import com.devsadeq.composecinematicketsreservations.ui.theme.Black
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.Grey
19 | import com.devsadeq.composecinematicketsreservations.ui.theme.LightGrey
20 | import com.devsadeq.composecinematicketsreservations.ui.theme.OpenSans
21 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
22 |
23 |
24 | @Composable
25 | fun TimeItem(
26 | time: String,
27 | isSelected: Boolean,
28 | ) {
29 | Column(
30 | modifier = Modifier
31 | .clip(RoundedCornerShape(24.dp))
32 | .background(if (isSelected) Grey else Color.Transparent)
33 | .border(1.dp, if (isSelected) Grey else LightGrey, RoundedCornerShape(24.dp)),
34 | horizontalAlignment = Alignment.CenterHorizontally,
35 | ) {
36 | Text(
37 | modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp),
38 | text = time,
39 | fontSize = 18.sp,
40 | fontFamily = OpenSans,
41 | fontWeight = FontWeight.Medium,
42 | color = if (isSelected) White else Black
43 | )
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/main/AppNavGraph.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.main
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.navigation.NavHostController
5 | import androidx.navigation.compose.NavHost
6 | import androidx.navigation.compose.composable
7 | import com.devsadeq.composecinematicketsreservations.ui.screen.cart.CartScreen
8 | import com.devsadeq.composecinematicketsreservations.ui.screen.details.DetailsScreen
9 | import com.devsadeq.composecinematicketsreservations.ui.screen.home.HomeScreen
10 | import com.devsadeq.composecinematicketsreservations.ui.screen.profile.ProfileScreen
11 | import com.devsadeq.composecinematicketsreservations.ui.screen.reservation.ReservationScreen
12 | import com.devsadeq.composecinematicketsreservations.ui.screen.search.SearchScreen
13 |
14 | @Composable
15 | fun AppNavGraph(navHostController: NavHostController) {
16 | NavHost(
17 | navController = navHostController,
18 | startDestination = Screen.Home.route,
19 | ) {
20 | composable(Screen.Home.route) {
21 | HomeScreen(navController = navHostController)
22 | }
23 | composable(Screen.Search.route) {
24 | SearchScreen()
25 | }
26 | composable(Screen.Cart.route) {
27 | CartScreen()
28 | }
29 | composable(Screen.Profile.route) {
30 | ProfileScreen()
31 | }
32 | composable(Screen.Details.route) {
33 | DetailsScreen(navController = navHostController)
34 | }
35 | composable(Screen.Reservation.route) {
36 | ReservationScreen(navController = navHostController)
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/main/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.main
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.tooling.preview.Preview
8 | import dagger.hilt.android.AndroidEntryPoint
9 |
10 | @AndroidEntryPoint
11 | class MainActivity : ComponentActivity() {
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | setContent {
15 | MainScreen()
16 | }
17 | }
18 | }
19 |
20 | @Preview(showBackground = true)
21 | @Composable
22 | fun MainPreview() {
23 | MainScreen()
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/main/MainScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.main
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.RowScope
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.foundation.layout.height
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.layout.size
10 | import androidx.compose.foundation.shape.RoundedCornerShape
11 | import androidx.compose.material.BottomNavigation
12 | import androidx.compose.material.BottomNavigationItem
13 | import androidx.compose.material3.ExperimentalMaterial3Api
14 | import androidx.compose.material3.Icon
15 | import androidx.compose.material3.MaterialTheme
16 | import androidx.compose.material3.Scaffold
17 | import androidx.compose.material3.Surface
18 | import androidx.compose.runtime.Composable
19 | import androidx.compose.runtime.getValue
20 | import androidx.compose.ui.Modifier
21 | import androidx.compose.ui.draw.clip
22 | import androidx.compose.ui.res.painterResource
23 | import androidx.compose.ui.tooling.preview.Preview
24 | import androidx.compose.ui.unit.dp
25 | import androidx.navigation.NavHostController
26 | import androidx.navigation.compose.currentBackStackEntryAsState
27 | import androidx.navigation.compose.rememberNavController
28 | import com.devsadeq.composecinematicketsreservations.ui.theme.ComposeCinemaTicketsReservationsTheme
29 | import com.devsadeq.composecinematicketsreservations.ui.theme.Orange
30 | import com.devsadeq.composecinematicketsreservations.ui.theme.White
31 |
32 | @Composable
33 | fun MainScreen() {
34 | ComposeCinemaTicketsReservationsTheme {
35 | Surface(
36 | modifier = Modifier.fillMaxSize(),
37 | color = MaterialTheme.colorScheme.background
38 | ) {
39 | MainScreenContent()
40 | }
41 | }
42 | }
43 |
44 | @OptIn(ExperimentalMaterial3Api::class)
45 | @Composable
46 | fun MainScreenContent() {
47 | val navController = rememberNavController()
48 | val navStackBackEntry by navController.currentBackStackEntryAsState()
49 | val currentDestination = navStackBackEntry?.destination
50 |
51 | Scaffold(
52 | bottomBar = if (currentDestination?.route != Screen.Details.route && currentDestination?.route != Screen.Reservation.route) {
53 | { BottomNavBar(navController) }
54 | } else {
55 | {}
56 | }
57 | ) { innerPadding ->
58 | Box(modifier = Modifier.padding(innerPadding)) {
59 | AppNavGraph(navController)
60 | }
61 | }
62 | }
63 |
64 | @Composable
65 | fun BottomNavBar(navController: NavHostController) {
66 | val screens = listOf(
67 | Screen.Home,
68 | Screen.Search,
69 | Screen.Cart,
70 | Screen.Profile
71 | )
72 | val navBackStackEntry by navController.currentBackStackEntryAsState()
73 | val currentRoute = navBackStackEntry?.destination?.route
74 |
75 | BottomNavigation(
76 | modifier = Modifier.height(80.dp),
77 | backgroundColor = White,
78 | elevation = 0.dp,
79 | ) {
80 | screens.forEach { screen ->
81 | AddItem(
82 | selected = currentRoute == screen.route,
83 | screen = screen,
84 | navController = navController
85 | )
86 | }
87 | }
88 | }
89 |
90 | @Composable
91 | fun RowScope.AddItem(
92 | selected: Boolean = false,
93 | screen: Screen,
94 | navController: NavHostController
95 | ) {
96 | BottomNavigationItem(
97 | icon = {
98 | if (selected) {
99 | Box(
100 | modifier = Modifier
101 | .clip(RoundedCornerShape(50.dp))
102 | .background(Orange)
103 | .padding(16.dp),
104 | ) {
105 | Icon(
106 | painter = painterResource(id = screen.icon),
107 | contentDescription = screen.title,
108 | tint = MaterialTheme.colorScheme.onPrimary,
109 | modifier = Modifier.size(24.dp)
110 | )
111 | }
112 | } else {
113 | Icon(
114 | painter = painterResource(id = screen.icon),
115 | contentDescription = screen.title,
116 | modifier = Modifier.size(24.dp)
117 | )
118 | }
119 | },
120 | selected = selected,
121 | onClick = {
122 | navController.navigate(screen.route) {
123 | popUpTo(navController.graph.startDestinationId)
124 | launchSingleTop = true
125 | }
126 | },
127 | alwaysShowLabel = false,
128 | )
129 | }
130 |
131 | @Preview(showBackground = true, showSystemUi = true, apiLevel = 31)
132 | @Composable
133 | fun MainScreenPreview() {
134 | MainScreen()
135 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/main/Screen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.main
2 |
3 | import com.devsadeq.composecinematicketsreservations.R
4 |
5 | sealed class Screen(
6 | val route: String,
7 | val title: String,
8 | val icon: Int
9 | ) {
10 | object Home : Screen("home", "Home", R.drawable.ic_video_play)
11 | object Search : Screen("search", "Search", R.drawable.ic_search)
12 | object Cart : Screen("cart", "Cart", R.drawable.ic_ticket)
13 | object Profile : Screen("profile", "Profile", R.drawable.ic_profile)
14 | object Details : Screen("details", "Details", R.drawable.ic_profile)
15 | object Reservation : Screen("reservation", "Reservation", R.drawable.ic_profile)
16 |
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/screen/cart/CartScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.screen.cart
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.material3.Text
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import androidx.compose.ui.unit.sp
11 |
12 | @Composable
13 | fun CartScreen() {
14 | CartScreenContent()
15 | }
16 |
17 | @Composable
18 | private fun CartScreenContent() {
19 | Column(
20 | modifier = Modifier,
21 | horizontalAlignment = Alignment.CenterHorizontally,
22 | verticalArrangement = Arrangement.Center,
23 | ) {
24 | Text(text = "Cart Screen", fontSize = 30.sp)
25 | }
26 | }
27 |
28 | @Preview(showBackground = true, showSystemUi = true, apiLevel = 31)
29 | @Composable
30 | fun CartScreenPreview() {
31 | CartScreen()
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/screen/details/DetailsScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.screen.details
2 |
3 | import androidx.compose.foundation.layout.Box
4 | import androidx.compose.foundation.layout.fillMaxSize
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.collectAsState
7 | import androidx.compose.runtime.getValue
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.hilt.navigation.compose.hiltViewModel
11 | import androidx.navigation.NavController
12 | import com.devsadeq.composecinematicketsreservations.ui.composable.DetailsBackgroundImage
13 | import com.devsadeq.composecinematicketsreservations.ui.composable.DetailsBottomSheet
14 | import com.devsadeq.composecinematicketsreservations.ui.composable.DetailsHeader
15 | import com.devsadeq.composecinematicketsreservations.ui.main.Screen
16 | import com.devsadeq.composecinematicketsreservations.viewmodel.details.DetailsUIState
17 | import com.devsadeq.composecinematicketsreservations.viewmodel.details.DetailsViewModel
18 |
19 | @Composable
20 | fun DetailsScreen(
21 | navController: NavController,
22 | viewModel: DetailsViewModel = hiltViewModel()
23 | ) {
24 | val state by viewModel.state.collectAsState()
25 | DetailsScreenContent(
26 | state,
27 | onCloseClicked = { navController.popBackStack() },
28 | onReserveClicked = { navController.navigate(Screen.Reservation.route) }
29 | )
30 | }
31 |
32 | @Composable
33 | fun DetailsScreenContent(
34 | state: DetailsUIState,
35 | onCloseClicked: () -> Unit,
36 | onReserveClicked: () -> Unit
37 | ) {
38 | Box(
39 | modifier = Modifier.fillMaxSize()
40 | ) {
41 | DetailsBackgroundImage(modifier = Modifier.align(Alignment.TopCenter))
42 | DetailsHeader(onCloseClicked = onCloseClicked)
43 | DetailsBottomSheet(
44 | state,
45 | modifier = Modifier.align(Alignment.BottomCenter),
46 | onReserveClicked = onReserveClicked
47 | )
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/screen/home/HomeScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.screen.home
2 |
3 | import androidx.compose.foundation.ExperimentalFoundationApi
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.foundation.pager.PagerState
8 | import androidx.compose.foundation.pager.rememberPagerState
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.collectAsState
11 | import androidx.compose.runtime.getValue
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.hilt.navigation.compose.hiltViewModel
15 | import androidx.navigation.NavController
16 | import com.devsadeq.composecinematicketsreservations.ui.composable.BlurBackground
17 | import com.devsadeq.composecinematicketsreservations.ui.composable.HomeFilterChips
18 | import com.devsadeq.composecinematicketsreservations.ui.composable.HomeOverview
19 | import com.devsadeq.composecinematicketsreservations.ui.composable.HomePager
20 | import com.devsadeq.composecinematicketsreservations.ui.main.Screen
21 | import com.devsadeq.composecinematicketsreservations.viewmodel.home.HomeUIState
22 | import com.devsadeq.composecinematicketsreservations.viewmodel.home.HomeViewModel
23 |
24 |
25 | @OptIn(ExperimentalFoundationApi::class)
26 | @Composable
27 | fun HomeScreen(
28 | navController: NavController,
29 | viewModel: HomeViewModel = hiltViewModel()
30 | ) {
31 | val state by viewModel.state.collectAsState()
32 | val pagerState = rememberPagerState(initialPage = 1)
33 |
34 | HomeScreenContent(
35 | state = state,
36 | pagerState = pagerState,
37 | onItemClicked = { navController.navigate(Screen.Details.route) }
38 | )
39 | }
40 |
41 | @OptIn(ExperimentalFoundationApi::class)
42 | @Composable
43 | private fun HomeScreenContent(
44 | state: HomeUIState,
45 | pagerState: PagerState,
46 | onItemClicked: () -> Unit
47 | ) {
48 |
49 | Box(
50 | modifier = Modifier.fillMaxSize()
51 | ) {
52 | BlurBackground(image = state.movies[pagerState.currentPage].imageRes)
53 | Column(
54 | modifier = Modifier,
55 | horizontalAlignment = Alignment.CenterHorizontally,
56 | ) {
57 | HomeFilterChips()
58 | HomePager(state.movies, pagerState = pagerState, onItemClicked = onItemClicked)
59 | HomeOverview(state, pagerState)
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/screen/profile/ProfileScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.screen.profile
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.material3.Text
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import androidx.compose.ui.unit.sp
11 |
12 | @Composable
13 | fun ProfileScreen() {
14 | ProfileScreenContent()
15 | }
16 |
17 | @Composable
18 | private fun ProfileScreenContent() {
19 | Column(
20 | modifier = Modifier,
21 | horizontalAlignment = Alignment.CenterHorizontally,
22 | verticalArrangement = Arrangement.Center,
23 | ) {
24 | Text(text = "Profile Screen", fontSize = 30.sp)
25 | }
26 | }
27 |
28 | @Preview(showBackground = true, showSystemUi = true, apiLevel = 31)
29 | @Composable
30 | fun ProfileScreenPreview() {
31 | ProfileScreen()
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/screen/reservation/ReservationScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.screen.reservation
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.runtime.collectAsState
9 | import androidx.compose.runtime.getValue
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.unit.dp
13 | import androidx.hilt.navigation.compose.hiltViewModel
14 | import androidx.navigation.NavController
15 | import com.devsadeq.composecinematicketsreservations.ui.composable.ReservationScreenFooter
16 | import com.devsadeq.composecinematicketsreservations.ui.composable.ReservationScreenHeader
17 | import com.devsadeq.composecinematicketsreservations.ui.composable.ReservationScreenSeats
18 | import com.devsadeq.composecinematicketsreservations.ui.theme.Black
19 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.ReservationUIState
20 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.ReservationViewModel
21 | import com.devsadeq.composecinematicketsreservations.viewmodel.reservation.toSeatPairs
22 |
23 | @Composable
24 | fun ReservationScreen(
25 | navController: NavController,
26 | viewModel: ReservationViewModel = hiltViewModel()
27 | ) {
28 | val state by viewModel.state.collectAsState()
29 | ReservationScreenContent(
30 | state,
31 | onSeatClick = viewModel::onSeatSelected,
32 | onCloseClicked = { navController.popBackStack() }
33 | )
34 | }
35 |
36 | @Composable
37 | private fun ReservationScreenContent(
38 | state: ReservationUIState,
39 | onSeatClick: (id: Int) -> Unit,
40 | onCloseClicked: () -> Unit
41 | ) {
42 | Box(
43 | modifier = Modifier
44 | .fillMaxSize()
45 | .background(Black)
46 | ) {
47 | ReservationScreenHeader(
48 | modifier = Modifier.align(Alignment.TopCenter),
49 | onCloseClicked = onCloseClicked
50 | )
51 | ReservationScreenSeats(
52 | seatsPairs = state.seats.toSeatPairs(),
53 | onSeatClick = onSeatClick,
54 | modifier = Modifier
55 | .align(Alignment.TopCenter)
56 | .padding(top = 250.dp)
57 | )
58 | ReservationScreenFooter(
59 | state = state,
60 | modifier = Modifier.align(Alignment.BottomCenter),
61 | )
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/screen/search/SearchScreen.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.screen.search
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.material3.Text
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import androidx.compose.ui.unit.sp
11 |
12 | @Composable
13 | fun SearchScreen() {
14 | SearchScreenContent()
15 | }
16 |
17 | @Composable
18 | private fun SearchScreenContent() {
19 | Column(
20 | modifier = Modifier,
21 | horizontalAlignment = Alignment.CenterHorizontally,
22 | verticalArrangement = Arrangement.Center,
23 | ) {
24 | Text(text = "Search Screen", fontSize = 30.sp)
25 | }
26 | }
27 |
28 | @Preview(showBackground = true, showSystemUi = true, apiLevel = 31)
29 | @Composable
30 | fun SearchScreenPreview() {
31 | SearchScreen()
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 |
9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)
12 |
13 | val White = Color(0xFFFFFFFF)
14 | val Black = Color(0xFF010101)
15 | val Grey = Color(0xFF989185)
16 | val DarkGrey = Color(0xFF404040)
17 | val Orange = Color(0xFFFF5524)
18 | val LightOrange = Color(0x80FF5524)
19 | val LightGrey = Color(0xFFEFEFEF)
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.theme
2 |
3 | import android.app.Activity
4 | import android.os.Build
5 | import androidx.compose.foundation.isSystemInDarkTheme
6 | import androidx.compose.material3.MaterialTheme
7 | import androidx.compose.material3.darkColorScheme
8 | import androidx.compose.material3.dynamicDarkColorScheme
9 | import androidx.compose.material3.dynamicLightColorScheme
10 | import androidx.compose.material3.lightColorScheme
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.SideEffect
13 | import androidx.compose.ui.graphics.toArgb
14 | import androidx.compose.ui.platform.LocalContext
15 | import androidx.compose.ui.platform.LocalView
16 | import androidx.core.view.WindowCompat
17 |
18 | private val DarkColorScheme = darkColorScheme(
19 | primary = Orange,
20 | secondary = DarkGrey,
21 | tertiary = Grey,
22 | background = White,
23 | onPrimary = White,
24 | onBackground = Black,
25 | onTertiary = White,
26 | )
27 |
28 | private val LightColorScheme = lightColorScheme(
29 | primary = Orange,
30 | secondary = DarkGrey,
31 | tertiary = Grey,
32 | background = White,
33 | onPrimary = White,
34 | onBackground = Black,
35 | onTertiary = White,
36 | )
37 |
38 | @Composable
39 | fun ComposeCinemaTicketsReservationsTheme(
40 | darkTheme: Boolean = isSystemInDarkTheme(),
41 | // Dynamic color is available on Android 12+
42 | dynamicColor: Boolean = true,
43 | content: @Composable () -> Unit
44 | ) {
45 | val colorScheme = when {
46 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
47 | val context = LocalContext.current
48 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
49 | }
50 |
51 | darkTheme -> DarkColorScheme
52 | else -> LightColorScheme
53 | }
54 | val view = LocalView.current
55 | if (!view.isInEditMode) {
56 | SideEffect {
57 | val window = (view.context as Activity).window
58 | window.statusBarColor = colorScheme.primary.toArgb()
59 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
60 | }
61 | }
62 |
63 | MaterialTheme(
64 | colorScheme = colorScheme,
65 | typography = Typography,
66 | content = content
67 | )
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.Font
6 | import androidx.compose.ui.text.font.FontFamily
7 | import androidx.compose.ui.text.font.FontWeight
8 | import androidx.compose.ui.unit.sp
9 | import com.devsadeq.composecinematicketsreservations.R
10 |
11 | val OpenSans = FontFamily(
12 | Font(R.font.opensans_regular),
13 | Font(R.font.opensans_medium, FontWeight.W500),
14 | )
15 |
16 | val Typography = Typography(
17 | headlineMedium = TextStyle(
18 | fontFamily = OpenSans,
19 | fontWeight = FontWeight.Medium,
20 | fontSize = 20.sp,
21 | lineHeight = 28.sp,
22 | letterSpacing = 0.sp
23 | ),
24 | bodyLarge = TextStyle(
25 | fontFamily = OpenSans,
26 | fontWeight = FontWeight.Normal,
27 | fontSize = 16.sp,
28 | lineHeight = 24.sp,
29 | letterSpacing = 0.5.sp
30 | ),
31 | bodyMedium = TextStyle(
32 | fontFamily = OpenSans,
33 | fontWeight = FontWeight.Normal,
34 | fontSize = 14.sp,
35 | lineHeight = 20.sp,
36 | letterSpacing = 0.25.sp
37 | ),
38 | bodySmall = TextStyle(
39 | fontFamily = OpenSans,
40 | fontWeight = FontWeight.Normal,
41 | fontSize = 12.sp,
42 | lineHeight = 20.sp,
43 | letterSpacing = 0.25.sp
44 | ),
45 | labelLarge = TextStyle(
46 | fontFamily = OpenSans,
47 | fontWeight = FontWeight.Medium,
48 | fontSize = 16.sp,
49 | lineHeight = 24.sp,
50 | letterSpacing = 0.5.sp
51 | ),
52 | labelMedium = TextStyle(
53 | fontFamily = OpenSans,
54 | fontWeight = FontWeight.Medium,
55 | fontSize = 14.sp,
56 | lineHeight = 20.sp,
57 | letterSpacing = 0.25.sp
58 | ),
59 | labelSmall = TextStyle(
60 | fontFamily = OpenSans,
61 | fontWeight = FontWeight.Medium,
62 | fontSize = 12.sp,
63 | lineHeight = 20.sp,
64 | letterSpacing = 0.25.sp
65 | ),
66 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/viewmodel/details/DetailsUIState.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.viewmodel.details
2 |
3 | data class DetailsUIState(
4 | val actors: List = emptyList(),
5 | )
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/viewmodel/details/DetailsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.viewmodel.details
2 |
3 | import androidx.lifecycle.ViewModel
4 | import com.devsadeq.composecinematicketsreservations.R
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import kotlinx.coroutines.flow.MutableStateFlow
7 | import kotlinx.coroutines.flow.asStateFlow
8 | import kotlinx.coroutines.flow.update
9 | import javax.inject.Inject
10 |
11 | @HiltViewModel
12 | class DetailsViewModel @Inject constructor() : ViewModel() {
13 | private val _state = MutableStateFlow(DetailsUIState())
14 | val state = _state.asStateFlow()
15 |
16 | init {
17 | getActors()
18 | }
19 |
20 | private fun getActors() {
21 | _state.update {
22 | it.copy(
23 | actors = listOf(
24 | R.drawable.actor_1,
25 | R.drawable.actor_2,
26 | R.drawable.actor_3,
27 | R.drawable.actor_4,
28 | R.drawable.actor_5,
29 | R.drawable.actor_6,
30 | R.drawable.actor_7,
31 | R.drawable.actor_8,
32 | R.drawable.actor_1,
33 | R.drawable.actor_2,
34 | R.drawable.actor_3,
35 | R.drawable.actor_4,
36 | R.drawable.actor_5,
37 | R.drawable.actor_6,
38 | R.drawable.actor_7,
39 | R.drawable.actor_8,
40 | )
41 | )
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/viewmodel/home/HomeUIState.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.viewmodel.home
2 |
3 | data class HomeUIState(
4 | val movies: List = emptyList(),
5 | ) {
6 | data class MovieUIState(
7 | val title: String = "",
8 | val imageRes: Int = 0,
9 | val duration: String = "",
10 | val genres: List = emptyList(),
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/viewmodel/home/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.viewmodel.home
2 |
3 | import androidx.lifecycle.ViewModel
4 | import com.devsadeq.composecinematicketsreservations.R
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import kotlinx.coroutines.flow.MutableStateFlow
7 | import kotlinx.coroutines.flow.asStateFlow
8 | import kotlinx.coroutines.flow.update
9 | import javax.inject.Inject
10 |
11 | @HiltViewModel
12 | class HomeViewModel @Inject constructor() : ViewModel() {
13 | private val _state = MutableStateFlow(HomeUIState())
14 | val state = _state.asStateFlow()
15 |
16 | private val dummyMovies = listOf(
17 | HomeUIState.MovieUIState(
18 | title = "Morbius",
19 | imageRes = R.drawable.movie1,
20 | duration = "1h 50m",
21 | genres = listOf("Horror", "Action", "Thriller")
22 | ),
23 | HomeUIState.MovieUIState(
24 | title = "fantastic Beasts: The Secrets of Dumbledore",
25 | imageRes = R.drawable.movie2,
26 | duration = "2h 23m",
27 | genres = listOf("Adventure", "Fantasy", "Family")
28 | ),
29 | HomeUIState.MovieUIState(
30 | title = "Doctor Strange in the Multiverse of Madness",
31 | imageRes = R.drawable.movie3,
32 | duration = "3h 15m",
33 | genres = listOf("Action", "Adventure", "Fantasy")
34 | )
35 | )
36 |
37 | init {
38 | getDummyData()
39 | }
40 |
41 | private fun getDummyData() {
42 | _state.update { it.copy(movies = dummyMovies) }
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/viewmodel/reservation/ReservationUIState.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.viewmodel.reservation
2 |
3 | data class ReservationUIState(
4 | val seats: List = emptyList(),
5 | val days: List = emptyList(),
6 | val times: List = emptyList(),
7 | )
8 |
9 | data class SeatUIState(
10 | val id: Int,
11 | val isReserved: Boolean = false,
12 | val isSelected: Boolean = false,
13 | )
14 |
15 | data class DayUIState(
16 | val id: Int,
17 | val dayOfWeek: String,
18 | val dayOfMonth: Int,
19 | val isSelected: Boolean = false,
20 | )
21 |
22 | data class TimeUIState(
23 | val id: Int,
24 | val time: String,
25 | val isSelected: Boolean = false,
26 | )
27 |
28 | fun List.toSeatPairs(): List> {
29 | return this.chunked(2).map { it.first() to it.last() }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/devsadeq/composecinematicketsreservations/viewmodel/reservation/ReservationViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations.viewmodel.reservation
2 |
3 | import androidx.lifecycle.ViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import kotlinx.coroutines.flow.MutableStateFlow
6 | import kotlinx.coroutines.flow.asStateFlow
7 | import kotlinx.coroutines.flow.update
8 | import javax.inject.Inject
9 |
10 | @HiltViewModel
11 | class ReservationViewModel @Inject constructor() : ViewModel() {
12 | private val _state = MutableStateFlow(ReservationUIState())
13 | val state = _state.asStateFlow()
14 |
15 | init {
16 | getSeats()
17 | getDays()
18 | getTimes()
19 | }
20 |
21 | fun onSeatSelected(seatId: Int) {
22 | _state.update {
23 | it.copy(
24 | seats = it.seats.map { seat ->
25 | if (seat.id == seatId) {
26 | seat.copy(isSelected = !seat.isSelected)
27 | } else {
28 | seat
29 | }
30 | }
31 | )
32 | }
33 | }
34 |
35 | private fun getSeats() {
36 | val seats = mutableListOf()
37 | for (i in 1..30) {
38 | seats.add(
39 | SeatUIState(
40 | id = i,
41 | isReserved = i % 3 == 0,
42 | isSelected = i == 5
43 | )
44 | )
45 | }
46 | _state.value = _state.value.copy(seats = seats)
47 | }
48 |
49 | private fun getDays() {
50 | val days = mutableListOf()
51 | for (i in 14..30) {
52 | days.add(
53 | DayUIState(
54 | id = i,
55 | dayOfWeek = if (i == 14) "Today" else "Day $i",
56 | dayOfMonth = i,
57 | isSelected = i == 16
58 | )
59 | )
60 | }
61 | _state.value = _state.value.copy(days = days)
62 | }
63 |
64 | private fun getTimes() {
65 | val times = mutableListOf()
66 | for (i in 1..7) {
67 | times.add(
68 | TimeUIState(
69 | id = i,
70 | time = "${i + 10}:00",
71 | isSelected = i == 1
72 | )
73 | )
74 | }
75 | _state.value = _state.value.copy(times = times)
76 | }
77 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_3.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_4.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_5.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_6.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_7.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/actor_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/actor_8.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/banner.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_clock.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/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/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_profile.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ticket.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_video_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
34 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/movie1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/movie1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/movie2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/movie2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/movie3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/drawable/movie3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seat.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
13 |
16 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seat_belt.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/font/opensans_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/font/opensans_medium.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/opensans_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/font/opensans_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/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/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ComposeCinemaTicketsReservations
3 | Now Showing
4 | Coming Soon
5 | 2h 23m
6 | Fantasy
7 | Adventure
8 | Fantastic Beasts: The Secrets of Dumbledore
9 | Professor Albus Dumbledore knows the powerful Dark wizard Gellert Grindelwald is moving to seize control of the wizarding world. Unable to stop him alone, he entrusts Magizoologist Newt Scamander to lead an intrepid team of wizards, witches and one brave Muggle baker on a dangerous mission, where they encounter old and new foes. But winning this battle against Grindelwald means making the ultimate sacrifice.
10 | Booking
11 | 6.8
12 | IMDB
13 | Rotten Tomatoes
14 | 36%
15 | IGN
16 | 4
17 | Available
18 | Taken
19 | Selected
20 | Buy Tickets
21 | $100.00
22 | 4 tickets
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/devsadeq/composecinematicketsreservations/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.composecinematicketsreservations
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 | }
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | @Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
3 | plugins {
4 | alias(libs.plugins.androidApplication) apply false
5 | alias(libs.plugins.kotlinAndroid) apply false
6 | alias(libs.plugins.kotlinKapt) apply false
7 | alias(libs.plugins.hilt) apply false
8 | }
9 | true // Needed to make the Suppress annotation work for the plugins block
--------------------------------------------------------------------------------
/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 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.2.0-alpha09"
3 | kotlin = "1.8.10"
4 | core-ktx = "1.9.0"
5 | junit = "4.13.2"
6 | androidx-test-ext-junit = "1.1.5"
7 | espresso-core = "3.5.1"
8 | lifecycle-runtime-ktx = "2.6.1"
9 | activity-compose = "1.7.2"
10 | compose-bom = "2023.03.00"
11 | hilt = "2.44"
12 | hilt-navigation = "1.0.0"
13 | coil = "2.4.0"
14 | ui-util = "1.4.3"
15 | navigation-compose = "2.6.0"
16 | compose-material = "1.4.3"
17 |
18 | [libraries]
19 | core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
20 | junit = { group = "junit", name = "junit", version.ref = "junit" }
21 | androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
22 | espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
23 | lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle-runtime-ktx" }
24 | activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
25 | compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
26 | ui = { group = "androidx.compose.ui", name = "ui" }
27 | ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
28 | ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
29 | ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
30 | ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
31 | ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
32 | material3 = { group = "androidx.compose.material3", name = "material3" }
33 | lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel" }
34 | hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
35 | hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
36 | hilt-navigation = { group = "androidx.hilt", name = "hilt-navigation", version.ref = "hilt-navigation" }
37 | coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" }
38 | compose-ui-util = { group = "androidx.compose.ui", name = "ui-util" }
39 | navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose" }
40 | compose-material = { group = "androidx.compose.material", name = "material", version.ref = "compose-material" }
41 | hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-navigation" }
42 |
43 | [plugins]
44 | androidApplication = { id = "com.android.application", version.ref = "agp" }
45 | kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
46 | kotlinKapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
47 | hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
48 |
49 | [bundles]
50 |
51 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/ComposeCinemaTicketsReservations/00dc62ec7796ebcd50a7b2148831f5846defc947/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jul 03 15:49:19 AST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 |
16 | rootProject.name = "ComposeCinemaTicketsReservations"
17 | include(":app")
18 |
--------------------------------------------------------------------------------