Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples and update dependencies #34

Merged
merged 68 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
dc656c5
Code refactor
ImaginativeShohag Jul 1, 2023
39379aa
Exclude `icon.svg` from `.gitignore`
ImaginativeShohag Jul 3, 2023
7b6c4cd
Exclude `.idea/icon.svg` from `.gitignore`
ImaginativeShohag Jul 3, 2023
92491ff
Rename `SquireCropImage` to `CropImage`, ratio can be set from the pa…
ImaginativeShohag Jul 9, 2023
08bdae3
Remove unnecessary permission
ImaginativeShohag Jul 9, 2023
2dbd2cb
Refactor email validation code
ImaginativeShohag Jul 9, 2023
d03461e
Refactor code
ImaginativeShohag Jul 19, 2023
f044235
Add deep link example
ImaginativeShohag Sep 18, 2023
aa4ff20
Add domain verification stats, add more docs
ImaginativeShohag Sep 19, 2023
ecad1ff
Refactor code, Update `README.md`
ImaginativeShohag Sep 19, 2023
ad439c4
Apply spotless
ImaginativeShohag Sep 19, 2023
d7b5921
Add deep links gif to `README.md`
ImaginativeShohag Sep 19, 2023
133ca3c
Merge pull request #27 from ImaginativeShohag/deep-link
ImaginativeShohag Sep 19, 2023
7a07f1f
Merge pull request #28 from ImaginativeShohag/author-module
ImaginativeShohag Sep 19, 2023
20fa26c
Update `README.md`
ImaginativeShohag Sep 19, 2023
c06fe8d
Update `Fastlane`
ImaginativeShohag Sep 21, 2023
5e979c4
Add `SUPPLY_UPLOAD_MAX_RETRIES` to Fastlane
ImaginativeShohag Sep 21, 2023
3550896
Add BMC button
ImaginativeShohag Sep 21, 2023
3a10055
Merge pull request #29 from ImaginativeShohag/update-cicd
ImaginativeShohag Sep 21, 2023
90dd098
Upgrade libs
ImaginativeShohag Oct 20, 2023
4e65d9b
Fix ktlint issues
ImaginativeShohag Oct 20, 2023
dbb0c94
Merge pull request #30 from ImaginativeShohag/apply-ktlint
ImaginativeShohag Oct 20, 2023
69bb74c
Remove unnecessary rules form `kt` file
ImaginativeShohag Oct 23, 2023
b3a3b06
Remove unnecessary permissions
ImaginativeShohag Nov 7, 2023
a8d51e7
Add more example for select image screen
ImaginativeShohag Nov 9, 2023
b9a8a53
Fix map issue
ImaginativeShohag Nov 29, 2023
b5b72d7
Add storage cache using shared preference
ImaginativeShohag Nov 29, 2023
61b5628
Refactor `object` with `data object`
ImaginativeShohag Nov 30, 2023
cbbb3ad
Add navigation data pass example
ImaginativeShohag Nov 30, 2023
68f64db
Apply spotless
ImaginativeShohag Nov 30, 2023
093cc21
Add example for parameter data pass
ImaginativeShohag Nov 30, 2023
f318e0b
Apply spotless
ImaginativeShohag Nov 30, 2023
6472756
Update moshi
ImaginativeShohag Nov 30, 2023
3af42d8
Update dependency
ImaginativeShohag Dec 2, 2023
d7a86ee
Merge pull request #33 from ImaginativeShohag/navigation-datapass
ImaginativeShohag Dec 2, 2023
ef5106a
Merge pull request #31 from ImaginativeShohag/memory-cache
ImaginativeShohag Dec 2, 2023
c8aacc5
Update `README.md`
ImaginativeShohag Dec 2, 2023
af98a4e
Merge pull request #32 from ImaginativeShohag/apply-ktlint
ImaginativeShohag Dec 2, 2023
de61603
Add new preview templates
ImaginativeShohag Dec 6, 2023
f2aeea9
Add ractive model example
ImaginativeShohag Dec 6, 2023
e93c048
Refactor code
ImaginativeShohag Dec 7, 2023
d44ece9
Refactor reactive model
ImaginativeShohag Dec 7, 2023
e04b552
Add memory cache example with data passing
ImaginativeShohag Dec 12, 2023
accdc7a
Refactor code
ImaginativeShohag Dec 12, 2023
4d05e2d
Apply spotless
ImaginativeShohag Dec 12, 2023
bfbabc8
Refactor code
ImaginativeShohag Dec 12, 2023
74e547b
Update data return-back code
ImaginativeShohag Dec 13, 2023
e4d9bdc
Update memory cache code, add documentation
ImaginativeShohag Dec 13, 2023
4ddafe1
Update memory cache code, add result extension
ImaginativeShohag Dec 14, 2023
4dbb82f
Update data pass code
ImaginativeShohag Dec 20, 2023
098bbc8
Fix `navArg` to restore issue
ImaginativeShohag Dec 20, 2023
36cf33a
Update `README.md`
ImaginativeShohag Dec 20, 2023
d9778fb
Apply spotless
ImaginativeShohag Dec 20, 2023
9ec3201
Add alternative solution fro `nullableSaver`
ImaginativeShohag Dec 22, 2023
1b1137b
Update dependency resolution
ImaginativeShohag Dec 22, 2023
18db78a
Add suppress
ImaginativeShohag May 23, 2024
fc0741b
Update to Kotlin 2.0
ImaginativeShohag Jun 3, 2024
f36d765
Remove deprecated code
ImaginativeShohag Jun 3, 2024
3fb4ace
feat(navigation): Migrate CMS module navigation
ImaginativeShohag Jun 3, 2024
3c0bc96
fix(cms-sheet): Fix black top space in appbar, fix sheet background c…
ImaginativeShohag Jun 4, 2024
602c47d
fix(cms-sheet): Fix sheet not correctly hidden issue
ImaginativeShohag Jun 4, 2024
14a21e2
build(release): Change version
ImaginativeShohag Jun 4, 2024
b883db5
refactor: Apply spotless
ImaginativeShohag Jun 4, 2024
fa9ca32
Merge pull request #37 from ImaginativeShohag/migrate-navigation
ImaginativeShohag Jun 4, 2024
9d87cfe
Merge pull request #36 from ImaginativeShohag/memory-cache
ImaginativeShohag Jun 7, 2024
5cbc026
Merge pull request #38 from ImaginativeShohag/reactive-model
ImaginativeShohag Jun 7, 2024
e8eecdb
feat(dark-light-theme): Add auto ui theme mode
ImaginativeShohag Jun 7, 2024
e70e67a
Merge pull request #39 from ImaginativeShohag/refactor-theme-change
ImaginativeShohag Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/local.properties
.DS_Store
/captures
.kotlin

