All Projects β†’ RajashekarRaju β†’ compose-actors

RajashekarRaju / compose-actors

Licence: Apache-2.0 license
πŸ€– Android app built with jetpack πŸš€ compose follows new revamped guide to app architecture. Implemented with State, Coroutines ➰, ViewModels, Repository pattern, Light/Dark theme 🌈 MD3, Animations, Draw on canvas, Custom layouts, UI state handling, πŸŒ€ Image loading with coil, Palette 🎨 usage and dynamic theming etc.

Programming Languages

kotlin
9241 projects

Projects that are alternatives of or similar to compose-actors

Delish
Delish, a Food Recipes App in Jetpack Compose and Hilt based on modern Android tech-stacks and MVI clean architecture.
Stars: ✭ 356 (+345%)
Mutual labels:  coroutines, viewmodel, jetpack-compose
Compose-BreakingBad
πŸ§ͺ ☠︎ Jetpack Compose - Breaking Bad ☒︎
Stars: ✭ 26 (-67.5%)
Mutual labels:  coroutines, jetpack-navigation, jetpack-compose
Multi-Module-Nextflix-Composable
Includes jetpack compose, navigation, paging, hilt, retrofit, coil, coroutines, flow..
Stars: ✭ 195 (+143.75%)
Mutual labels:  coroutines, jetpack-compose
StarWarsSearch-MVI
Star wars sample android project showcasing the use of View components for rendering UI in Fragments and Activities. Uses Android Jetpack, clean architecture with MVI (Uni-directional data flow), dagger hilt, and kotlin coroutines with StateFlow
Stars: ✭ 189 (+136.25%)
Mutual labels:  coroutines, viewmodel
Wiggles
🐢 Beautiful Puppy adoption app with Jetpack Compose #AndroidDevChallenge
Stars: ✭ 365 (+356.25%)
Mutual labels:  jetpack-navigation, jetpack-compose
Dagger-Hilt-MVVM
Sample app that demonstrates the usage of Dagger Hilt with Kotlin & MVVM
Stars: ✭ 62 (-22.5%)
Mutual labels:  coroutines, viewmodel
DailyDoc
Productivity Note App utilizing Jetpack Compose
Stars: ✭ 31 (-61.25%)
Mutual labels:  jetpack-navigation, jetpack-compose
Compose-ToDo
A fully functional Android TODO app built entirely with Kotlin and Jetpack Compose
Stars: ✭ 130 (+62.5%)
Mutual labels:  viewmodel, jetpack-compose
ComposeNotes
Notes app with full jetpack compose architecture (UI + navigation). Uses MVVM, Room, Kotlin Flows & LiveData
Stars: ✭ 32 (-60%)
Mutual labels:  coroutines, jetpack-compose
Simple-Notes-Kotlin-App
✍️ Simple Note Making App use mvvm architecture , dagger , coroutines and navigation component. Features includes πŸ—’οΈ create , edit and ❌ delete notes
Stars: ✭ 40 (-50%)
Mutual labels:  coroutines, viewmodel
MusicX
MusicX is a music player 🎡 android app built using Kotlin and Jetpack Compose. It follows M.A.D. practices and hence is a good learning resource for beginners
Stars: ✭ 85 (+6.25%)
Mutual labels:  coroutines, jetpack-compose
SSComposeCookBook
A Collection of major Jetpack compose UI components which are commonly used.πŸŽ‰πŸ”πŸ‘Œ
Stars: ✭ 386 (+382.5%)
Mutual labels:  animations, jetpack-compose
Praxis
Example Android project using MVVM, DaggerAndroid, Jetpack Compose, Retrofit, Coroutines and Multi module architecture ✌🏽
Stars: ✭ 258 (+222.5%)
Mutual labels:  jetpack-compose, jetpack-components
KotlinEverywhere
This application created for Kotlin Everywhere series as a codelab. It will show step by step Kotlin and Android Jetpack Components fundamentals. πŸš€πŸš€
Stars: ✭ 52 (-35%)
Mutual labels:  coroutines, viewmodel
VegetableOrderUI-Android
Check out the new style for App Design aims for the Vegetable Order Service using jetpack compose...πŸ˜‰πŸ˜€πŸ˜πŸ˜Ž
Stars: ✭ 349 (+336.25%)
Mutual labels:  jetpack-navigation, jetpack-compose
floppy
🧩 Handling and maintain your UI view component easily
Stars: ✭ 55 (-31.25%)
Mutual labels:  coroutines, viewmodel
compose-ratingbar
A ratingbar composable for jetpack compose πŸš€πŸŒŸ
Stars: ✭ 89 (+11.25%)
Mutual labels:  jetpack-compose, jetpack-components
Books jetpack
A sample application to demonstrate how to use Jetpack Architecture Components in an Android Application following the Clean Architecture concepts.
Stars: ✭ 241 (+201.25%)
Mutual labels:  coroutines, viewmodel
Nytimes App
πŸ—½ A Simple Demonstration of the New York Times App πŸ“± using Jsoup web crawler with MVVM Architecture πŸ”₯
Stars: ✭ 246 (+207.5%)
Mutual labels:  coroutines, viewmodel
Sunset-hadith
Islamic app written with Kotlin, using KTOR + coroutines + flow + MVVM + Android Jetpack + Navigation component. Old version using RxJava + Retrofit + OKHttp
Stars: ✭ 26 (-67.5%)
Mutual labels:  coroutines, viewmodel

Compose Actors πŸ’ƒ

Roadmap v0.3.0

  • Let users search for movies directly just like searching for actors.
  • Collapsable TopBars, BottomBars, Scroll effects, new animations.
  • Add feature for adding actors to favorites like movies.

AppBanner

New release - v0.2.0

  • Add DI with Koin.
  • Modal bottom sheets & Bottom sheets.
  • Migrate to compose insets from accompanist.
  • Add new movie details screen, made changes to actors details screen.
  • Improved search functionality, added voice search, handled keyboard changes.
  • New feature to add Movie to favorites.
  • Add new database repository layer for favorites.
  • Add tabs in Home screen with actors/movies/favorites categories.

V2 Previews

Home Tabs

Actors Movies Favorites

Modal bottom sheets

Actor Movie

Movie details & Add to favorites

Add to favorites Favorites Details

Voice search actors

Search capabilities

Inspired from

JetCaster JetNews JetSnack

More compose content

πŸ—Ό Architecture

Follows new architecture guide updated on 14 December 2021 from revamped guide to app architecture.

🎹 Layer of this app.

Network Repository ViewModels Screens
Data
🎁🎁
🎁🎁
---> Source
🎁
--->
Suspend
Coroutines
➰➰
--->
State
Composables
πŸ“±πŸ“±
πŸ“±πŸ“±

ArchitectureLayer

🍑 App Overview Compose Blog

Android app built with Jetpack Compose shows actors information fetched from Tmdb Api. You may install and try to understand the code better, but make sure you provide your own Tmdb api key for data to show up in directory /utils/ApiKey.kt.

Release - v0.1.0

Screen Preview
Home Screen (Default destination)

β€’ Shows category list of actors in row of type popular & trending.
β€’ Has it's own ViewModel to manage it's ui state.
β€’ Custom TopAppBar container with search box.
β€’ Navigates to Search screen clicking search box.
β€’ Navigates to Detail screen with castId clicking any cast item.
β€’ If user is offline snackbar message is shown.
β€’ CircularProgressIndicator will be shown untill data is fetched.
β€’ Image fetching with Coil, manages state error/placeholder.
Home screen preview
Search Screen

β€’ Shows list of actors based on user submitted query.
β€’ Animatable shapes infinitely repeatable.
β€’ Has it's own ViewModel to manage it's ui state.
β€’ TextField contained in TopAppBar completely transparent.
β€’ Navigates to Detail screen with castId clicking any cast item.
β€’ Screen and animation state changes on search began.
β€’ Handles query & value changes correctly to fetch results.
β€’ Draw Arc/Line on canvas & animate to shape shift like search icon.
β€’ Different colors for animatables for both light/dark theme.
Search screen preview
Detail Screen

β€’ Shows user selected actor from other screens.
β€’ Has it's own ViewModel to manage it's ui state.
β€’ Reveal effect animation added to few composables.
β€’ CircularProgressIndicator will be shown untill data is fetched.
β€’ Image fetching with Coil, manages state error/placeholder.
β€’ Background image with gradient foreground effect.
β€’ Draws dynamic color behind system bars.
Detail screen preview

πŸ” Search Animation

// Simple progressive circle looking animation
val animateCircle = remember { Animatable(0f) }.apply {
    AnimateShapeInfinitely(this)
}

@Composable
fun AnimateShapeInfinitely(
    // shape which will be animated infinitely.
    animateShape: Animatable<Float, AnimationVector1D>,
    // final float state to be animated.
    targetValue: Float = 1f,
    // duration took for animating once.
    durationMillis: Int = 1000
) {
    LaunchedEffect(animateShape) {
        animateShape.animateTo(
            targetValue = targetValue,
            animationSpec = infiniteRepeatable(
                animation = tween(durationMillis, LinearEasing),
                repeatMode = RepeatMode.Restart
            )
        )
    }
}

