Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .idea/gradle.xml

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

1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ android-application = { id = "com.android.application", version.ref = "agpVersio
android-library = { id = "com.android.library", version.ref = "agpVersion" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinVersion" }
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlinVersion" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlinVersion" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
google-services = { id = "com.google.gms.google-services", version.ref = "googleServicesVersion" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ suspend fun HttpClient.downloadFile(
}
}

suspend fun HttpClient.fetchBitmap(url: String): Bitmap? =
try {
suspend fun HttpClient.fetchBitmap(url: String): Bitmap? {
return try {
if (url.isBlank()) return null
val bytes: ByteArray = get(url).body()
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
1 change: 1 addition & 0 deletions modules/lyrics-maker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ android {

dependencies {
implementation project(path: ':modules:core')
implementation project(path: ':modules:motion-video-editor')
implementation libs.androidx.appcompat
implementation libs.google.android.material
implementation libs.androidx.activity
Expand Down
1 change: 1 addition & 0 deletions modules/lyrics-maker/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<activity
android:name=".presentation.activity.SearchActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/Theme.Animator">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,21 @@ class AlbumArtRemoteDataSourceImpl(

override suspend fun fetchBitmap(url: String): Bitmap? =
withContext(Dispatchers.IO) {
val request = Request.Builder().url(url).build()
try {
if (url.isBlank()) {
return@withContext null
}
val request = Request.Builder().url(url).build()

client.newCall(request).execute().use { response ->
if (!response.isSuccessful) return@withContext null
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) return@withContext null

val bytes = response.body()?.bytes() ?: return@withContext null
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
val bytes = response.body()?.bytes() ?: return@withContext null
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
}
} catch (e: Exception) {
Timber.e(e, "fetchBitmap failed for url: $url")
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.core.app.ActivityCompat
import androidx.core.content.FileProvider
Expand Down Expand Up @@ -57,7 +59,6 @@ class SearchActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
LyricsMotionWorker.cancelAllWork(applicationContext)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ActivityCompat.checkSelfPermission(
Expand All @@ -73,31 +74,33 @@ class SearchActivity : ComponentActivity() {
}
}

val metadata = ShareReceiverActivity.readMetadataFromIntent(intent)
metadata?.let {
lyricsViewModel.socialMeta.value = it
lyricsViewModel.query.value = it.title ?: it.description ?: ""
lyricsViewModel.searchLyrics(it.title ?: it.description ?: "")
}
handleIntent(intent)

setContent {
val navController = rememberNavController()
LaunchedEffect(metadata) {
if (metadata != null) {
navController.navigate(Screen.Search.route)
val socialMeta by lyricsViewModel.socialMeta.collectAsState()

LaunchedEffect(socialMeta) {
if (socialMeta.title != null || socialMeta.description != null) {
navController.navigate(Screen.Search.route) {
launchSingleTop = true
}
}
}

AnimatorTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Scaffold(
modifier = Modifier.fillMaxSize(),
contentWindowInsets = WindowInsets(0, 0, 0, 0),
) { _ ->
AppNavHost(
navController = navController,
projectsViewModel = projectsViewModel,
onProjectClick = { motionProject ->
navController.navigate(Screen.ProjectDetails.createRoute(motionProject.id))
},
lyricsViewModel = lyricsViewModel,
modifier = Modifier.padding(innerPadding),
modifier = Modifier, // Padding handled by internal screens
)
}
}
Expand Down Expand Up @@ -128,6 +131,24 @@ class SearchActivity : ComponentActivity() {
}
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleIntent(intent)
}

private fun handleIntent(intent: Intent?) {
LyricsMotionWorker.cancelAllWork(applicationContext)
intent?.let {
val metadata = ShareReceiverActivity.readMetadataFromIntent(it)
metadata?.let { socialMeta ->
lyricsViewModel.socialMeta.value = socialMeta
lyricsViewModel.query.value = socialMeta.title ?: socialMeta.description ?: ""
lyricsViewModel.searchLyrics(socialMeta.title ?: socialMeta.description ?: "")
}
}
}

/**
* Share Project
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.tejpratapsingh.lyricsmaker.asLyricsApp
import com.tejpratapsingh.lyricsmaker.domain.ensureArrayList
import com.tejpratapsingh.lyricsmaker.presentation.motion.extractLyricsTemplateData
import com.tejpratapsingh.lyricsmaker.presentation.viewmodel.LyricsViewModel
import com.tejpratapsingh.lyricsmaker.presentation.viewmodel.ProjectsViewModel
import com.tejpratapsingh.motioneditor.ui.MotionEditorScreen
import com.tejpratapsingh.motionlib.core.MotionConfig
import com.tejpratapsingh.motionlib.core.VideoAspectRatio
import com.tejpratapsingh.motionlib.core.extensions.md5
import com.tejpratapsingh.motionlib.templates.sdui.MotionTemplateSDUIProvider
import com.tejpratapsingh.motionstore.tables.MotionProject

sealed class Screen(
Expand All @@ -31,6 +36,10 @@ sealed class Screen(
object ProjectDetails : Screen("project_details/{projectId}") {
fun createRoute(projectId: String) = "project_details/$projectId"
}

object VideoEditor : Screen("video_editor/{projectId}") {
fun createRoute(projectId: String) = "video_editor/$projectId"
}
}

@Composable
Expand Down Expand Up @@ -128,13 +137,63 @@ fun AppNavHost(
it.metadata.addProperty("template", template.name)
// Clear old SDUI if any
it.metadata.remove("sdui")

navController.context.asLyricsApp().motionStoreDao.upsert(it)

val templateData = extractLyricsTemplateData(it)

val config =
MotionConfig(
aspectRatio = VideoAspectRatio.Ratio9x16_480,
fps = 24,
)

// Generate and save SDUI
val sdui =
MotionTemplateSDUIProvider.provideSDUI(
context = navController.context,
template = template,
data = templateData,
config = config,
)

val updatedProject = it.copy(sdui = sdui)

navController.context
.asLyricsApp()
.motionStoreDao
.upsert(updatedProject)

projectsViewModel.loadProjects()
navController.navigate(Screen.ProjectDetails.createRoute(it.id)) {

navController.navigate(Screen.VideoEditor.createRoute(it.id)) {
// Pop the template selector so back from details goes to lyrics
popUpTo(Screen.TemplateSelector.route) { inclusive = true }
launchSingleTop = true
}
},
modifier = modifier,
)
}
}

composable(route = Screen.VideoEditor.route) { backStackEntry ->
val projectId = backStackEntry.arguments?.getString("projectId")
val projects = projectsViewModel.projects.collectAsStateWithLifecycle()
val project = projects.value.find { it.id == projectId }

project?.let {
MotionEditorScreen(
project = it,
onBackClick = { navController.popBackStack() },
onSaveClick = { updatedProject ->
navController.context
.asLyricsApp()
.motionStoreDao
.upsert(updatedProject)

projectsViewModel.loadProjects()
navController.navigate(Screen.ProjectDetails.createRoute(updatedProject.id)) {
popUpTo(Screen.Projects.route) { inclusive = false }
launchSingleTop = true
}
},
modifier = modifier,
Expand All @@ -151,6 +210,11 @@ fun AppNavHost(
ProjectDetailsScreen(
project = it,
onBackClick = { navController.popBackStack() },
onEditClick = { p ->
navController.navigate(Screen.VideoEditor.createRoute(p.id)) {
launchSingleTop = true
}
},
onShareClick = { p -> projectsViewModel.shareProject(p) },
modifier = modifier,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.tejpratapsingh.lyricsmaker.presentation.ui.theme.ThemeBlue
import com.tejpratapsingh.lyricsmaker.presentation.ui.theme.ThemePink

Expand All @@ -21,6 +27,14 @@ fun GradientText(
text: String,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val malamPoek =
remember(context) {
FontFamily(
Font(path = "fonts/Malam_Poek.ttf", assetManager = context.assets),
)
}

val infiniteTransition = rememberInfiniteTransition(label = "shimmer")
val offset by infiniteTransition.animateFloat(
initialValue = 0f,
Expand All @@ -35,22 +49,30 @@ fun GradientText(

val gradientColors =
listOf(
ThemeBlue,
ThemePink,
ThemeBlue,
)

Text(
text = text,
style =
MaterialTheme.typography.displayMedium.copy(
fontFamily = malamPoek,
brush =
Brush.linearGradient(
colors = gradientColors,
start = Offset(offset, offset),
end = Offset(offset + 5f, offset + 5f),
),
fontSize = 48.sp,
),
fontWeight = FontWeight.ExtraBold,
modifier = modifier,
)
}

@Preview(showBackground = true)
@Composable
fun GradientTextPreview() {
GradientText(text = "Lyrics Maker")
}
Loading
Loading