# Source: https://github.com/github/gitignore/blob/master/Android.gitignore

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Feel free to request features or suggestions for improvements.
- CMS (Advanced)
- Memory and storage caching
- [Deep Link](https://developer.android.com/training/app-links) (Intermediate)
- Navigation Data Pass (Intermediate)
- Reactive Model (Beginner)

| ![Counter](images/counter.gif) | ![Animated Visibility](images/animated-visibility.gif) | ![Lottie](images/lottie.gif) |
|:------------------------------------:|:------------------------------------------------------:|:----------------------------:|
Expand Down
8 changes: 4 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ plugins {
id(Libs.Android.application)
kotlin("android")
kotlin("kapt")
id(Libs.Kotlin.composeCompilerGradlePlugin)
id(Libs.Google.DevTools.ksp)
id(Libs.Kotlin.percelizeGradlePlugin)
id(Libs.Google.Hilt.gradlePlugin)
Expand All @@ -45,7 +46,7 @@ android {
minSdk = BuildConfigConst.minSdk
targetSdk = BuildConfigConst.targetSdk
versionCode = (findProperty("android.injected.version.code") as? String)?.toIntOrNull() ?: 1
versionName = "5.0.1.${getCurrentDateAsYYMMDD()}" // Major.Minor.Patch.YYMMDD
versionName = "6.0.0.${getCurrentDateAsYYMMDD()}" // Major.Minor.Patch.YYMMDD
vectorDrawables.useSupportLibrary = true

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -110,8 +111,8 @@ android {
shaders = false
}

composeOptions {
kotlinCompilerExtensionVersion = Libs.AndroidX.Compose.compilerVersion
composeCompiler {
enableStrongSkippingMode = true
}

signingConfigs {
Expand Down Expand Up @@ -151,7 +152,6 @@ dependencies {
// ----------------------------------------------------------------
implementation(platform(Libs.AndroidX.Compose.bom))

implementation(Libs.AndroidX.Compose.compiler)
implementation(Libs.AndroidX.Compose.ui)
implementation(Libs.AndroidX.Compose.uiUtil)
// Tooling support (Previews, etc.)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<application
android:name=".App"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.addCallback
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
Expand All @@ -58,7 +58,10 @@ class MainActivity : ComponentActivity() {
installSplashScreen()
super.onCreate(savedInstanceState)

WindowCompat.setDecorFitsSystemWindows(window, false)
// Turn off the decor fitting system windows, which allows us to handle insets,
// including IME animations, and go edge-to-edge
// This also sets up the initial system bar style based on the platform theme
enableEdgeToEdge()

UIThemeController.updateUITheme(sharedPref.getDarkMode())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,19 @@

package org.imaginativeworld.whynotcompose.ui.screens

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Text
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
Expand All @@ -42,6 +49,10 @@ import androidx.navigation.navArgument
import androidx.navigation.navigation
import org.imaginativeworld.whynotcompose.base.extensions.getJsonFromObj
import org.imaginativeworld.whynotcompose.base.extensions.getObjFromJson
import org.imaginativeworld.whynotcompose.base.extensions.navArg
import org.imaginativeworld.whynotcompose.base.extensions.navResult
import org.imaginativeworld.whynotcompose.base.extensions.navigate
import org.imaginativeworld.whynotcompose.base.extensions.popBackStackWithResult
import org.imaginativeworld.whynotcompose.cms.ui.screens.CMSMainScreen
import org.imaginativeworld.whynotcompose.exoplayer.ExoPlayerScreen
import org.imaginativeworld.whynotcompose.models.DemoData
Expand Down Expand Up @@ -100,12 +111,15 @@ import org.imaginativeworld.whynotcompose.ui.screens.tutorial.datafetchandpaging
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.deeplinks.DeepLinksScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.index.TutorialIndexScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.lottie.LottieScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.navdatapass.NavDataPassFourScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.navdatapass.NavDataPassHomeScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.navdatapass.NavDataPassOneScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.navdatapass.NavDataPassThreeScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.navdatapass.NavDataPassTwoScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.onesignalandbroadcast.OneSignalAndBroadcastScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.permission.PermissionScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.reactivemodel.ReactiveModelScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.reactivemodel.ReactiveModelViewModel
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.selectimageandcrop.SelectImageAndCropScreen
import org.imaginativeworld.whynotcompose.ui.screens.tutorial.selectimageandcrop.SelectImageAndCropViewModel
import org.imaginativeworld.whynotcompose.ui.screens.ui.index.UiIndexScreen
Expand Down Expand Up @@ -215,8 +229,12 @@ sealed class TutorialsScreen(val route: String) {
data object TutorialCMS : TutorialsScreen("tutorial/cms")
data object TutorialDeepLink : TutorialsScreen("tutorial/deep-link")

// ================================================================
// Navigation pass-receive example
// ================================================================

data object TutorialNavDataPassHome : TutorialsScreen("tutorial/nav-data-pass/home") {
const val KEY_RECEIVED_DATA = "received_data"
const val RESULT_KEY_DATA = "received_data"
}

data object TutorialNavDataPassScreen1 :
Expand All @@ -240,6 +258,28 @@ sealed class TutorialsScreen(val route: String) {
.replace("{$PARAM_ID}", "$id")
.replace("{$PARAM_NAME}", name)
}

data object TutorialNavDataPassScreen4 :
TutorialsScreen("tutorial/nav-data-pass/four/details/{id}") {
const val PARAM_ID = "id"

const val RESULT_DATA = "data"
const val ARG_NAME = "name"
const val ARG_RANKS = "ranks"

fun createRoute(id: Int) =
route
.replace("{$PARAM_ID}", "$id")
}

data object TutorialNavDataPassScreen5 :
TutorialsScreen("tutorial/nav-data-pass/five/details")

// ================================================================
// Reactive model
// ================================================================

data object TutorialReactiveModel : TutorialsScreen("tutorial/reactive-model")
}

// ================================================================
Expand Down Expand Up @@ -922,22 +962,34 @@ private fun NavGraphBuilder.addTutorialIndexScreen(
// Navigation pass-receive example
// ================================================================

composable(TutorialsScreen.TutorialNavDataPassHome.route) { backStateEntry ->
val receivedData = backStateEntry.savedStateHandle.get<DemoData>(
TutorialsScreen.TutorialNavDataPassHome.KEY_RECEIVED_DATA
composable(TutorialsScreen.TutorialNavDataPassHome.route) { backStackEntry ->
// Observe for receive data using `SavedStateHandle`.
// Pros: Using official `SavedStateHandle`.
// Cons: The data need to be remove manually after use.
val resultDataBySavedState = backStackEntry.savedStateHandle
.getLiveData<DemoData>(TutorialsScreen.TutorialNavDataPassHome.RESULT_KEY_DATA)
.observeAsState()

// Receive result using Memory Cache.
// Pros: It will be reset automatically.
// Cons: It need Memory Cache.
val resultDataByMemoryCache: DemoData? = navResult(
TutorialsScreen.TutorialNavDataPassScreen4.RESULT_DATA
)

NavDataPassHomeScreen(
receivedData = receivedData,
receivedDataBySavedState = resultDataBySavedState.value,
receivedDataByMemoryCache = resultDataByMemoryCache,
goBack = {
navController.popBackStack()
},
gotoScreenOne = { item ->
navController.navigate(TutorialsScreen.TutorialNavDataPassScreen1.createRoute(item))
},
gotoScreenTwo = { item ->
// Navigate with passing data using `savedStateHandle`.
// Equivalent: navController.currentBackStackEntry?.savedStateHandle
backStateEntry.savedStateHandle.apply {
backStackEntry.savedStateHandle.apply {
set(
TutorialsScreen.TutorialNavDataPassScreen2.PARAM_DATA,
item
Expand All @@ -946,12 +998,27 @@ private fun NavGraphBuilder.addTutorialIndexScreen(
navController.navigate(TutorialsScreen.TutorialNavDataPassScreen2.route)
},
gotoScreenThree = { id, name ->
// Navigate with passing data using default `arguments` system in `NavController`. (Recommended)
navController.navigate(
TutorialsScreen.TutorialNavDataPassScreen3.createRoute(
id = id,
name = name
)
)
},
gotoScreenFour = { id, name ->
// Navigate with passing data using custom Memory Cache.
navController.navigate(
TutorialsScreen.TutorialNavDataPassScreen4.createRoute(id = id),
args = mapOf(
TutorialsScreen.TutorialNavDataPassScreen4.ARG_NAME to name,
TutorialsScreen.TutorialNavDataPassScreen4.ARG_RANKS to listOf(
"A",
"B",
"C"
)
)
)
}
)
}
Expand All @@ -964,30 +1031,32 @@ private fun NavGraphBuilder.addTutorialIndexScreen(
}
)
) { backStackEntry ->
backStackEntry.arguments?.let { args ->
val data = args.getString(TutorialsScreen.TutorialNavDataPassScreen1.PARAM_DATA)
.getObjFromJson<DemoData>() ?: throw Exception("Data cannot be null!")
// Receive parameters using default `NavController` route system.
val receivedData = backStackEntry.arguments
?.getString(TutorialsScreen.TutorialNavDataPassScreen1.PARAM_DATA)
.getObjFromJson<DemoData>() ?: throw Exception("Data cannot be null!")

NavDataPassOneScreen(
data = data,
goBack = {
navController.popBackStack()
},
backWithData = { data ->
navController.previousBackStackEntry
?.savedStateHandle
?.set(
TutorialsScreen.TutorialNavDataPassHome.KEY_RECEIVED_DATA,
data
)
NavDataPassOneScreen(
data = receivedData,
goBack = {
navController.popBackStack()
},
backWithData = { data ->
// Send-back data using `SavedStateHandle`.
navController.previousBackStackEntry
?.savedStateHandle
?.set(
TutorialsScreen.TutorialNavDataPassHome.RESULT_KEY_DATA,
data
)

navController.popBackStack()
}
)
}
navController.popBackStack()
}
)
}

composable(TutorialsScreen.TutorialNavDataPassScreen2.route) {
// Receive passed data using `savedStateHandle`.
val data: DemoData? = navController.previousBackStackEntry?.savedStateHandle?.get<DemoData>(
TutorialsScreen.TutorialNavDataPassScreen2.PARAM_DATA
)
Expand All @@ -1014,6 +1083,7 @@ private fun NavGraphBuilder.addTutorialIndexScreen(
var id = 0
var name = ""

// Receive data using default `arguments` system in `NavController`. (Recommended)
backStackEntry.arguments?.apply {
id = getInt(TutorialsScreen.TutorialNavDataPassScreen3.PARAM_ID)
name = getString(TutorialsScreen.TutorialNavDataPassScreen3.PARAM_NAME, "")
Expand All @@ -1027,6 +1097,80 @@ private fun NavGraphBuilder.addTutorialIndexScreen(
}
)
}

composable(
TutorialsScreen.TutorialNavDataPassScreen4.route,
arguments = listOf(
navArgument(TutorialsScreen.TutorialNavDataPassScreen3.PARAM_ID) {
type = NavType.IntType
}
)
) { backStackEntry ->
val id = backStackEntry.arguments
?.getInt(TutorialsScreen.TutorialNavDataPassScreen4.PARAM_ID)
?: throw Exception("Id cannot be null!")

// Receive data using custom Memory Cache.
val name = navArg<String>(
TutorialsScreen.TutorialNavDataPassScreen4.ARG_NAME
).value ?: throw Exception("Name cannot be null!")
val ranks = navArg<List<String>>(
TutorialsScreen.TutorialNavDataPassScreen4.ARG_RANKS
).value ?: throw Exception("Ranks cannot be null!")

NavDataPassFourScreen(
id = id,
name = name,
ranks = ranks,
goBack = {
navController.popBackStack()
},
backWithData = { data ->
// Send-back data using Memory Cache.
navController.popBackStackWithResult(
TutorialsScreen.TutorialNavDataPassScreen4.RESULT_DATA to data
)
},
goAnotherScreen = {
navController.navigate(
TutorialsScreen.TutorialNavDataPassScreen5.route
)
}
)
}

composable(TutorialsScreen.TutorialNavDataPassScreen5.route) {
Column(
Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Hello World!")

Spacer(Modifier.height(16.dp))

Button(onClick = {
navController.popBackStack()
}) {
Text("Go Back")
}
}
}

// ================================================================
// Reactive model
// ================================================================

composable(TutorialsScreen.TutorialReactiveModel.route) {
val viewModel: ReactiveModelViewModel = hiltViewModel()

ReactiveModelScreen(
viewModel = viewModel,
goBack = {
navController.popBackStack()
}
)
}
}

// ================================================================
Expand Down
Loading