replace everything with clean template from https://github.com/ferhatozcelik/jetpack-compose-template.git
This commit is contained in:
parent
4b8386b716
commit
e5ad6dc3c7
55 changed files with 980 additions and 337 deletions
3
app/.gitignore
vendored
3
app/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/build
|
||||
/build
|
||||
/.idea/**
|
134
app/build.gradle
Normal file
134
app/build.gradle
Normal file
|
@ -0,0 +1,134 @@
|
|||
plugins {
|
||||
alias(libs.plugins.com.android.application)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.android)
|
||||
alias(libs.plugins.com.google.dagger.hilt.android)
|
||||
alias(libs.plugins.com.google.devtools.ksp)
|
||||
id('kotlin-parcelize')
|
||||
// id("com.google.gms.google-services") // Google Play Services
|
||||
// id("com.google.firebase.crashlytics") // Google Play Services
|
||||
}
|
||||
hilt {
|
||||
enableAggregatingTask = true
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.ferhatozcelik.jetpackcomposetemplate'
|
||||
compileSdk appCompileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.ferhatozcelik.jetpackcomposetemplate"
|
||||
minSdk appMinSdkVersion
|
||||
targetSdk appTargetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
useSupportLibrary true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion '1.5.3'
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// Kotlin
|
||||
implementation(libs.kotlin.stdlib)
|
||||
implementation(libs.core.ktx)
|
||||
implementation(libs.appcompat)
|
||||
|
||||
// Compose
|
||||
implementation(libs.activity.compose)
|
||||
implementation(platform(libs.compose.bom))
|
||||
implementation(libs.ui)
|
||||
implementation(libs.ui.graphics)
|
||||
implementation(libs.ui.tooling.preview)
|
||||
implementation(libs.material3)
|
||||
|
||||
// JUnit
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.test.ext.junit)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
androidTestImplementation(platform(libs.compose.bom))
|
||||
androidTestImplementation(libs.ui.test.junit4)
|
||||
debugImplementation(libs.ui.tooling)
|
||||
debugImplementation(libs.ui.test.manifest)
|
||||
|
||||
// Material Design
|
||||
implementation(libs.material)
|
||||
implementation libs.androidx.viewpager2
|
||||
|
||||
// ConstraintLayout
|
||||
implementation(libs.constraintlayout)
|
||||
|
||||
// Legacy Support Library
|
||||
implementation(libs.androidx.legacy.support.v4)
|
||||
|
||||
// Multidex
|
||||
implementation(libs.androidx.multidex)
|
||||
|
||||
// DeSugar Use Java 8 language features and APIs
|
||||
coreLibraryDesugaring(libs.desugar.jdk.libs)
|
||||
|
||||
// Dagger Hilt
|
||||
implementation(libs.hilt)
|
||||
ksp(libs.hilt.compiler)
|
||||
|
||||
// Room
|
||||
implementation(libs.room)
|
||||
implementation(libs.room.runtime)
|
||||
ksp(libs.room.compiler)
|
||||
|
||||
// Coroutines
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
|
||||
// Lifecycle Scopes
|
||||
implementation(libs.lifecycle)
|
||||
implementation(libs.lifecycle.runtime)
|
||||
implementation(libs.lifecycle.runtime.ktx)
|
||||
|
||||
// Retrofit
|
||||
implementation(libs.retrofit)
|
||||
implementation(libs.converter.gson)
|
||||
implementation(libs.logging.interceptor)
|
||||
|
||||
// Navigation
|
||||
implementation libs.androidx.hilt.navigation.compose
|
||||
implementation libs.androidx.navigation.compose
|
||||
|
||||
|
||||
// Glide
|
||||
implementation(libs.glide)
|
||||
ksp(libs.ksp)
|
||||
|
||||
// Firebase
|
||||
// implementation(libs.firebase)
|
||||
// implementation(libs.analytics)
|
||||
// implementation(libs.crashlytics)
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.gyromin"
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.example.gyromin"
|
||||
minSdk = 21
|
||||
targetSdk = 35
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.ui)
|
||||
implementation(libs.androidx.ui.graphics)
|
||||
implementation(libs.androidx.ui.tooling.preview)
|
||||
implementation(libs.androidx.material3)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||
debugImplementation(libs.androidx.ui.tooling)
|
||||
debugImplementation(libs.androidx.ui.test.manifest)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.example.gyromin
|
||||
package com.ferhatozcelik.jetpackcomposetemplate
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
|
|||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.example.gyromin", appContext.packageName)
|
||||
assertEquals("com.ferhatozcelik.myapplication", appContext.packageName)
|
||||
}
|
||||
}
|
|
@ -2,9 +2,10 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature android:name="android.hardware.sensor.gyroscope" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<application
|
||||
android:name=".App"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
@ -12,13 +13,12 @@
|
|||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Gyromin"
|
||||
android:theme="@style/Theme.MyApplication"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".ui.activitys.MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Gyromin">
|
||||
android:theme="@style/Theme.MyApplication">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
package com.example.gyromin
|
||||
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioTrack
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.example.gyromin.ui.theme.GyrominTheme
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.sin
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private lateinit var Track: AudioTrack
|
||||
private var isPlaying: MutableState<Boolean> = mutableStateOf(false)
|
||||
private val Fs: Int = 44100
|
||||
private val buffLength: Int = AudioTrack.getMinBufferSize(Fs, 4, 2)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
GyrominTheme {
|
||||
Scaffold { padding ->
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Button(onClick = {
|
||||
if (!isPlaying.value)
|
||||
// Create a new thread to play the audio.
|
||||
|
||||
// Performing intensive operations and computations on the main UI thread,
|
||||
// makes the app slow.
|
||||
|
||||
// That is, it is a bad idea to do intensive computations on main UI thread,
|
||||
// so it is recommended to create a new thread to do computations in the background
|
||||
|
||||
Thread {
|
||||
initTrack()
|
||||
startPlaying()
|
||||
playback()
|
||||
}.start()
|
||||
else stopPlaying()
|
||||
}) {
|
||||
Text("Play / Pause", modifier = Modifier.padding(padding))
|
||||
}
|
||||
Text(
|
||||
if (isPlaying.value) "Playing" else "Stopped",
|
||||
modifier = Modifier.padding(padding)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initTrack() {
|
||||
// Very similar to opening a stream in PyAudio
|
||||
// In Android create a AudioTrack instance and initialize it with different parameters
|
||||
|
||||
// AudioTrack is deprecated for some android versions
|
||||
// Please look up for other alternatives if this does not work
|
||||
Track = AudioTrack(
|
||||
AudioManager.MODE_NORMAL, Fs, 4,
|
||||
2, buffLength, AudioTrack.MODE_STREAM
|
||||
)
|
||||
}
|
||||
|
||||
private fun playback() {
|
||||
// simple sine wave generator
|
||||
val frame_out = ShortArray(buffLength)
|
||||
val amplitude = 32767
|
||||
val frequency = 440
|
||||
val twopi: Double = 8.0 * atan(1.0)
|
||||
var phase = 0.0
|
||||
|
||||
while (isPlaying.value) {
|
||||
for (i in 0 until buffLength) {
|
||||
frame_out[i] = (amplitude * sin(phase)).toInt().toShort()
|
||||
phase += twopi * frequency / Fs
|
||||
if (phase > twopi) {
|
||||
phase -= twopi
|
||||
}
|
||||
}
|
||||
Track.write(frame_out, 0, buffLength)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPlaying() {
|
||||
Track.play()
|
||||
isPlaying.value = true
|
||||
}
|
||||
|
||||
private fun stopPlaying() {
|
||||
if (isPlaying.value) {
|
||||
isPlaying.value = false
|
||||
// Stop playing the audio data and release the resources
|
||||
Track.stop()
|
||||
Track.release()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class App : Application()
|
|
@ -0,0 +1,21 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.dao
|
||||
|
||||
import androidx.room.*
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.entity.ExampleEntity
|
||||
|
||||
@Dao
|
||||
interface ExampleDao {
|
||||
|
||||
@Query("SELECT * FROM example_table")
|
||||
fun getExampleData(): List<ExampleEntity>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(search: ExampleEntity?)
|
||||
|
||||
@Update
|
||||
suspend fun update(search: ExampleEntity)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(search: ExampleEntity)
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@Entity(tableName = "example_table")
|
||||
data class ExampleEntity(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int? = null,
|
||||
val title: String?,
|
||||
val description: String?
|
||||
) : Parcelable
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.local
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.dao.ExampleDao
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.entity.ExampleEntity
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.di.ApplicationScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
@Database(entities = [ExampleEntity::class], version = 1)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun getExampleDao(): ExampleDao
|
||||
|
||||
class Callback @Inject constructor(
|
||||
private val database: Provider<AppDatabase>,
|
||||
@ApplicationScope private val applicationScope: CoroutineScope
|
||||
) : RoomDatabase.Callback()
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.local
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import java.util.Date
|
||||
|
||||
class Converters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromTimestamp(value: Long?): Date {
|
||||
return value?.let { Date(it) } ?: Date(System.currentTimeMillis())
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toTimestamp(value: Date?): Long {
|
||||
return value?.let { value.time } ?: System.currentTimeMillis()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class ExampleModel(
|
||||
@SerializedName("title")
|
||||
var title: String?,
|
||||
@SerializedName("description")
|
||||
var description: String?
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.model
|
||||
|
||||
sealed class Resource<out T : Any> {
|
||||
object Loading : Resource<Nothing>()
|
||||
data class Success<out T : Any>(val data: Any) : Resource<T>()
|
||||
data class Error(val errorMessage: String) : Resource<Nothing>()
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.remote
|
||||
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.model.ExampleModel
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.*
|
||||
|
||||
interface AppApi {
|
||||
|
||||
@GET("/api/v1/example")
|
||||
suspend fun getExampleResult(): Response<List<ExampleModel>>
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.data.repository
|
||||
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.dao.ExampleDao
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.remote.AppApi
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
||||
@Singleton
|
||||
class ExampleRepository @Inject constructor(private val appApi: AppApi, private val exampleDao: ExampleDao)
|
|
@ -0,0 +1,43 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.di
|
||||
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.remote.AppApi
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.util.BASE_URL
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object ApiModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
|
||||
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(logging: HttpLoggingInterceptor): OkHttpClient {
|
||||
return OkHttpClient.Builder().addInterceptor(logging).build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRetrofit(client: OkHttpClient): Retrofit {
|
||||
return Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).client(client).build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppApi(retrofit: Retrofit): AppApi {
|
||||
return retrofit.create(AppApi::class.java)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import javax.inject.Qualifier
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AppModule {
|
||||
|
||||
@ApplicationScope
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideApplicationScope(): CoroutineScope {
|
||||
return CoroutineScope(SupervisorJob())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Qualifier
|
||||
annotation class ApplicationScope
|
|
@ -0,0 +1,27 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.di
|
||||
|
||||
import android.app.Application
|
||||
import androidx.room.Room
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.dao.ExampleDao
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.local.AppDatabase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DatabaseModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDatabase(application: Application, callback: AppDatabase.Callback): AppDatabase {
|
||||
return Room.databaseBuilder(application, AppDatabase::class.java, "local_database").fallbackToDestructiveMigration().addCallback(callback).build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideExampleDao(database: AppDatabase): ExampleDao {
|
||||
return database.getExampleDao()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.navigation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.ui.detail.DetailScreen
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.ui.home.MainScreen
|
||||
|
||||
@Composable
|
||||
fun NavGraph(navController: NavHostController) {
|
||||
|
||||
NavHost(
|
||||
navController = navController, startDestination = Screen.Main.route
|
||||
) {
|
||||
|
||||
composable(Screen.Main.route) {
|
||||
MainScreen(navController = navController)
|
||||
}
|
||||
composable(
|
||||
"${Screen.Detail.route}/{id}",
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) {
|
||||
DetailScreen(navController = navController, id = it.arguments?.getInt("id") ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.navigation
|
||||
|
||||
sealed class Screen(val route: String) {
|
||||
object Main : Screen("main_screen")
|
||||
object Detail : Screen("detail_screen")
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.activitys
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.navigation.NavGraph
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.ui.theme.MyApplicationTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
MyApplicationTheme {
|
||||
val navController = rememberNavController()
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
NavGraph(navController = navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.detail
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavController
|
||||
import java.util.*
|
||||
|
||||
|
||||
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
|
||||
@Composable
|
||||
fun DetailScreen(
|
||||
viewModel: DetailViewModel = hiltViewModel(),
|
||||
navController: NavController,
|
||||
id: Int
|
||||
) {
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(text = id.toString())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.detail
|
||||
|
||||
data class DetailScreenState(
|
||||
val isLoading: Boolean = false,
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.detail
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.repository.ExampleRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@HiltViewModel
|
||||
class DetailViewModel @Inject constructor(private val exampleRepository: ExampleRepository) : ViewModel() {
|
||||
private val TAG = DetailViewModel::class.java.simpleName
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.home
|
||||
|
||||
data class HomeScreenState(
|
||||
val isLoading: Boolean = false,
|
||||
)
|
|
@ -0,0 +1,13 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.home
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.data.repository.ExampleRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class HomeViewModel @Inject constructor(private val exampleRepository: ExampleRepository) : ViewModel() {
|
||||
private val TAG = HomeViewModel::class.java.simpleName
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.ui.home
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import com.ferhatozcelik.jetpackcomposetemplate.navigation.Screen
|
||||
|
||||
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
viewModel: HomeViewModel = hiltViewModel(),
|
||||
navController: NavHostController,
|
||||
) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Button(onClick = {
|
||||
navController.navigate(Screen.Detail.route + "/123")
|
||||
}) {
|
||||
Text(text = "Go to Detail")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.example.gyromin.ui.theme
|
||||
package com.ferhatozcelik.jetpackcomposetemplate.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.example.gyromin.ui.theme
|
||||
package com.ferhatozcelik.jetpackcomposetemplate.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
|
@ -9,7 +9,11 @@ import androidx.compose.material3.dynamicDarkColorScheme
|
|||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
|
@ -34,7 +38,7 @@ private val LightColorScheme = lightColorScheme(
|
|||
)
|
||||
|
||||
@Composable
|
||||
fun GyrominTheme(
|
||||
fun MyApplicationTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
|
@ -49,6 +53,14 @@ fun GyrominTheme(
|
|||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
window.statusBarColor = colorScheme.primary.toArgb()
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
|
@ -1,4 +1,4 @@
|
|||
package com.example.gyromin.ui.theme
|
||||
package com.ferhatozcelik.jetpackcomposetemplate.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
|
@ -0,0 +1,3 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.util
|
||||
|
||||
const val BASE_URL = "https://api.ferhatozcelik.com"
|
|
@ -0,0 +1,41 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.util
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
|
||||
fun View.show() {
|
||||
visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun View.gone() {
|
||||
visibility = View.GONE
|
||||
}
|
||||
|
||||
fun Context.toast(message: String) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
fun String.debug(message: String) {
|
||||
Log.d(this, message)
|
||||
}
|
||||
|
||||
fun EditText.modifyText(numberText: String) {
|
||||
this.setText(numberText)
|
||||
this.setSelection(numberText.length)
|
||||
}
|
||||
|
||||
fun Context.goURL(url: String) {
|
||||
try {
|
||||
val myIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(myIntent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
this.toast("No application can handle this request. Please install a webbrowser")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.ferhatozcelik.jetpackcomposetemplate.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
|
||||
class NetworkUtil {
|
||||
companion object {
|
||||
fun hasInternetConnection(context: Context): Boolean {
|
||||
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
val activeNetwork = connectivityManager.activeNetwork ?: return false
|
||||
val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
|
||||
return when {
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
|
||||
else -> false
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">Gyromin</string>
|
||||
<string name="app_name">My Application</string>
|
||||
</resources>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Gyromin" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
<style name="Theme.MyApplication" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
</resources>
|
|
@ -2,7 +2,7 @@
|
|||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older than API 31
|
||||
Note: This file is ignored for devices older that API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.example.gyromin
|
||||
package com.ferhatozcelik.jetpackcomposetemplate
|
||||
|
||||
import org.junit.Test
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue