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
9 changes: 9 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*.iml
.gradle/
.idea/
local.properties
.DS_Store
build/
/captures
.externalNativeBuild
.cxx
8 changes: 8 additions & 0 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.androidLibrary) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.composeMultiplatform) apply false
alias(libs.plugins.composeCompiler) apply false
alias(libs.plugins.kotlinSerialization) apply false
}
63 changes: 63 additions & 0 deletions android/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.androidApplication)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
}

kotlin {
androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
}
}

sourceSets {
commonMain.dependencies {
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.kotlinx.coroutines.core)
}

androidMain.dependencies {
implementation(libs.ktor.client.okhttp)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.ui)
implementation(compose.components.resources)
}
}
}

android {
namespace = "com.computerization.mediafilter"
compileSdk = libs.versions.android.compileSdk.get().toInt()

defaultConfig {
applicationId = "com.computerization.mediafilter"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
}

buildTypes {
release {
isMinifyEnabled = false
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
31 changes: 31 additions & 0 deletions android/composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MediaFilter">

<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/Theme.MediaFilter">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.computerization.mediafilter

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import com.computerization.mediafilter.data.AnalyzeResponse
import com.computerization.mediafilter.ui.MainScreen
import com.computerization.mediafilter.ui.ResultScreen
import kotlinx.coroutines.flow.SharedFlow

@Composable
fun App(
initialSharedText: String?,
sharedTextFlow: SharedFlow<String>
) {
val viewModel = remember { SharedViewModel() }
var currentResult by remember { mutableStateOf<AnalyzeResponse?>(null) }

if (currentResult != null) {
ResultScreen(
result = currentResult!!,
viewModel = viewModel,
onBack = { currentResult = null }
)
} else {
MainScreen(
viewModel = viewModel,
initialSharedText = initialSharedText,
sharedTextFlow = sharedTextFlow,
onNavigateToResult = { result -> currentResult = result }
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.computerization.mediafilter

import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.computerization.mediafilter.theme.MediaFilterTheme
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow

class MainActivity : ComponentActivity() {

private val _sharedTextFlow = MutableSharedFlow<String>(extraBufferCapacity = 1)
val sharedTextFlow = _sharedTextFlow.asSharedFlow()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()

val initialSharedText = handleShareIntent(intent)

setContent {
MediaFilterTheme {
App(
initialSharedText = initialSharedText,
sharedTextFlow = sharedTextFlow
)
}
}
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleShareIntent(intent)?.let { text ->
_sharedTextFlow.tryEmit(text)
}
}

private fun handleShareIntent(intent: Intent): String? {
if (intent.action == Intent.ACTION_SEND && intent.type == "text/plain") {
return intent.getStringExtra(Intent.EXTRA_TEXT)
}
return null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.computerization.mediafilter.theme

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color

object AppColors {
val primaryBlue = Color(0xFF4A8FD9)
val accentGreen = Color(0xFF33C759)
val warningOrange = Color(0xFFFF9900)
val dangerRed = Color(0xFFE64033)

@Composable
fun cardBackground(): Color {
return if (isSystemInDarkTheme()) Color(0xFF262626) else Color.White
}

@Composable
fun secondaryBackground(): Color {
return if (isSystemInDarkTheme()) Color(0xFF1A1A1A) else Color(0xFFF7F7F7)
}

@Composable
fun inputBackground(): Color {
return if (isSystemInDarkTheme()) Color(0xFF1F1F1F) else Color.White
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.computerization.mediafilter.theme

import android.app.Activity
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat

private val DarkColorScheme = darkColorScheme(
primary = AppColors.primaryBlue,
secondary = AppColors.accentGreen,
background = Color(0xFF121212),
surface = Color(0xFF262626),
onPrimary = Color.White,
onBackground = Color.White,
onSurface = Color.White,
)

private val LightColorScheme = lightColorScheme(
primary = AppColors.primaryBlue,
secondary = AppColors.accentGreen,
background = Color.White,
surface = Color.White,
onPrimary = Color.White,
onBackground = Color.Black,
onSurface = Color.Black,
)

@Composable
fun MediaFilterTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme

val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
window.statusBarColor = AppColors.primaryBlue.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = false
}
}

MaterialTheme(
colorScheme = colorScheme,
content = content
)
}
Loading