Skip to content

Commit 75497a9

Browse files
authored
Merge pull request #16 from tuuhin/enhancements
Fixes: Bugs, Visualizations, and Enhancements over the recorder and player
2 parents ea9c384 + f8e7bf6 commit 75497a9

97 files changed

Lines changed: 1538 additions & 1119 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
.externalNativeBuild
1515
.cxx
1616
local.properties
17+
keystore.properties

.idea/compiler.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deploymentTargetSelector.xml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deviceManager.xml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/kotlinc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle.kts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,53 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
12
import java.util.Properties
23

34
plugins {
45
alias(libs.plugins.android.application)
56
alias(libs.plugins.jetbrains.kotlin.android)
6-
77
alias(libs.plugins.recorderapp.hilt)
88
alias(libs.plugins.recorderapp.compose.compiler)
99
}
1010

1111
android {
1212
namespace = "com.eva.recorderapp"
13-
compileSdk = 35
13+
compileSdk = libs.versions.compileSdk.get().toInt()
1414

1515
defaultConfig {
1616
applicationId = "com.eva.recorderapp"
17-
minSdk = 29
18-
targetSdk = 35
19-
versionCode = 8
20-
versionName = "1.3.0"
17+
minSdk = libs.versions.minSdk.get().toInt()
18+
targetSdk = libs.versions.compileSdk.get().toInt()
19+
versionCode = 9
20+
versionName = "1.3.1"
2121

2222
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2323
vectorDrawables {
2424
useSupportLibrary = true
2525
}
26+
}
2627

27-
rootProject.file("developer.properties").inputStream().use {
28-
val localProperties = Properties()
29-
localProperties.load(it)
28+
signingConfigs {
29+
// find if there is a properties file
30+
val keySecretFile = rootProject.file("keystore.properties")
31+
if (!keySecretFile.exists()) return@signingConfigs
3032

31-
buildConfigField(
32-
"String",
33-
"GITHUB_PROFILE_LINK",
34-
"\"${localProperties.getProperty("GITHUB_PROFILE_LINK")}\""
35-
)
33+
// load the properties
34+
val properties = Properties()
35+
keySecretFile.inputStream().use { properties.load(it) }
3636

37-
buildConfigField(
38-
"String",
39-
"GITHUB_PROJECT_LINK",
40-
"\"${localProperties.getProperty("GITHUB_PROJECT_LINK")}\""
41-
)
37+
val userHome = System.getProperty("user.home")
38+
val storeFileName = properties.getProperty("STORE_FILE_NAME")
39+
40+
val keyStoreFolder = File(userHome, "keystore")
41+
if (!keyStoreFolder.exists()) return@signingConfigs
42+
43+
val keyStoreFile = File(keyStoreFolder, storeFileName)
44+
if (!keyStoreFile.exists()) return@signingConfigs
45+
46+
create("release") {
47+
storeFile = keyStoreFile
48+
keyAlias = properties.getProperty("KEY_ALIAS")
49+
keyPassword = properties.getProperty("KEY_PASSWORD")
50+
storePassword = properties.getProperty("STORE_PASSWORD")
4251
}
4352
}
4453

@@ -48,7 +57,8 @@ android {
4857
applicationIdSuffix = ".release"
4958
isShrinkResources = true
5059
multiDexEnabled = true
51-
signingConfig = signingConfigs.getByName("debug")
60+
// change the signing config if release is not found
61+
signingConfig = signingConfigs.findByName("release")
5262
proguardFiles(
5363
getDefaultProguardFile("proguard-android-optimize.txt"),
5464
"proguard-rules.pro"
@@ -59,9 +69,6 @@ android {
5969
sourceCompatibility = JavaVersion.VERSION_17
6070
targetCompatibility = JavaVersion.VERSION_17
6171
}
62-
kotlinOptions {
63-
jvmTarget = "17"
64-
}
6572
buildFeatures {
6673
compose = true
6774
buildConfig = true
@@ -73,6 +80,12 @@ android {
7380
}
7481
}
7582

83+
kotlin {
84+
compilerOptions {
85+
jvmTarget = JvmTarget.JVM_17
86+
}
87+
}
88+
7689
dependencies {
7790

7891
implementation(libs.androidx.core.ktx)

app/src/main/java/com/eva/recorderapp/MainActivity.kt

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,93 +2,128 @@ package com.eva.recorderapp
22

33
import android.animation.AnimatorSet
44
import android.animation.ObjectAnimator
5-
import android.app.Activity
65
import android.content.Intent
76
import android.os.Bundle
87
import android.view.View
98
import android.view.animation.AccelerateDecelerateInterpolator
9+
import android.view.animation.AccelerateInterpolator
10+
import android.view.animation.DecelerateInterpolator
1011
import androidx.activity.ComponentActivity
1112
import androidx.activity.compose.setContent
1213
import androidx.activity.enableEdgeToEdge
1314
import androidx.compose.material3.MaterialTheme
1415
import androidx.compose.material3.Surface
1516
import androidx.core.animation.doOnEnd
17+
import androidx.core.animation.doOnStart
18+
import androidx.core.splashscreen.SplashScreen
1619
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
1720
import androidx.navigation.NavHostController
18-
import androidx.navigation.compose.rememberNavController
1921
import com.eva.recorderapp.navigation.AppNavHost
2022
import com.eva.ui.theme.RecorderAppTheme
2123
import dagger.hilt.android.AndroidEntryPoint
2224

2325
@AndroidEntryPoint
2426
class MainActivity : ComponentActivity() {
2527

26-
private lateinit var navController: NavHostController
28+
private var navController: NavHostController? = null
2729

2830
override fun onCreate(savedInstanceState: Bundle?) {
2931

30-
// configure splash screen
31-
configureSplashScreen(onAnimationEnd = { enableEdgeToEdge() })
32+
val splash = installSplashScreen()
3233

3334
super.onCreate(savedInstanceState)
3435

35-
// if enabled edge to edge not applied after animation
36+
// set enable edge to edge normally
3637
enableEdgeToEdge()
38+
// on splash complete again enable edge to edge
39+
splash.animateOnExit(onAnimationEnd = { enableEdgeToEdge() })
3740

38-
setContent {
39-
40-
navController = rememberNavController()
4141

42+
setContent {
4243
RecorderAppTheme {
4344
Surface(color = MaterialTheme.colorScheme.background) {
44-
AppNavHost(navController = navController)
45+
AppNavHost(
46+
onSetController = { controller ->
47+
if (navController == null) navController = controller
48+
},
49+
)
4550
}
4651
}
4752
}
4853
}
4954

5055
override fun onNewIntent(intent: Intent) {
5156
super.onNewIntent(intent)
52-
navController.handleDeepLink(intent)
57+
navController?.handleDeepLink(intent)
5358
}
5459
}
5560

56-
private fun Activity.configureSplashScreen(onAnimationEnd: () -> Unit = {}) {
57-
val splash = installSplashScreen()
61+
private fun SplashScreen.animateOnExit(
62+
onAnimationStart: () -> Unit = {},
63+
onAnimationEnd: () -> Unit = {}
64+
) {
65+
val screenViewDuration = 200L
5866

59-
splash.setOnExitAnimationListener { screenView ->
60-
// do all the animation is reverse way
67+
setOnExitAnimationListener { screenView ->
68+
// do all the animation is a reverse way
6169
val interpolator = AccelerateDecelerateInterpolator()
62-
val duration = 1000L
6370

64-
val scaleXAnimation = ObjectAnimator
71+
val iconScaleXAnimation = ObjectAnimator
6572
.ofFloat(screenView.iconView, View.SCALE_X, 1f, 0.5f)
6673
.apply {
6774
this.interpolator = interpolator
68-
this.duration = duration
75+
this.duration = screenView.iconAnimationDurationMillis
6976
}
7077

71-
val scaleYAnimation = ObjectAnimator
78+
val iconScaleYAnimation = ObjectAnimator
7279
.ofFloat(screenView.iconView, View.SCALE_Y, 1f, 0.5f)
7380
.apply {
7481
this.interpolator = interpolator
75-
this.duration = duration
82+
this.duration = screenView.iconAnimationDurationMillis
7683
}
7784

78-
val translateAnimation = ObjectAnimator
85+
val iconTranslateYAnimation = ObjectAnimator
7986
.ofFloat(screenView.iconView, View.TRANSLATION_Y, 0.0f, 20.0f)
8087
.apply {
8188
this.interpolator = interpolator
82-
this.duration = duration
89+
this.duration = screenView.iconAnimationDurationMillis
90+
}
91+
92+
val viewFadeAnimation = ObjectAnimator
93+
.ofFloat(screenView.view, View.ALPHA, 1.0f, .2f)
94+
.apply {
95+
this.interpolator = DecelerateInterpolator()
96+
this.duration = screenViewDuration
8397
}
8498

85-
val animatorSet = AnimatorSet().apply {
86-
playTogether(scaleXAnimation, scaleYAnimation, translateAnimation)
99+
val viewTranslateAnimation = ObjectAnimator.ofFloat(
100+
screenView.view,
101+
View.TRANSLATION_Y,
102+
0f,
103+
screenView.view.height.toFloat()
104+
).apply {
105+
this.interpolator = AccelerateInterpolator()
106+
this.duration = screenViewDuration
107+
}
108+
109+
val viewAnimatorSet = AnimatorSet().apply {
110+
playTogether(viewFadeAnimation, viewTranslateAnimation)
87111
doOnEnd {
88112
screenView.remove()
89113
onAnimationEnd()
90114
}
91115
}
92-
animatorSet.start()
116+
117+
val iconAnimatorSet = AnimatorSet().apply {
118+
playTogether(
119+
iconScaleXAnimation,
120+
iconScaleYAnimation,
121+
iconTranslateYAnimation
122+
)
123+
doOnEnd { viewAnimatorSet.start() }
124+
doOnStart { onAnimationStart() }
125+
126+
}
127+
iconAnimatorSet.start()
93128
}
94129
}

app/src/main/java/com/eva/recorderapp/navigation/AppNavHost.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import androidx.compose.animation.SharedTransitionLayout
55
import androidx.compose.material3.SnackbarHostState
66
import androidx.compose.runtime.Composable
77
import androidx.compose.runtime.CompositionLocalProvider
8+
import androidx.compose.runtime.LaunchedEffect
9+
import androidx.compose.runtime.getValue
810
import androidx.compose.runtime.remember
11+
import androidx.compose.runtime.rememberUpdatedState
912
import androidx.compose.ui.Modifier
1013
import androidx.navigation.NavHostController
1114
import androidx.navigation.compose.NavHost
@@ -30,8 +33,15 @@ import com.eva.ui.utils.LocalSnackBarProvider
3033
@Composable
3134
fun AppNavHost(
3235
modifier: Modifier = Modifier,
33-
navController: NavHostController = rememberNavController(),
36+
onSetController: suspend (NavHostController) -> Unit = {},
3437
) {
38+
val navController = rememberNavController()
39+
val currentOnSetController by rememberUpdatedState(onSetController)
40+
41+
LaunchedEffect(navController) {
42+
currentOnSetController(navController)
43+
}
44+
3545
val snackBarProvider = remember { SnackbarHostState() }
3646

3747
SharedTransitionLayout {

app/src/main/java/com/eva/recorderapp/navigation/routes/AppInfoDialog.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ import com.eva.recorderapp.BuildConfig
4141
import com.eva.ui.R
4242
import com.eva.ui.navigation.NavDialogs
4343
import com.eva.ui.theme.RecorderAppTheme
44+
import com.eva.utils.ApplicationInfo
4445

4546
fun NavGraphBuilder.appInfoDialog() = dialog<NavDialogs.ApplicationInfo> {
4647
AppDialogInfoContent()
4748
}
4849

50+
4951
@OptIn(ExperimentalLayoutApi::class)
5052
@Composable
5153
private fun AppDialogInfoContent(
@@ -111,7 +113,7 @@ private fun AppDialogInfoContent(
111113
) {
112114
SuggestionChip(
113115
onClick = {
114-
context.launchViewIntent(BuildConfig.GITHUB_PROJECT_LINK.toUri())
116+
context.launchViewIntent(ApplicationInfo.GITHUB_PROJECT_LINK.toUri())
115117
},
116118
label = { Text(text = stringResource(id = R.string.app_info_source_code)) },
117119
shape = MaterialTheme.shapes.large,
@@ -128,7 +130,7 @@ private fun AppDialogInfoContent(
128130
)
129131
SuggestionChip(
130132
onClick = {
131-
context.launchViewIntent(BuildConfig.GITHUB_PROFILE_LINK.toUri())
133+
context.launchViewIntent(ApplicationInfo.PROJECT_AUTHOR_LINK.toUri())
132134
},
133135
label = { Text(text = stringResource(id = R.string.app_info_author)) },
134136
shape = MaterialTheme.shapes.large,
@@ -156,7 +158,7 @@ private fun Context.launchViewIntent(uri: Uri) {
156158
data = uri
157159
startActivity(this)
158160
}
159-
} catch (e: ActivityNotFoundException) {
161+
} catch (_: ActivityNotFoundException) {
160162
Toast.makeText(
161163
applicationContext,
162164
R.string.cannot_launch_activity,

0 commit comments

Comments
 (0)