Although I couldn't fully achieve the desired result as I imagined, I've settled for this current state for now.

Offline Dark

Calling the function once will draw a circle, in my example I have drawn it thrice with differnt colors, radius and scales.

DrawCircleOnCanvas(
    scale = scaleInfiniteTransition(targetValue = 2f, durationMillis = 600),
    color = circleColor,
    radiusRatio = 4f
)

I have kept all initial states of 3 circles to 0f to make end result much smoother.
Random or uneven gaps between initial/target/durationMillis will make end animation look more abrupt and aggressively pushing it's bounds.

@Composable
private fun scaleInfiniteTransition(
    initialValue: Float = 0f,
    targetValue: Float,
    durationMillis: Int,
): Float {
    val infiniteTransition = rememberInfiniteTransition()
    val scale: Float by infiniteTransition.animateFloat(
        initialValue = initialValue,
        targetValue = targetValue,
        animationSpec = infiniteRepeatable(
            animation = tween(durationMillis, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        )
    )
    return scale
}
@Composable
fun DrawCircleOnCanvas(
    scale: Float,
    color: Color,
    radiusRatio: Float
) {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
            }
    ) {
        val canvasWidth = size.width
        val canvasHeight = size.height
        drawCircle(
            color = color,
            center = Offset(
                x = canvasWidth / 2,
                y = canvasHeight / 2
            ),
            radius = size.minDimension / radiusRatio,
        )
    }
}

πŸ“΄ Offline state

Dark Light
Offline Dark Offline Light

Show a Snackbar message with SnackbarHostState.

if (!isOnline) {
    LaunchedEffect(scope) {
        scope.launch {
            scaffoldState.snackbarHostState.showSnackbar(
                message = context.getString(R.string.offline_snackbar_message),
                duration = SnackbarDuration.Indefinite
            )
        }
    }
}

ViewModels

All screens have their own ViewModels for managing the ui state.

class HomeViewModel(
    application: Application,
    private val repository: AppRepository
) : AndroidViewModel(application) {

    // Holds the state for values in HomeViewState
    var uiState by mutableStateOf(HomeViewState())
        private set

    init {
        // Update the values in uiState from all data sources.
        viewModelScope.launch {
            uiState = HomeViewState(isFetchingActors = true)
            val popularActorsList = repository.getPopularActorsData()
            val trendingActorsList = repository.getTrendingActorsData()
            uiState = HomeViewState(
                popularActorList = popularActorsList,
                trendingActorList = trendingActorsList,
                isFetchingActors = false
            )
        }
    }
}

Model for UI state of the screen.

data class HomeViewState(
    var popularActorList: List<Actor> = emptyList(),
    var trendingActorList: List<Actor> = emptyList(),
    val isFetchingActors: Boolean = false,
)

ViewModel used in a screen-level composable.

@Composable
fun HomeScreen(
    viewModel: HomeViewModel
) {
    val uiState = viewModel.uiState
    Box {
        ScreenContent(uiState.popularActorList)
    }
}

Repository

All ViewModels have access to repository which has single instance.

class AppRepository {

    private val networkDataSource by lazy { NetworkDataSource() }

    suspend fun getPopularActorsData(): List<Actor> {
        val listData: List<Actor>
        withContext(Dispatchers.IO) {
            listData = networkDataSource.getPopularActors()
        }
        return listData
    }
}

Instantiated repository will be passed to all ViewModels.

val repository = (application as ComposeActorsApp).repository

NavHost(
    navController = navController,
    startDestination = startDestination
) {
    composable(
        "Destination Route"
    ) {
        HomeScreen(
            viewModel = viewModel(
                factory = HomeViewModel.provideFactory(
                    application, repository
                )
            )
        )
    }
}

πŸ”¨ Structure

πŸ“ data πŸ“ navigation πŸ“ repository πŸ“ root
πŸ“„ NetworkDataSource.kt
πŸ“„ JsonRemoteData.kt
πŸ“„ Urls.kt
πŸ“„ AppActions.kt
πŸ“„ AppDestinations.kt
πŸ“„ AppNavigation.kt
πŸ“„ AppRepository.kt πŸ“„ MainActivity.kt
πŸ“„ Application.kt
πŸ“ ui πŸ“ utils πŸ“ model
πŸ“ home
πŸ“ details
πŸ“ search
πŸ“ components
πŸ“ theme
πŸ“„ InfiniteFlowingThings.kt
πŸ“„ RevealEffect.kt
πŸ“„ Utilities.kt
πŸ“„ DynamicThemeGenerator.kt
πŸ“„ NetworkManager.kt
πŸ“„ NetworkQueryUtils.kt
πŸ“„ Actor.kt
πŸ“„ ActorDetail.kt
πŸ“„ Movie.kt

πŸ“ Packages in ui

πŸ“ home πŸ“ details πŸ“ search πŸ“ components πŸ“ theme
πŸ“„ HomeScreen.kt
πŸ“„ HomeViewModel.kt
πŸ“„ DetailsScreen.kt
πŸ“„ DetailsViewModel.kt
πŸ“„ SearchScreen.kt
πŸ“„ SearchViewModel.kt
πŸ“„ AnimatedSearch.kt
πŸ“„ AppBars.kt
πŸ“„ Components.kt
πŸ“„ NetworkImage.kt
πŸ“„ Progress.kt
πŸ“„ Color.kt
πŸ“„ Shape.kt
πŸ“„ Theme.kt
πŸ“„ Type.kt

πŸŒ€ Image loading with Coil

Reusable composable used in all screens to load image from an Url.

@Composable
fun LoadNetworkImage(
    imageUrl: String,
    contentDescription: String,
    modifier: Modifier,
    shape: Shape
) {
    Image(
        painter = rememberImagePainter(
            data = imageUrl,
            builder = {
                placeholder(R.drawable.animated_progress)
                error(R.drawable.ic_image_not_available)
            }),
        contentDescription = contentDescription,
        contentScale = ContentScale.Crop,
        modifier = modifier
            .clip(shape)
            .background(color = MaterialTheme.colors.surface)
    )
}

Then we will just call the composable anywhere in app screens.

LoadNetworkImage(
    imageUrl = "https://image_url",
    contentDescription = stringResource(R.string.cd_movie_poster),
    modifier = Modifier.size(100.dp, 150.dp),
    shape = MaterialTheme.shapes.medium,
)

🎨 App Theme

🌈 Material Design 3.

Followed theming and color practices from Material Theme Builder Web Tool. Learn more here

Color.kt

// Light theme colors
val light_primary = Color(0xFFaa370c)
val light_onPrimary = Color(0xFFffffff)
val light_background = Color(0xFFFFFAF9)
val light_onBackground = Color(0xFF211a18)
val light_surface = Color(0xFFFFE6DB)
val light_onSurface = Color(0xFF211a18)

// Dark theme colors
val dark_primary = Color(0xFFffb59c)
val dark_onPrimary = Color(0xFF5f1600)
val dark_background = Color(0xFF211a18)
val dark_onBackground = Color(0xFFede0dc)
val dark_surface = Color(0xFF302522)
val dark_onSurface = Color(0xFFede0dc)

Theme.kt

val LightColorPalette = lightColors(
    primary = light_primary,
    onPrimary = light_onPrimary,
    background = light_background,
    onBackground = light_onBackground,
    surface = light_surface,
    onSurface = light_onSurface,
)

val DarkColorPalette = darkColors(
    primary = dark_primary,
    onPrimary = dark_onPrimary,
    background = dark_background,
    onBackground = dark_onBackground,
    surface = dark_surface,
    onSurface = dark_onSurface
)

βšͺ⚫ Light/Dark theme screenshots

Home Search Detail
Home Dark
Home Light
Search Dark
Search Light
Detail Dark
Detail Light

πŸ“ Blog

Article banner
Reveal effect animations in compose jetpack android
Read article
Article banner
Compose and build android app with new architecture principles
Read article
Article banner
Custom shape animations pulsating circles on canvas in compose android
Read article
Article banner
Search with TextField in list Compose Android Jetpack
Read article

AppPreview

πŸ’‘ Motivation and Context

Jetpack Compose is Android’s modern toolkit for building native UI. It enables you to quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Understanding to implement own Theme Shape Typography Color has became bit easier by referring to lot of official jetpack compose samples which are available in GitHub.

Best of all we got to do this in Kotlin way. Excited and long way to go from here.

πŸ† Credits

πŸš€ JetCaster

Check the official JetCaster example from Android Team, I have used their code to generate Swatch with Palette Api in my Detail screen.

πŸ”‘ Tmdb Api

Images and all information in app belongs to and taken from Tmdb Api. I do not own any of it and only made use of it for this app demonstration purpose.

Obtain your own Tmdb Api Key from here

License

Copyright 2021 Rajasekhar K E

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].