Skip to content

Commit

Permalink
Compose UI Improvement (Release) (#42)
Browse files Browse the repository at this point in the history
* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Migrate to compose UI (Basic) (#33)

* Improve app performance and security (#25)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Hotfix: missing favorite module title (#26)

* Create LICENSE.md (#27)

* Minor update: increment app version and rename Versions.GRADLE to Versions.AGP (#28)

* Add compose dependency in app module

* WIP: migrate layout to compose ui

* Implemented Compose UI

* Patch/update app version to 1.2.0 (#34)

* Update build.gradle.kts

* Update build.gradle.kts

* Patch/resolve conflict app v1.2.0 (#36)

* Improve app performance and security (#25)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Hotfix: missing favorite module title (#26)

* Create LICENSE.md (#27)

* Minor update: increment app version and rename Versions.GRADLE to Versions.AGP (#28)

* Migrate to Compose UI (#31)

* Add compose dependency in app module

* WIP: migrate layout to compose ui

* Implemented Compose UI

* Revert "Migrate to Compose UI (#31)" (#32)

This reverts commit 0b080c5.

* Patch/dev resolve conflict (#37)

* Improve app performance and security (#25)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Hotfix: missing favorite module title (#26)

* Create LICENSE.md (#27)

* Minor update: increment app version and rename Versions.GRADLE to Versions.AGP (#28)

* Migrate to Compose UI (#31)

* Add compose dependency in app module

* WIP: migrate layout to compose ui

* Implemented Compose UI

* Revert "Migrate to Compose UI (#31)" (#32)

This reverts commit 0b080c5.

* Remove unused unit test and update git ignore (#39)

* Compose UI Improvement (#40)

* Migrate to Compose UI (#38)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Migrate to compose UI (Basic) (#33)

* Improve app performance and security (#25)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Hotfix: missing favorite module title (#26)

* Create LICENSE.md (#27)

* Minor update: increment app version and rename Versions.GRADLE to Versions.AGP (#28)

* Add compose dependency in app module

* WIP: migrate layout to compose ui

* Implemented Compose UI

* Patch/update app version to 1.2.0 (#34)

* Update build.gradle.kts

* Update build.gradle.kts

* Patch/resolve conflict app v1.2.0 (#36)

* Improve app performance and security (#25)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Hotfix: missing favorite module title (#26)

* Create LICENSE.md (#27)

* Minor update: increment app version and rename Versions.GRADLE to Versions.AGP (#28)

* Migrate to Compose UI (#31)

* Add compose dependency in app module

* WIP: migrate layout to compose ui

* Implemented Compose UI

* Revert "Migrate to Compose UI (#31)" (#32)

This reverts commit 0b080c5.

* Patch/dev resolve conflict (#37)

* Improve app performance and security (#25)

* Bugfix/lint (#17)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Remove unused property

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Change activity favorite label

---------

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Feature/app optimization (#23)

* Update PR CI/CD (#16)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Patch: update CI/CD (#18)

Co-authored-by: Baharudin Yusup <baharudin.yusup@photon.com>

* Add obfuscation

* Implement Leak Canary and inspect performance issues

* Update CI/CD

* Add local database encryption

* Add certificate pinning

* Improve code

* Add unit test for ArrayListOfIntConverter

* Update app version (#24)

* Hotfix: missing favorite module title (#26)

* Create LICENSE.md (#27)

* Minor update: increment app version and rename Versions.GRADLE to Versions.AGP (#28)

* Migrate to Compose UI (#31)

* Add compose dependency in app module

* WIP: migrate layout to compose ui

* Implemented Compose UI

* Revert "Migrate to Compose UI (#31)" (#32)

This reverts commit 0b080c5.

* Remove unused unit test and update git ignore (#39)

* Bugfix: flicker in movie list screen

* Bugfix: backdropPath null in movie response

* Add AboutScreen and loading indicator for AsyncImage

* Update build number and version (#41)
  • Loading branch information
baharudin-yusup committed Jan 9, 2024
1 parent 0c1e709 commit e49920b
Show file tree
Hide file tree
Showing 25 changed files with 470 additions and 148 deletions.
5 changes: 4 additions & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 6 additions & 11 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ android {
applicationId = "dev.baharudin.tmdb_android"
minSdk = 30
targetSdk = 34
versionCode = 3
versionName = "1.2.0"
versionCode = 4
versionName = "1.2.1"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand All @@ -38,15 +38,10 @@ android {
keyAlias = System.getenv("GH_ACTIONS_SIGNING_KEY_ALIAS")
keyPassword = System.getenv("GH_ACTIONS_SIGNING_KEY_PASSWORD")
} else {
// Create a variable called keystorePropertiesFile, and initialize it to your
// keystore.properties file, in the rootProject folder.
val keystorePropertiesFile = rootProject.file("keystore.properties")

// Initialize a new Properties() object called keystoreProperties.
val keystoreProperties = Properties()

// Load your keystore.properties file into the keystoreProperties object.
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
val keystoreProperties = Properties().apply {
load(FileInputStream(keystorePropertiesFile))
}

keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
Expand Down Expand Up @@ -80,7 +75,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.3"
kotlinCompilerExtensionVersion = Versions.COMPOSE_COMPILER
}
packaging {
resources {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,14 @@ import dev.baharudin.tmdb_android.presentation.theme.TheMovieDBTheme

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

companion object {
const val EXTRA_FRAGMENT_DESTINATION = "fragment_destination"
const val EXTRA_PARCELABLE = "parcelable"
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TheMovieDBTheme {
MainScreen()
Surface {
AppNavHost(navController = rememberNavController())
}
}
}
}
}

@Composable
fun MainScreen() {
Surface(
modifier = Modifier.fillMaxSize(),
) {
AppNavHost(navController = rememberNavController())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import dev.baharudin.tmdb_android.presentation.screens.about.AboutScreen
import dev.baharudin.tmdb_android.presentation.screens.detail.MovieDetailScreen
import dev.baharudin.tmdb_android.presentation.screens.favorite_movie_list.FavoriteMovieListScreen
import dev.baharudin.tmdb_android.presentation.screens.home.HomeScreen
Expand All @@ -29,6 +30,11 @@ fun AppNavHost(
HomeScreen(navController)
}

composable(NavigationItem.About.route) {
AboutScreen()
}


composable(
NavigationItem.MovieList.route,
NavigationItem.MovieList.navArgument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.navigation.navArgument

sealed class NavigationItem(val route: String, val navArgument: List<NamedNavArgument> = listOf()) {
data object Home : NavigationItem("home")
data object About : NavigationItem("about")
data object MovieList : NavigationItem(
"movies?genreId={genreId}&genreName={genreName}&onlyFavorite={onlyFavorite}", listOf(
navArgument("genreId") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package dev.baharudin.tmdb_android.presentation.screens.about

import android.content.Intent
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.compose.SubcomposeAsyncImage
import dev.baharudin.tmdb_android.R

val githubLightIcon = compositionLocalOf { R.drawable.ic_github_black }
val githubDarkIcon = compositionLocalOf { R.drawable.ic_github_white }

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AboutScreen() {

val githubIcon = if (isSystemInDarkTheme()) {
githubDarkIcon
} else {
githubLightIcon
}

val context = LocalContext.current

val openUrlLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { }

Scaffold(
topBar = {
TopAppBar(title = {
Text(text = stringResource(id = R.string.about_screen_top_appbar_title))
})
},
floatingActionButton = {
CompositionLocalProvider {
FloatingActionButton(
modifier = Modifier.size(56.dp),
shape = CircleShape,
onClick = {
val url = "https://github.com/baharudin-yusup"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
openUrlLauncher.launch(intent)
},
content = {
Icon(
painter = painterResource(id = githubIcon.current),
contentDescription = null,
)
})
}

}
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
SubcomposeAsyncImage(
modifier = Modifier.size(100.dp, 100.dp),
model = "https://github.com/baharudin-yusup/baharudin-yusup/blob/main/assets/images/user-picture.png?raw=true",
contentDescription = stringResource(id = R.string.developer_profile_picture),
contentScale = ContentScale.Fit,
loading = {
Box(
modifier = Modifier
.size(100.dp, 100.dp)
.padding(24.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
)

Text(
modifier = Modifier.padding(vertical = 24.dp),
text = stringResource(id = R.string.developer_name),
style = MaterialTheme.typography.titleLarge
)
}
}
}

@Preview
@Composable
fun PreviewAboutScreen() {
AboutScreen()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
Expand All @@ -26,6 +27,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.compose.SubcomposeAsyncImage
import dev.baharudin.tmdb_android.R
import dev.baharudin.tmdb_android.core.R as CoreR
import dev.baharudin.tmdb_android.core.domain.entities.Genre
Expand All @@ -48,13 +50,23 @@ fun MovieDetailHeader(
modifier = Modifier.fillMaxWidth()
) {
// Poster
AsyncImage(
SubcomposeAsyncImage(
model = movie.posterPath.toImageUrl(),
contentDescription = stringResource(CoreR.string.movie_thumbnail),
modifier = Modifier
.clip(shape = RoundedCornerShape(8.dp))
.background(MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f)),
contentScale = ContentScale.Fit,
loading = {
Box(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
)

// Small Info
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,68 +44,59 @@ fun HomeScreen(navController: NavHostController, homeViewModel: HomeViewModel =
genres?.errorMessage?.showErrorMessage(LocalContext.current)
}

Scaffold(
topBar = {
TopAppBar(
title = { Text(text = stringResource(id = R.string.home_fragment_title)) },
actions = {
IconButton(onClick = { /* TODO: Handle about button click */ }) {
Icon(imageVector = Icons.Default.Info, contentDescription = null)
}
}
)
},
floatingActionButton = {
FloatingActionButton(
Scaffold(topBar = {
TopAppBar(title = {
Text(text = stringResource(id = R.string.home_fragment_title))
}, actions = {
IconButton(
onClick = {
val route = NavigationItem.MovieList.route.buildRoute(
mapOf(
"onlyFavorite" to true,
)
)
Log.d("HomeScreen", "navigate to $route")
val route = NavigationItem.About.route
navController.navigate(route)

},
content = { Icon(imageVector = Icons.Default.Favorite, contentDescription = null) }
) {
Icon(imageVector = Icons.Default.Info, contentDescription = null)
}
})
}, floatingActionButton = {
FloatingActionButton(onClick = {
val route = NavigationItem.MovieList.route.buildRoute(
mapOf("onlyFavorite" to true)
)
},
content = { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
Log.d("HomeScreen", "navigate to $route")
navController.navigate(route)
}, content = { Icon(imageVector = Icons.Default.Favorite, contentDescription = null) })
}, content = { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
) {
FlowRow(
modifier = Modifier.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
FlowRow(
modifier = Modifier.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
genres?.data?.forEach {
GenreCard(it) { genre ->
val route = NavigationItem.MovieList.route.buildRoute(
mapOf(
"genreId" to genre.id,
"genreName" to genre.name
)
genres?.data?.forEach {
GenreCard(it) { genre ->
val route = NavigationItem.MovieList.route.buildRoute(
mapOf(
"genreId" to genre.id, "genreName" to genre.name
)
Log.d("HomeScreen", "navigate to $route")
navController.navigate(route)
}
)
Log.d("HomeScreen", "navigate to $route")
navController.navigate(route)
}
}
}

if (genres?.isLoading == true) {
Box(
modifier = Modifier
.align(Alignment.Center),
) {
CircularProgressIndicator(
modifier = Modifier
.width(64.dp),
)
}
if (genres?.isLoading == true) {
Box(
modifier = Modifier.align(Alignment.Center),
) {
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
)
}
}
}
)
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dev.baharudin.tmdb_android.presentation.screens.movie_list

sealed class MovieListEvent {
data object Init : MovieListEvent()
}
Loading

0 comments on commit e49920b

Please sign in to comment.