From fe174a79649b8a23e228dfd19e22953735c3bbfd Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Fri, 14 Jun 2024 11:10:14 +0900 Subject: [PATCH 01/10] upgrade to K2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c253fbe..caad712 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.9.23' + ext.kotlin_version = '2.0.0' repositories { google() mavenCentral() From 8e1552922e91798024c7ec61ead9e336d5921335 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Fri, 14 Jun 2024 14:44:40 +0900 Subject: [PATCH 02/10] add GithubReposViewModel --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 3 +- .../us/mitene/practicalexam/MainActivity.kt | 13 ++++- .../mitene/practicalexam/MainApplication.kt | 7 +++ .../practicalexam/ui/GithubReposScreen.kt | 58 +++++++++++++++++++ .../practicalexam/ui/GithubReposViewModel.kt | 25 ++++++++ build.gradle | 2 +- 7 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/us/mitene/practicalexam/MainApplication.kt create mode 100644 app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt create mode 100644 app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt diff --git a/app/build.gradle b/app/build.gradle index 4add9a7..9c6d577 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -162,4 +162,5 @@ dependencies { kapt 'com.google.dagger:hilt-compiler:2.51.1' testImplementation 'com.google.dagger:hilt-android-testing:2.51.1' kaptTest 'com.google.dagger:hilt-compiler:2.51.1' + implementation "androidx.hilt:hilt-navigation-compose:1.2.0" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0a107b8..f41c811 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,7 +7,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.PracticalExam"> + android:theme="@style/Theme.PracticalExam" + android:name=".MainApplication"> diff --git a/app/src/main/java/us/mitene/practicalexam/MainActivity.kt b/app/src/main/java/us/mitene/practicalexam/MainActivity.kt index 903cdae..975b356 100644 --- a/app/src/main/java/us/mitene/practicalexam/MainActivity.kt +++ b/app/src/main/java/us/mitene/practicalexam/MainActivity.kt @@ -2,10 +2,21 @@ package us.mitene.practicalexam import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.activity.compose.setContent +import dagger.hilt.android.AndroidEntryPoint +import us.mitene.practicalexam.ui.GithubReposScreen +import us.mitene.practicalexam.ui.theme.PracticalExamTheme +@AndroidEntryPoint class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + + setContent { + PracticalExamTheme { + GithubReposScreen() + } + } +// setContentView(R.layout.activity_main) } } \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/MainApplication.kt b/app/src/main/java/us/mitene/practicalexam/MainApplication.kt new file mode 100644 index 0000000..fe8be2d --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/MainApplication.kt @@ -0,0 +1,7 @@ +package us.mitene.practicalexam + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class MainApplication : Application() \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt b/app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt new file mode 100644 index 0000000..69dd1b5 --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt @@ -0,0 +1,58 @@ +package us.mitene.practicalexam.ui + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel + +@Composable +fun GithubReposScreen( + githubReposViewModel: GithubReposViewModel = hiltViewModel() +) { + val githubReposUiState by githubReposViewModel.uiState.collectAsState() + + Scaffold { + GithubReposLayout( + repoNames = githubReposUiState.repoNames, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(it) + ) + } +} + +@Composable +fun GithubReposLayout( + repoNames: List, + modifier: Modifier = Modifier, +) { + LazyColumn(modifier = modifier) { + items(repoNames) { name -> + Text(text = name) + } + } +} + +@Preview +@Composable +private fun Preview() { + Scaffold { + GithubReposLayout( + repoNames = (1..200).map { it.toString() }.toList(), + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() // TODO: どんな効果があるか調べる + .padding(it) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt b/app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt new file mode 100644 index 0000000..72bf52a --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt @@ -0,0 +1,25 @@ +package us.mitene.practicalexam.ui + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class GithubReposViewModel @Inject constructor() : ViewModel() { + private val _uiState = MutableStateFlow(GithubReposUiState(emptyList())) + val uiState = _uiState.asStateFlow() + + init { + fetch() + } + + fun fetch() { + _uiState.value = GithubReposUiState((1..200).map { it.toString() }.toList()) + } +} + +data class GithubReposUiState( + val repoNames: List +) \ No newline at end of file diff --git a/build.gradle b/build.gradle index caad712..c253fbe 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '2.0.0' + ext.kotlin_version = '1.9.23' repositories { google() mavenCentral() From 8d73f50b300958b46b572d6d76ce5cacae9fe750 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Fri, 14 Jun 2024 15:22:05 +0900 Subject: [PATCH 03/10] add GithubApiService --- app/src/main/AndroidManifest.xml | 1 + .../us/mitene/practicalexam/MainActivity.kt | 3 +-- .../practicalexam/network/GithubApiService.kt | 26 +++++++++++++++++++ .../practicalexam/network/GithubRepo.kt | 8 ++++++ .../ui/{ => screen}/GithubReposScreen.kt | 2 +- .../ui/{ => screen}/GithubReposViewModel.kt | 12 +++++++-- 6 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/us/mitene/practicalexam/network/GithubApiService.kt create mode 100644 app/src/main/java/us/mitene/practicalexam/network/GithubRepo.kt rename app/src/main/java/us/mitene/practicalexam/ui/{ => screen}/GithubReposScreen.kt (97%) rename app/src/main/java/us/mitene/practicalexam/ui/{ => screen}/GithubReposViewModel.kt (58%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f41c811..d42e5bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + +} + +object GithubApi { + val retrofitService: GithubApiService by lazy { + retrofit.create(GithubApiService::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/network/GithubRepo.kt b/app/src/main/java/us/mitene/practicalexam/network/GithubRepo.kt new file mode 100644 index 0000000..5461dba --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/network/GithubRepo.kt @@ -0,0 +1,8 @@ +package us.mitene.practicalexam.network + +import kotlinx.serialization.Serializable + +@Serializable +data class GithubRepo( + val name: String +) \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt similarity index 97% rename from app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt rename to app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt index 69dd1b5..2bcec30 100644 --- a/app/src/main/java/us/mitene/practicalexam/ui/GithubReposScreen.kt +++ b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt @@ -1,4 +1,4 @@ -package us.mitene.practicalexam.ui +package us.mitene.practicalexam.ui.screen import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding diff --git a/app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt similarity index 58% rename from app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt rename to app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt index 72bf52a..48b6a6e 100644 --- a/app/src/main/java/us/mitene/practicalexam/ui/GithubReposViewModel.kt +++ b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt @@ -1,9 +1,12 @@ -package us.mitene.practicalexam.ui +package us.mitene.practicalexam.ui.screen import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import us.mitene.practicalexam.network.GithubApi import javax.inject.Inject @HiltViewModel @@ -16,7 +19,12 @@ class GithubReposViewModel @Inject constructor() : ViewModel() { } fun fetch() { - _uiState.value = GithubReposUiState((1..200).map { it.toString() }.toList()) + viewModelScope.launch { + val result = GithubApi.retrofitService.getRepos() + _uiState.value = GithubReposUiState( + result.map { it.name } + ) + } } } From 87f424d07206888222bba1cfa9bf3275e4aaa1c5 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Tue, 18 Jun 2024 13:41:45 +0900 Subject: [PATCH 04/10] add cache --- app/build.gradle | 21 ++++++ .../us/mitene/practicalexam/MainActivity.kt | 2 +- .../mitene/practicalexam/MainApplication.kt | 9 ++- .../data/GithubRepoCacheRepository.kt | 73 +++++++++++++++++++ .../datastore/GithubRepoCacheSerializer.kt | 21 ++++++ .../ui/screen/GithubReposScreen.kt | 4 +- .../ui/screen/GithubReposViewModel.kt | 15 ++-- app/src/main/proto/github_repo_cache.proto | 11 +++ 8 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt create mode 100644 app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt create mode 100644 app/src/main/proto/github_repo_cache.proto diff --git a/app/build.gradle b/app/build.gradle index 9c6d577..ddc4bed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,7 @@ plugins { id 'kotlin-kapt' id 'kotlinx-serialization' id 'dagger.hilt.android.plugin' + id 'com.google.protobuf' version '0.9.1' } android { @@ -163,4 +164,24 @@ dependencies { testImplementation 'com.google.dagger:hilt-android-testing:2.51.1' kaptTest 'com.google.dagger:hilt-compiler:2.51.1' implementation "androidx.hilt:hilt-navigation-compose:1.2.0" + + // Proto DataStore + implementation "androidx.datastore:datastore:1.0.0" + implementation "com.google.protobuf:protobuf-javalite:3.18.0" +} + +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.21.7" + } + + generateProtoTasks { + all().each { task -> + task.builtins { + java { + option 'lite' + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/MainActivity.kt b/app/src/main/java/us/mitene/practicalexam/MainActivity.kt index 8caac0b..b624b76 100644 --- a/app/src/main/java/us/mitene/practicalexam/MainActivity.kt +++ b/app/src/main/java/us/mitene/practicalexam/MainActivity.kt @@ -1,8 +1,8 @@ package us.mitene.practicalexam -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity import dagger.hilt.android.AndroidEntryPoint import us.mitene.practicalexam.ui.screen.GithubReposScreen import us.mitene.practicalexam.ui.theme.PracticalExamTheme diff --git a/app/src/main/java/us/mitene/practicalexam/MainApplication.kt b/app/src/main/java/us/mitene/practicalexam/MainApplication.kt index fe8be2d..5595251 100644 --- a/app/src/main/java/us/mitene/practicalexam/MainApplication.kt +++ b/app/src/main/java/us/mitene/practicalexam/MainApplication.kt @@ -2,6 +2,13 @@ package us.mitene.practicalexam import android.app.Application import dagger.hilt.android.HiltAndroidApp +import timber.log.Timber @HiltAndroidApp -class MainApplication : Application() \ No newline at end of file +class MainApplication : Application(){ + override fun onCreate() { + super.onCreate() + + Timber.plant(Timber.DebugTree()) + } +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt new file mode 100644 index 0000000..aa49d5b --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt @@ -0,0 +1,73 @@ +package us.mitene.practicalexam.data + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.dataStore +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import timber.log.Timber +import us.mitene.practicalexam.datastore.GithubRepoCacheSerializer +import us.mitene.practicalexam.datastore.proto.GithubRepoCache +import us.mitene.practicalexam.network.GithubApi +import java.io.IOException +import java.time.ZonedDateTime +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class GithubRepoCacheRepository @Inject constructor( + @ApplicationContext private val context: Context, +) { + private val Context.githubRepoCacheStore: DataStore by dataStore( + fileName = DATA_STORE_FILE_NAME, + serializer = GithubRepoCacheSerializer + ) + private val repoCacheFlow = context.githubRepoCacheStore.data + .catch { exception -> + // dataStore.data throws an IOException when an error is encountered when reading data + if (exception is IOException) { + Timber.tag(TAG).e(exception, "Error reading sort order preferences.") + emit(GithubRepoCache.getDefaultInstance()) + } else { + throw exception + } + } + + suspend fun getNames(): Flow> { + val cache = repoCacheFlow.first() + Timber.tag(TAG).i("lastFetchedAt: ${cache.fetchedAt}") + val now = ZonedDateTime.now().toEpochSecond() - cache.fetchedAt + + if (now > CACHE_DURATION) { + fetch() + + return repoCacheFlow.map { it.namesList } + } + + return flowOf(cache.namesList) + } + + private suspend fun fetch() { + context.githubRepoCacheStore.updateData { cache -> + val names = GithubApi.retrofitService.getRepos().map { it.name } + val fetchedAt = ZonedDateTime.now().toEpochSecond() + Timber.tag(TAG).i("fetched cache at: $fetchedAt") + + cache.toBuilder() + .setFetchedAt(fetchedAt) + .clearNames() + .addAllNames(names) + .build() + } + } + + companion object { + private const val DATA_STORE_FILE_NAME = "github_repo_cache.pb" + private const val TAG: String = "GithubRepoCacheRepo" + private const val CACHE_DURATION = 30 // 秒で指定 + } +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt b/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt new file mode 100644 index 0000000..529cec3 --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt @@ -0,0 +1,21 @@ +package us.mitene.practicalexam.datastore + +import androidx.datastore.core.CorruptionException +import androidx.datastore.core.Serializer +import com.google.protobuf.InvalidProtocolBufferException +import us.mitene.practicalexam.datastore.proto.GithubRepoCache +import java.io.InputStream +import java.io.OutputStream + +object GithubRepoCacheSerializer : Serializer { + override val defaultValue: GithubRepoCache = GithubRepoCache.getDefaultInstance() + override suspend fun readFrom(input: InputStream): GithubRepoCache { + try { + return GithubRepoCache.parseFrom(input) + } catch (e: InvalidProtocolBufferException) { + throw CorruptionException("Cannot read proto.", e) + } + } + + override suspend fun writeTo(t: GithubRepoCache, output: OutputStream) = t.writeTo(output) +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt index 2bcec30..532edec 100644 --- a/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt +++ b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposScreen.kt @@ -46,13 +46,13 @@ fun GithubReposLayout( @Preview @Composable private fun Preview() { - Scaffold { + Scaffold { paddingValues -> GithubReposLayout( repoNames = (1..200).map { it.toString() }.toList(), modifier = Modifier .fillMaxWidth() .wrapContentHeight() // TODO: どんな効果があるか調べる - .padding(it) + .padding(paddingValues) ) } } \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt index 48b6a6e..182a1b9 100644 --- a/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt +++ b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt @@ -6,11 +6,13 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import us.mitene.practicalexam.network.GithubApi +import us.mitene.practicalexam.data.GithubRepoCacheRepository import javax.inject.Inject @HiltViewModel -class GithubReposViewModel @Inject constructor() : ViewModel() { +class GithubReposViewModel @Inject constructor( + private val githubRepoCacheRepository: GithubRepoCacheRepository, +) : ViewModel() { private val _uiState = MutableStateFlow(GithubReposUiState(emptyList())) val uiState = _uiState.asStateFlow() @@ -18,12 +20,11 @@ class GithubReposViewModel @Inject constructor() : ViewModel() { fetch() } - fun fetch() { + private fun fetch() { viewModelScope.launch { - val result = GithubApi.retrofitService.getRepos() - _uiState.value = GithubReposUiState( - result.map { it.name } - ) + githubRepoCacheRepository.getNames().collect { + _uiState.value = GithubReposUiState(it) + } } } } diff --git a/app/src/main/proto/github_repo_cache.proto b/app/src/main/proto/github_repo_cache.proto new file mode 100644 index 0000000..bd70539 --- /dev/null +++ b/app/src/main/proto/github_repo_cache.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +option java_package = "us.mitene.practicalexam.datastore.proto"; +option java_multiple_files = true; + +message GithubRepoCache { + // 最後にfetchしたDatetime + int64 fetchedAt = 1; + // レポジトリ名一覧 + repeated string names = 2; +} From 96f45c58ecd20ad76ac66bd5b3d6bd95d887d1d6 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Tue, 18 Jun 2024 18:10:54 +0900 Subject: [PATCH 05/10] refactor modules --- .../data/GithubRepoCacheRepository.kt | 6 ++-- .../GithubRepoCacheSerializer.kt | 2 +- .../network/GithubApiDataSource.kt | 32 +++++++++++++++++++ .../practicalexam/network/GithubApiService.kt | 26 --------------- app/src/main/res/layout/activity_main.xml | 18 ----------- 5 files changed, 36 insertions(+), 48 deletions(-) rename app/src/main/java/us/mitene/practicalexam/{datastore => data}/GithubRepoCacheSerializer.kt (94%) create mode 100644 app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt delete mode 100644 app/src/main/java/us/mitene/practicalexam/network/GithubApiService.kt delete mode 100644 app/src/main/res/layout/activity_main.xml diff --git a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt index aa49d5b..61db6a9 100644 --- a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt +++ b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt @@ -10,9 +10,8 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import timber.log.Timber -import us.mitene.practicalexam.datastore.GithubRepoCacheSerializer import us.mitene.practicalexam.datastore.proto.GithubRepoCache -import us.mitene.practicalexam.network.GithubApi +import us.mitene.practicalexam.network.GithubApiDataSource import java.io.IOException import java.time.ZonedDateTime import javax.inject.Inject @@ -20,6 +19,7 @@ import javax.inject.Singleton @Singleton class GithubRepoCacheRepository @Inject constructor( + private val github: GithubApiDataSource, @ApplicationContext private val context: Context, ) { private val Context.githubRepoCacheStore: DataStore by dataStore( @@ -53,7 +53,7 @@ class GithubRepoCacheRepository @Inject constructor( private suspend fun fetch() { context.githubRepoCacheStore.updateData { cache -> - val names = GithubApi.retrofitService.getRepos().map { it.name } + val names = github.getRepos().map { it.name } val fetchedAt = ZonedDateTime.now().toEpochSecond() Timber.tag(TAG).i("fetched cache at: $fetchedAt") diff --git a/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheSerializer.kt similarity index 94% rename from app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt rename to app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheSerializer.kt index 529cec3..6074787 100644 --- a/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt +++ b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheSerializer.kt @@ -1,4 +1,4 @@ -package us.mitene.practicalexam.datastore +package us.mitene.practicalexam.data import androidx.datastore.core.CorruptionException import androidx.datastore.core.Serializer diff --git a/app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt b/app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt new file mode 100644 index 0000000..374cb77 --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt @@ -0,0 +1,32 @@ +package us.mitene.practicalexam.network + +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import retrofit2.Retrofit +import retrofit2.http.GET +import javax.inject.Inject +import javax.inject.Singleton + +interface GithubApi { + @GET("orgs/mixigroup/repos") + suspend fun getRepos(): List +} + +@Singleton +class GithubApiDataSource @Inject constructor() { + private val json = Json { ignoreUnknownKeys = true } + private val retrofit = Retrofit.Builder() + .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) + .baseUrl(BASE_URL) + .build() + private val retrofitService: GithubApi by lazy { + retrofit.create(GithubApi::class.java) + } + + suspend fun getRepos(): List = retrofitService.getRepos() + + companion object { + private const val BASE_URL = "https://api.github.com" + } +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/network/GithubApiService.kt b/app/src/main/java/us/mitene/practicalexam/network/GithubApiService.kt deleted file mode 100644 index 0428139..0000000 --- a/app/src/main/java/us/mitene/practicalexam/network/GithubApiService.kt +++ /dev/null @@ -1,26 +0,0 @@ -package us.mitene.practicalexam.network - -import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory -import kotlinx.serialization.json.Json -import okhttp3.MediaType.Companion.toMediaType -import retrofit2.Retrofit -import retrofit2.http.GET - -private const val BASE_URL = "https://api.github.com" - -private val json = Json { ignoreUnknownKeys = true } -private val retrofit = Retrofit.Builder() - .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) - .baseUrl(BASE_URL) - .build() - -interface GithubApiService { - @GET("orgs/mixigroup/repos") - suspend fun getRepos(): List -} - -object GithubApi { - val retrofitService: GithubApiService by lazy { - retrofit.create(GithubApiService::class.java) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index c08b7a3..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file From 5ae7b6e400f37b27c5497780058c8989f36e45fd Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Tue, 18 Jun 2024 19:38:58 +0900 Subject: [PATCH 06/10] migrate dependencies versions to version catalog --- app/build.gradle | 165 ++++++++++++++++---------------- build.gradle | 11 ++- gradle/libs.versions.toml | 191 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 90 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/app/build.gradle b/app/build.gradle index ddc4bed..d26a65e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,6 @@ plugins { - id 'com.android.application' + alias(libs.plugins.com.android.application) +// id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' id 'kotlinx-serialization' @@ -8,14 +9,14 @@ plugins { } android { - compileSdkVersion 34 + compileSdkVersion libs.versions.app.compileSdk.get().toInteger() defaultConfig { applicationId "us.mitene.practicalexam" - minSdkVersion 26 - targetSdkVersion 34 - versionCode 1 - versionName "1.0" + minSdkVersion libs.versions.app.minSdk.get().toInteger() + targetSdkVersion libs.versions.app.targetSdk.get().toInteger() + versionCode libs.versions.app.versionCode.get().toInteger() + versionName libs.versions.app.versionName.get() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -42,7 +43,7 @@ android { targetCompatibility JavaVersion.VERSION_17 } composeOptions { - kotlinCompilerExtensionVersion = "1.5.11" + kotlinCompilerExtensionVersion = libs.versions.app.kotlinCompilerExtensionVersion.get() } kotlinOptions { jvmTarget = JavaVersion.VERSION_17.toString() @@ -55,124 +56,118 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.13.1' - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.12.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation libs.androidx.core.core.ktx + implementation libs.androidx.appcompat + implementation libs.com.google.android.material + implementation libs.androidx.constraintlayout + testImplementation libs.junit + androidTestImplementation libs.androidx.test.ext.junit + androidTestImplementation libs.androidx.test.espresso.espresso.core // jetpack compose bom - implementation platform('androidx.compose:compose-bom:2024.05.00') - implementation 'androidx.compose.ui:ui' - implementation 'androidx.compose.material:material' - implementation 'androidx.compose.material:material-icons-extended' - implementation 'androidx.compose.ui:ui-tooling-preview' - implementation 'androidx.compose.material3:material3' - debugImplementation 'androidx.compose.ui:ui-tooling' - debugImplementation 'androidx.compose.ui:ui-test-manifest' - implementation 'androidx.compose.runtime:runtime-livedata' + implementation platform(libs.androidx.compose.compose.bom) + implementation libs.androidx.ui + implementation libs.androidx.material + implementation libs.androidx.material.icons.extended + implementation libs.androidx.ui.tooling.preview + implementation libs.androidx.material3 + debugImplementation libs.androidx.ui.tooling + debugImplementation libs.androidx.ui.test.manifest + implementation libs.androidx.runtime.livedata // jetpack compose - implementation 'androidx.activity:activity-compose:1.9.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0' + implementation libs.androidx.activity.activity.compose + implementation libs.androidx.lifecycle.lifecycle.viewmodel.ktx + implementation libs.androidx.lifecycle.lifecycle.viewmodel.compose // for test - testImplementation 'org.robolectric:robolectric:4.12.1' - testImplementation "androidx.test:core:1.5.0" - testImplementation "androidx.test:core-ktx:1.5.0" - testImplementation "androidx.test.ext:junit:1.1.5" - testImplementation "androidx.test.ext:junit-ktx:1.1.5" - testImplementation("androidx.arch.core:core-testing:2.2.0") - testImplementation 'io.mockk:mockk:1.13.10' - testImplementation 'org.mockito:mockito-core:5.12.0' + testImplementation libs.org.robolectric + testImplementation libs.androidx.test.core + testImplementation libs.androidx.test.core.ktx + testImplementation libs.androidx.test.ext.junit + testImplementation libs.androidx.test.ext.junit.ktx + testImplementation(libs.androidx.arch.core.core.testing) + testImplementation libs.io.mockk + testImplementation libs.org.mockito.mockito.core // jet pack - implementation "androidx.fragment:fragment-ktx:1.7.1" - implementation "androidx.recyclerview:recyclerview:1.3.2" + implementation libs.androidx.fragment.fragment.ktx + implementation libs.androidx.recyclerview // androidx.lifecycle - def lifecycle_version = "2.8.0" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + implementation libs.androidx.lifecycle.lifecycle.viewmodel.ktx + implementation libs.androidx.lifecycle.lifecycle.livedata.ktx //noinspection LifecycleAnnotationProcessorWithJava8 - kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" + kapt libs.androidx.lifecycle.lifecycle.compiler + implementation libs.androidx.lifecycle.lifecycle.process // room - def room_version = "2.6.1" - implementation("androidx.room:room-runtime:$room_version") - kapt "androidx.room:room-compiler:$room_version" - implementation("androidx.room:room-ktx:$room_version") - implementation("androidx.room:room-rxjava2:$room_version") - implementation("androidx.room:room-rxjava3:$room_version") - testImplementation("androidx.room:room-testing:$room_version") + implementation(libs.androidx.room.room.runtime) + kapt libs.androidx.room.room.compiler + implementation(libs.androidx.room.room.ktx) + implementation(libs.androidx.room.room.rxjava2) + implementation(libs.androidx.room.room.rxjava3) + testImplementation(libs.androidx.room.room.testing) // okhttp - def okhttp_version = "4.12.0" - implementation "com.squareup.okhttp3:okhttp:$okhttp_version" - implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" - testImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version" + implementation libs.com.squareup.okhttp3.okhttp + implementation libs.com.squareup.okhttp3.logging.interceptor + testImplementation libs.com.squareup.okhttp3.mockwebserver // glide - def glide_version = '4.16.0' - implementation "com.github.bumptech.glide:glide:$glide_version" - implementation "com.github.bumptech.glide:glide:$glide_version" - implementation "com.github.bumptech.glide:annotations:$glide_version" - kapt "com.github.bumptech.glide:compiler:$glide_version" + implementation libs.com.github.bumptech.glide + implementation libs.com.github.bumptech.glide + implementation libs.com.github.bumptech.glide.annotations + kapt libs.com.github.bumptech.glide.compiler // coroutine - def coroutine_version = "1.8.0" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$coroutine_version" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutine_version" + implementation libs.org.jetbrains.kotlinx.kotlinx.coroutines.core + implementation libs.org.jetbrains.kotlinx.kotlinx.coroutines.android + implementation libs.org.jetbrains.kotlinx.kotlinx.coroutines.rx2 + testImplementation libs.org.jetbrains.kotlinx.kotlinx.coroutines.test // rxjava - implementation "io.reactivex.rxjava2:rxjava:2.2.21" - implementation "io.reactivex.rxjava2:rxandroid:2.1.1" - implementation "io.reactivex.rxjava2:rxkotlin:2.4.0" + implementation libs.io.reactivex.rxjava2.rxjava + implementation libs.io.reactivex.rxjava2.rxandroid + implementation libs.io.reactivex.rxjava2.rxkotlin // retrofit - def retrofit2_version = "2.10.0" - implementation "com.squareup.retrofit2:retrofit:$retrofit2_version" - implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2_version" - implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version" - implementation "com.squareup.retrofit2:converter-moshi:$retrofit2_version" - implementation 'com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0' + implementation libs.com.squareup.retrofit2.retrofit + implementation libs.com.squareup.retrofit2.adapter.rxjava2 + implementation libs.com.squareup.retrofit2.converter.gson + implementation libs.com.squareup.retrofit2.converter.moshi + implementation libs.com.jakewharton.retrofit.retrofit2.kotlinx.serialization.converter // gson - implementation "com.google.code.gson:gson:2.10.1" + implementation libs.com.google.code.gson // moshi - implementation 'com.squareup.moshi:moshi-kotlin:1.15.1' + implementation libs.com.squareup.moshi.moshi.kotlin // serialization - implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3' + implementation libs.org.jetbrains.kotlinx.kotlinx.serialization.json // timber - implementation "com.jakewharton.timber:timber:5.0.1" + implementation libs.com.jakewharton.timber // DI : dagger - implementation 'com.google.dagger:dagger:2.51.1' - kapt 'com.google.dagger:dagger-compiler:2.51.1' + implementation libs.com.google.dagger + kapt libs.com.google.dagger.dagger.compiler // DI : hilt - implementation 'com.google.dagger:hilt-android:2.51.1' - kapt 'com.google.dagger:hilt-compiler:2.51.1' - testImplementation 'com.google.dagger:hilt-android-testing:2.51.1' - kaptTest 'com.google.dagger:hilt-compiler:2.51.1' - implementation "androidx.hilt:hilt-navigation-compose:1.2.0" + implementation libs.com.google.dagger.hilt.android + kapt libs.com.google.dagger.hilt.compiler + testImplementation libs.com.google.dagger.hilt.android.testing + kaptTest libs.com.google.dagger.hilt.compiler + implementation libs.androidx.hilt.hilt.navigation.compose // Proto DataStore - implementation "androidx.datastore:datastore:1.0.0" - implementation "com.google.protobuf:protobuf-javalite:3.18.0" + implementation libs.androidx.datastore + implementation libs.com.google.protobuf.protobuf.javalite } protobuf { protoc { - artifact = "com.google.protobuf:protoc:3.21.7" + artifact = libs.com.google.protobuf.protoc.get() } generateProtoTasks { diff --git a/build.gradle b/build.gradle index c253fbe..7e6f38a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,16 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.9.23' + ext.kotlin_version = libs.versions.org.jetbrains.kotlin repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.4.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - classpath 'com.google.dagger:hilt-android-gradle-plugin:2.51.1' + classpath libs.com.android.tools.build.gradle + classpath libs.com.android.tools.build.gradle + classpath libs.org.jetbrains.kotlin.kotlin.gradle.plugin + classpath libs.org.jetbrains.kotlin.kotlin.serialization + classpath libs.com.google.dagger.hilt.android.gradle.plugin // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..bd3def2 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,191 @@ +[versions] +androidx-compose-material = "1.6.7" +androidx-compose-ui = "1.6.7" +androidx-databinding = "8.4.1" +androidx-lifecycle = "2.8.0" +androidx-room = "2.6.1" +androidx-test = "1.5.0" +androidx-test-ext = "1.1.5" +app-compileSdk = "34" +app-minSdk = "26" +app-targetSdk = "26" +app-versionCode = "1" +app-versionName = "1.0" +app-kotlinCompilerExtensionVersion = "1.5.11" +com-android-tools-utp = "31.4.1" +com-github-bumptech-glide = "4.16.0" +com-google-dagger = "2.51.1" +com-google-testing-platform = "0.0.9-alpha02" +com-squareup-okhttp3 = "4.12.0" +com-squareup-retrofit2 = "2.10.0" +org-jetbrains-kotlin = "1.9.23" +org-jetbrains-kotlinx = "1.8.0" + +[libraries] +androidx-activity-activity-compose = "androidx.activity:activity-compose:1.9.0" +androidx-appcompat = "androidx.appcompat:appcompat:1.6.1" +androidx-arch-core-core-testing = "androidx.arch.core:core-testing:2.2.0" +androidx-compose-compiler = "androidx.compose.compiler:compiler:1.5.11" +androidx-compose-compose-bom = "androidx.compose:compose-bom:2024.05.00" +androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-compose-material" } +androidx-compose-material-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "androidx-compose-material" } +androidx-compose-material3 = "androidx.compose.material3:material3:1.2.1" +androidx-compose-runtime-runtime-livedata = "androidx.compose.runtime:runtime-livedata:1.6.7" +androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "androidx-compose-ui" } +androidx-compose-ui-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "androidx-compose-ui" } +androidx-compose-ui-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "androidx-compose-ui" } +androidx-compose-ui-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "androidx-compose-ui" } +androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" +androidx-core-core-ktx = "androidx.core:core-ktx:1.13.1" +androidx-databinding-databinding-adapters = { module = "androidx.databinding:databinding-adapters", version.ref = "androidx-databinding" } +androidx-databinding-databinding-common = { module = "androidx.databinding:databinding-common", version.ref = "androidx-databinding" } +androidx-databinding-databinding-compiler = { module = "androidx.databinding:databinding-compiler", version.ref = "androidx-databinding" } +androidx-databinding-databinding-ktx = { module = "androidx.databinding:databinding-ktx", version.ref = "androidx-databinding" } +androidx-databinding-databinding-runtime = { module = "androidx.databinding:databinding-runtime", version.ref = "androidx-databinding" } +androidx-datastore = "androidx.datastore:datastore:1.0.0" +androidx-fragment-fragment-ktx = "androidx.fragment:fragment-ktx:1.7.1" +androidx-hilt-hilt-navigation-compose = "androidx.hilt:hilt-navigation-compose:1.2.0" +androidx-lifecycle-lifecycle-compiler = { module = "androidx.lifecycle:lifecycle-compiler", version.ref = "androidx-lifecycle" } +androidx-lifecycle-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidx-lifecycle" } +androidx-lifecycle-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } +androidx-lifecycle-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } +androidx-material = { module = "androidx.compose.material:material" } +androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } +androidx-material3 = { module = "androidx.compose.material3:material3" } +androidx-recyclerview = "androidx.recyclerview:recyclerview:1.3.2" +androidx-room-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" } +androidx-room-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" } +androidx-room-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidx-room" } +androidx-room-room-rxjava2 = { module = "androidx.room:room-rxjava2", version.ref = "androidx-room" } +androidx-room-room-rxjava3 = { module = "androidx.room:room-rxjava3", version.ref = "androidx-room" } +androidx-room-room-testing = { module = "androidx.room:room-testing", version.ref = "androidx-room" } +androidx-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata" } +androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" } +androidx-test-core-ktx = { module = "androidx.test:core-ktx", version.ref = "androidx-test" } +androidx-test-espresso-espresso-core = "androidx.test.espresso:espresso-core:3.5.1" +androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-ext" } +androidx-test-ext-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "androidx-test-ext" } +androidx-ui = { module = "androidx.compose.ui:ui" } +androidx-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" } +androidx-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } +androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } +com-android-tools-build-gradle = "com.android.tools.build:gradle:8.4.1" +com-android-tools-utp-android-device-provider-ddmlib = { module = "com.android.tools.utp:android-device-provider-ddmlib", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-device-provider-gradle = { module = "com.android.tools.utp:android-device-provider-gradle", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-additional-test-output = { module = "com.android.tools.utp:android-test-plugin-host-additional-test-output", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-apk-installer = { module = "com.android.tools.utp:android-test-plugin-host-apk-installer", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-coverage = { module = "com.android.tools.utp:android-test-plugin-host-coverage", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-device-info = { module = "com.android.tools.utp:android-test-plugin-host-device-info", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-emulator-control = { module = "com.android.tools.utp:android-test-plugin-host-emulator-control", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-logcat = { module = "com.android.tools.utp:android-test-plugin-host-logcat", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-host-retention = { module = "com.android.tools.utp:android-test-plugin-host-retention", version.ref = "com-android-tools-utp" } +com-android-tools-utp-android-test-plugin-result-listener-gradle = { module = "com.android.tools.utp:android-test-plugin-result-listener-gradle", version.ref = "com-android-tools-utp" } +com-github-bumptech-glide = { module = "com.github.bumptech.glide:glide", version.ref = "com-github-bumptech-glide" } +com-github-bumptech-glide-annotations = { module = "com.github.bumptech.glide:annotations", version.ref = "com-github-bumptech-glide" } +com-github-bumptech-glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "com-github-bumptech-glide" } +com-google-android-material = "com.google.android.material:material:1.12.0" +com-google-code-gson = "com.google.code.gson:gson:2.10.1" +com-google-dagger = { module = "com.google.dagger:dagger", version.ref = "com-google-dagger" } +com-google-dagger-dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "com-google-dagger" } +com-google-dagger-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "com-google-dagger" } +com-google-dagger-hilt-android-gradle-plugin = { module = "com.google.dagger:hilt-android-gradle-plugin", version.ref = "com-google-dagger" } +com-google-dagger-hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "com-google-dagger" } +com-google-dagger-hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "com-google-dagger" } +com-google-protobuf-protobuf-javalite = "com.google.protobuf:protobuf-javalite:3.18.0" +com-google-protobuf-protoc = "com.google.protobuf:protoc:3.21.7" +com-google-testing-platform-android-driver-instrumentation = { module = "com.google.testing.platform:android-driver-instrumentation", version.ref = "com-google-testing-platform" } +com-google-testing-platform-android-test-plugin = { module = "com.google.testing.platform:android-test-plugin", version.ref = "com-google-testing-platform" } +com-google-testing-platform-core = { module = "com.google.testing.platform:core", version.ref = "com-google-testing-platform" } +com-google-testing-platform-launcher = { module = "com.google.testing.platform:launcher", version.ref = "com-google-testing-platform" } +com-jakewharton-retrofit-retrofit2-kotlinx-serialization-converter = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0" +com-jakewharton-timber = "com.jakewharton.timber:timber:5.0.1" +com-squareup-moshi-moshi-kotlin = "com.squareup.moshi:moshi-kotlin:1.15.1" +com-squareup-okhttp3-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "com-squareup-okhttp3" } +com-squareup-okhttp3-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "com-squareup-okhttp3" } +com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "com-squareup-okhttp3" } +com-squareup-retrofit2-adapter-rxjava2 = { module = "com.squareup.retrofit2:adapter-rxjava2", version.ref = "com-squareup-retrofit2" } +com-squareup-retrofit2-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "com-squareup-retrofit2" } +com-squareup-retrofit2-converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "com-squareup-retrofit2" } +com-squareup-retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "com-squareup-retrofit2" } +io-mockk = "io.mockk:mockk:1.13.10" +io-reactivex-rxjava2-rxandroid = "io.reactivex.rxjava2:rxandroid:2.1.1" +io-reactivex-rxjava2-rxjava = "io.reactivex.rxjava2:rxjava:2.2.21" +io-reactivex-rxjava2-rxkotlin = "io.reactivex.rxjava2:rxkotlin:2.4.0" +junit = "junit:junit:4.13.2" +org-apache-logging-log4j-log4j-core = "org.apache.logging.log4j:log4j-core:2.17.1" +org-jetbrains-kotlin-kotlin-annotation-processing-gradle = { module = "org.jetbrains.kotlin:kotlin-annotation-processing-gradle", version.ref = "org-jetbrains-kotlin" } +org-jetbrains-kotlin-kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } +org-jetbrains-kotlin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } +org-jetbrains-kotlin-kotlin-serialization-compiler-plugin-embeddable = { module = "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable", version.ref = "org-jetbrains-kotlin" } +org-jetbrains-kotlin-kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "org-jetbrains-kotlin" } +org-jetbrains-kotlinx-kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "org-jetbrains-kotlinx" } +org-jetbrains-kotlinx-kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "org-jetbrains-kotlinx" } +org-jetbrains-kotlinx-kotlinx-coroutines-rx2 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2", version.ref = "org-jetbrains-kotlinx" } +org-jetbrains-kotlinx-kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "org-jetbrains-kotlinx" } +org-jetbrains-kotlinx-kotlinx-serialization-json = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3" +org-mockito-mockito-core = "org.mockito:mockito-core:5.12.0" +org-robolectric = "org.robolectric:robolectric:4.12.1" + +[plugins] +android = "android:8.4.1" +android-library = "android-library:8.4.1" +android-reporting = "android-reporting:8.4.1" +com-android-application = "com.android.application:8.4.1" +com-android-asset-pack = "com.android.asset-pack:8.4.1" +com-android-asset-pack-bundle = "com.android.asset-pack-bundle:8.4.1" +com-android-base = "com.android.base:8.4.1" +com-android-dynamic-feature = "com.android.dynamic-feature:8.4.1" +com-android-fused-library = "com.android.fused-library:8.4.1" +com-android-internal-application = "com.android.internal.application:8.4.1" +com-android-internal-asset-pack = "com.android.internal.asset-pack:8.4.1" +com-android-internal-asset-pack-bundle = "com.android.internal.asset-pack-bundle:8.4.1" +com-android-internal-dynamic-feature = "com.android.internal.dynamic-feature:8.4.1" +com-android-internal-fused-library = "com.android.internal.fused-library:8.4.1" +com-android-internal-kotlin-multiplatform-library = "com.android.internal.kotlin.multiplatform.library:8.4.1" +com-android-internal-library = "com.android.internal.library:8.4.1" +com-android-internal-lint = "com.android.internal.lint:8.4.1" +com-android-internal-privacy-sandbox-sdk = "com.android.internal.privacy-sandbox-sdk:8.4.1" +com-android-internal-reporting = "com.android.internal.reporting:8.4.1" +com-android-internal-test = "com.android.internal.test:8.4.1" +com-android-internal-version-check = "com.android.internal.version-check:8.4.1" +com-android-kotlin-multiplatform-library = "com.android.kotlin.multiplatform.library:8.4.1" +com-android-library = "com.android.library:8.4.1" +com-android-lint = "com.android.lint:8.4.1" +com-android-privacy-sandbox-sdk = "com.android.privacy-sandbox-sdk:8.4.1" +com-android-reporting = "com.android.reporting:8.4.1" +com-android-test = "com.android.test:8.4.1" +com-github-ben-manes-versions = "com.github.ben-manes.versions:0.41.0" +com-google-dagger-hilt-android = "com.google.dagger.hilt.android:2.51.1" +com-google-protobuf = "com.google.protobuf:0.9.1" +dagger-hilt-android-plugin = "dagger.hilt.android.plugin:2.51.1" +kotlin = "kotlin:1.9.23" +kotlin-android = "kotlin-android:1.9.23" +kotlin-android-extensions = "kotlin-android-extensions:1.9.23" +kotlin-kapt = "kotlin-kapt:1.9.23" +kotlin-multiplatform = "kotlin-multiplatform:1.9.23" +kotlin-native-cocoapods = "kotlin-native-cocoapods:1.9.23" +kotlin-native-performance = "kotlin-native-performance:1.9.23" +kotlin-parcelize = "kotlin-parcelize:1.9.23" +kotlin-platform-android = "kotlin-platform-android:1.9.23" +kotlin-platform-common = "kotlin-platform-common:1.9.23" +kotlin-platform-js = "kotlin-platform-js:1.9.23" +kotlin-platform-jvm = "kotlin-platform-jvm:1.9.23" +kotlin-scripting = "kotlin-scripting:1.9.23" +kotlinx-serialization = "kotlinx-serialization:1.9.23" +nl-littlerobots-version-catalog-update = "nl.littlerobots.version-catalog-update:0.8.4" +org-jetbrains-kotlin-android = "org.jetbrains.kotlin.android:1.9.23" +org-jetbrains-kotlin-android-extensions = "org.jetbrains.kotlin.android.extensions:1.9.23" +org-jetbrains-kotlin-js = "org.jetbrains.kotlin.js:1.9.23" +org-jetbrains-kotlin-jvm = "org.jetbrains.kotlin.jvm:1.9.23" +org-jetbrains-kotlin-kapt = "org.jetbrains.kotlin.kapt:1.9.23" +org-jetbrains-kotlin-multiplatform = "org.jetbrains.kotlin.multiplatform:1.9.23" +org-jetbrains-kotlin-native-cocoapods = "org.jetbrains.kotlin.native.cocoapods:1.9.23" +org-jetbrains-kotlin-native-performance = "org.jetbrains.kotlin.native.performance:1.9.23" +org-jetbrains-kotlin-platform-android = "org.jetbrains.kotlin.platform.android:1.9.23" +org-jetbrains-kotlin-platform-common = "org.jetbrains.kotlin.platform.common:1.9.23" +org-jetbrains-kotlin-platform-js = "org.jetbrains.kotlin.platform.js:1.9.23" +org-jetbrains-kotlin-platform-jvm = "org.jetbrains.kotlin.platform.jvm:1.9.23" +org-jetbrains-kotlin-plugin-parcelize = "org.jetbrains.kotlin.plugin.parcelize:1.9.23" +org-jetbrains-kotlin-plugin-scripting = "org.jetbrains.kotlin.plugin.scripting:1.9.23" +org-jetbrains-kotlin-plugin-serialization = "org.jetbrains.kotlin.plugin.serialization:1.9.23" From 31249247692f5c8bcef647eca006ff3920ce4af8 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Wed, 19 Jun 2024 11:35:51 +0900 Subject: [PATCH 07/10] migrate dependencies versions to version catalog --- app/build.gradle | 8 ++-- gradle/libs.versions.toml | 97 --------------------------------------- 2 files changed, 3 insertions(+), 102 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d26a65e..ffb3a3f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,18 +1,16 @@ plugins { - alias(libs.plugins.com.android.application) -// id 'com.android.application' + id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' id 'kotlinx-serialization' id 'dagger.hilt.android.plugin' - id 'com.google.protobuf' version '0.9.1' + alias(libs.plugins.com.google.protobuf) } android { - compileSdkVersion libs.versions.app.compileSdk.get().toInteger() - defaultConfig { applicationId "us.mitene.practicalexam" + compileSdk libs.versions.app.compileSdk.get().toInteger() minSdkVersion libs.versions.app.minSdk.get().toInteger() targetSdkVersion libs.versions.app.targetSdk.get().toInteger() versionCode libs.versions.app.versionCode.get().toInteger() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bd3def2..6cbaf6b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,4 @@ [versions] -androidx-compose-material = "1.6.7" -androidx-compose-ui = "1.6.7" -androidx-databinding = "8.4.1" androidx-lifecycle = "2.8.0" androidx-room = "2.6.1" androidx-test = "1.5.0" @@ -12,10 +9,8 @@ app-targetSdk = "26" app-versionCode = "1" app-versionName = "1.0" app-kotlinCompilerExtensionVersion = "1.5.11" -com-android-tools-utp = "31.4.1" com-github-bumptech-glide = "4.16.0" com-google-dagger = "2.51.1" -com-google-testing-platform = "0.0.9-alpha02" com-squareup-okhttp3 = "4.12.0" com-squareup-retrofit2 = "2.10.0" org-jetbrains-kotlin = "1.9.23" @@ -25,23 +20,9 @@ org-jetbrains-kotlinx = "1.8.0" androidx-activity-activity-compose = "androidx.activity:activity-compose:1.9.0" androidx-appcompat = "androidx.appcompat:appcompat:1.6.1" androidx-arch-core-core-testing = "androidx.arch.core:core-testing:2.2.0" -androidx-compose-compiler = "androidx.compose.compiler:compiler:1.5.11" androidx-compose-compose-bom = "androidx.compose:compose-bom:2024.05.00" -androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "androidx-compose-material" } -androidx-compose-material-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "androidx-compose-material" } -androidx-compose-material3 = "androidx.compose.material3:material3:1.2.1" -androidx-compose-runtime-runtime-livedata = "androidx.compose.runtime:runtime-livedata:1.6.7" -androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "androidx-compose-ui" } -androidx-compose-ui-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "androidx-compose-ui" } -androidx-compose-ui-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "androidx-compose-ui" } -androidx-compose-ui-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "androidx-compose-ui" } androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4" androidx-core-core-ktx = "androidx.core:core-ktx:1.13.1" -androidx-databinding-databinding-adapters = { module = "androidx.databinding:databinding-adapters", version.ref = "androidx-databinding" } -androidx-databinding-databinding-common = { module = "androidx.databinding:databinding-common", version.ref = "androidx-databinding" } -androidx-databinding-databinding-compiler = { module = "androidx.databinding:databinding-compiler", version.ref = "androidx-databinding" } -androidx-databinding-databinding-ktx = { module = "androidx.databinding:databinding-ktx", version.ref = "androidx-databinding" } -androidx-databinding-databinding-runtime = { module = "androidx.databinding:databinding-runtime", version.ref = "androidx-databinding" } androidx-datastore = "androidx.datastore:datastore:1.0.0" androidx-fragment-fragment-ktx = "androidx.fragment:fragment-ktx:1.7.1" androidx-hilt-hilt-navigation-compose = "androidx.hilt:hilt-navigation-compose:1.2.0" @@ -71,16 +52,6 @@ androidx-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" } androidx-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } com-android-tools-build-gradle = "com.android.tools.build:gradle:8.4.1" -com-android-tools-utp-android-device-provider-ddmlib = { module = "com.android.tools.utp:android-device-provider-ddmlib", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-device-provider-gradle = { module = "com.android.tools.utp:android-device-provider-gradle", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-additional-test-output = { module = "com.android.tools.utp:android-test-plugin-host-additional-test-output", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-apk-installer = { module = "com.android.tools.utp:android-test-plugin-host-apk-installer", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-coverage = { module = "com.android.tools.utp:android-test-plugin-host-coverage", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-device-info = { module = "com.android.tools.utp:android-test-plugin-host-device-info", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-emulator-control = { module = "com.android.tools.utp:android-test-plugin-host-emulator-control", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-logcat = { module = "com.android.tools.utp:android-test-plugin-host-logcat", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-host-retention = { module = "com.android.tools.utp:android-test-plugin-host-retention", version.ref = "com-android-tools-utp" } -com-android-tools-utp-android-test-plugin-result-listener-gradle = { module = "com.android.tools.utp:android-test-plugin-result-listener-gradle", version.ref = "com-android-tools-utp" } com-github-bumptech-glide = { module = "com.github.bumptech.glide:glide", version.ref = "com-github-bumptech-glide" } com-github-bumptech-glide-annotations = { module = "com.github.bumptech.glide:annotations", version.ref = "com-github-bumptech-glide" } com-github-bumptech-glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "com-github-bumptech-glide" } @@ -94,10 +65,6 @@ com-google-dagger-hilt-android-testing = { module = "com.google.dagger:hilt-andr com-google-dagger-hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "com-google-dagger" } com-google-protobuf-protobuf-javalite = "com.google.protobuf:protobuf-javalite:3.18.0" com-google-protobuf-protoc = "com.google.protobuf:protoc:3.21.7" -com-google-testing-platform-android-driver-instrumentation = { module = "com.google.testing.platform:android-driver-instrumentation", version.ref = "com-google-testing-platform" } -com-google-testing-platform-android-test-plugin = { module = "com.google.testing.platform:android-test-plugin", version.ref = "com-google-testing-platform" } -com-google-testing-platform-core = { module = "com.google.testing.platform:core", version.ref = "com-google-testing-platform" } -com-google-testing-platform-launcher = { module = "com.google.testing.platform:launcher", version.ref = "com-google-testing-platform" } com-jakewharton-retrofit-retrofit2-kotlinx-serialization-converter = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0" com-jakewharton-timber = "com.jakewharton.timber:timber:5.0.1" com-squareup-moshi-moshi-kotlin = "com.squareup.moshi:moshi-kotlin:1.15.1" @@ -113,12 +80,8 @@ io-reactivex-rxjava2-rxandroid = "io.reactivex.rxjava2:rxandroid:2.1.1" io-reactivex-rxjava2-rxjava = "io.reactivex.rxjava2:rxjava:2.2.21" io-reactivex-rxjava2-rxkotlin = "io.reactivex.rxjava2:rxkotlin:2.4.0" junit = "junit:junit:4.13.2" -org-apache-logging-log4j-log4j-core = "org.apache.logging.log4j:log4j-core:2.17.1" -org-jetbrains-kotlin-kotlin-annotation-processing-gradle = { module = "org.jetbrains.kotlin:kotlin-annotation-processing-gradle", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } -org-jetbrains-kotlin-kotlin-serialization-compiler-plugin-embeddable = { module = "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable", version.ref = "org-jetbrains-kotlin" } -org-jetbrains-kotlin-kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "org-jetbrains-kotlin" } org-jetbrains-kotlinx-kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "org-jetbrains-kotlinx" } org-jetbrains-kotlinx-kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "org-jetbrains-kotlinx" } org-jetbrains-kotlinx-kotlinx-coroutines-rx2 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2", version.ref = "org-jetbrains-kotlinx" } @@ -128,64 +91,4 @@ org-mockito-mockito-core = "org.mockito:mockito-core:5.12.0" org-robolectric = "org.robolectric:robolectric:4.12.1" [plugins] -android = "android:8.4.1" -android-library = "android-library:8.4.1" -android-reporting = "android-reporting:8.4.1" -com-android-application = "com.android.application:8.4.1" -com-android-asset-pack = "com.android.asset-pack:8.4.1" -com-android-asset-pack-bundle = "com.android.asset-pack-bundle:8.4.1" -com-android-base = "com.android.base:8.4.1" -com-android-dynamic-feature = "com.android.dynamic-feature:8.4.1" -com-android-fused-library = "com.android.fused-library:8.4.1" -com-android-internal-application = "com.android.internal.application:8.4.1" -com-android-internal-asset-pack = "com.android.internal.asset-pack:8.4.1" -com-android-internal-asset-pack-bundle = "com.android.internal.asset-pack-bundle:8.4.1" -com-android-internal-dynamic-feature = "com.android.internal.dynamic-feature:8.4.1" -com-android-internal-fused-library = "com.android.internal.fused-library:8.4.1" -com-android-internal-kotlin-multiplatform-library = "com.android.internal.kotlin.multiplatform.library:8.4.1" -com-android-internal-library = "com.android.internal.library:8.4.1" -com-android-internal-lint = "com.android.internal.lint:8.4.1" -com-android-internal-privacy-sandbox-sdk = "com.android.internal.privacy-sandbox-sdk:8.4.1" -com-android-internal-reporting = "com.android.internal.reporting:8.4.1" -com-android-internal-test = "com.android.internal.test:8.4.1" -com-android-internal-version-check = "com.android.internal.version-check:8.4.1" -com-android-kotlin-multiplatform-library = "com.android.kotlin.multiplatform.library:8.4.1" -com-android-library = "com.android.library:8.4.1" -com-android-lint = "com.android.lint:8.4.1" -com-android-privacy-sandbox-sdk = "com.android.privacy-sandbox-sdk:8.4.1" -com-android-reporting = "com.android.reporting:8.4.1" -com-android-test = "com.android.test:8.4.1" -com-github-ben-manes-versions = "com.github.ben-manes.versions:0.41.0" -com-google-dagger-hilt-android = "com.google.dagger.hilt.android:2.51.1" com-google-protobuf = "com.google.protobuf:0.9.1" -dagger-hilt-android-plugin = "dagger.hilt.android.plugin:2.51.1" -kotlin = "kotlin:1.9.23" -kotlin-android = "kotlin-android:1.9.23" -kotlin-android-extensions = "kotlin-android-extensions:1.9.23" -kotlin-kapt = "kotlin-kapt:1.9.23" -kotlin-multiplatform = "kotlin-multiplatform:1.9.23" -kotlin-native-cocoapods = "kotlin-native-cocoapods:1.9.23" -kotlin-native-performance = "kotlin-native-performance:1.9.23" -kotlin-parcelize = "kotlin-parcelize:1.9.23" -kotlin-platform-android = "kotlin-platform-android:1.9.23" -kotlin-platform-common = "kotlin-platform-common:1.9.23" -kotlin-platform-js = "kotlin-platform-js:1.9.23" -kotlin-platform-jvm = "kotlin-platform-jvm:1.9.23" -kotlin-scripting = "kotlin-scripting:1.9.23" -kotlinx-serialization = "kotlinx-serialization:1.9.23" -nl-littlerobots-version-catalog-update = "nl.littlerobots.version-catalog-update:0.8.4" -org-jetbrains-kotlin-android = "org.jetbrains.kotlin.android:1.9.23" -org-jetbrains-kotlin-android-extensions = "org.jetbrains.kotlin.android.extensions:1.9.23" -org-jetbrains-kotlin-js = "org.jetbrains.kotlin.js:1.9.23" -org-jetbrains-kotlin-jvm = "org.jetbrains.kotlin.jvm:1.9.23" -org-jetbrains-kotlin-kapt = "org.jetbrains.kotlin.kapt:1.9.23" -org-jetbrains-kotlin-multiplatform = "org.jetbrains.kotlin.multiplatform:1.9.23" -org-jetbrains-kotlin-native-cocoapods = "org.jetbrains.kotlin.native.cocoapods:1.9.23" -org-jetbrains-kotlin-native-performance = "org.jetbrains.kotlin.native.performance:1.9.23" -org-jetbrains-kotlin-platform-android = "org.jetbrains.kotlin.platform.android:1.9.23" -org-jetbrains-kotlin-platform-common = "org.jetbrains.kotlin.platform.common:1.9.23" -org-jetbrains-kotlin-platform-js = "org.jetbrains.kotlin.platform.js:1.9.23" -org-jetbrains-kotlin-platform-jvm = "org.jetbrains.kotlin.platform.jvm:1.9.23" -org-jetbrains-kotlin-plugin-parcelize = "org.jetbrains.kotlin.plugin.parcelize:1.9.23" -org-jetbrains-kotlin-plugin-scripting = "org.jetbrains.kotlin.plugin.scripting:1.9.23" -org-jetbrains-kotlin-plugin-serialization = "org.jetbrains.kotlin.plugin.serialization:1.9.23" From 580ae2193ba3a3c3ed7ad7d9f389eda0fb053dbb Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Wed, 19 Jun 2024 11:45:20 +0900 Subject: [PATCH 08/10] migrate some libraries to KSP from kapt --- app/build.gradle | 5 +++-- build.gradle | 4 ++++ gradle/libs.versions.toml | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ffb3a3f..5b07be5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,6 +5,7 @@ plugins { id 'kotlinx-serialization' id 'dagger.hilt.android.plugin' alias(libs.plugins.com.google.protobuf) + alias(libs.plugins.com.google.devtools.ksp) } android { @@ -100,7 +101,7 @@ dependencies { // room implementation(libs.androidx.room.room.runtime) - kapt libs.androidx.room.room.compiler + ksp libs.androidx.room.room.compiler implementation(libs.androidx.room.room.ktx) implementation(libs.androidx.room.room.rxjava2) implementation(libs.androidx.room.room.rxjava3) @@ -115,7 +116,7 @@ dependencies { implementation libs.com.github.bumptech.glide implementation libs.com.github.bumptech.glide implementation libs.com.github.bumptech.glide.annotations - kapt libs.com.github.bumptech.glide.compiler + ksp libs.com.github.bumptech.glide.compiler // coroutine implementation libs.org.jetbrains.kotlinx.kotlinx.coroutines.core diff --git a/build.gradle b/build.gradle index 7e6f38a..0173f7b 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,10 @@ buildscript { } } +plugins { + alias(libs.plugins.com.google.devtools.ksp) apply false +} + allprojects { repositories { google() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6cbaf6b..57dfa8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview com-android-tools-build-gradle = "com.android.tools.build:gradle:8.4.1" com-github-bumptech-glide = { module = "com.github.bumptech.glide:glide", version.ref = "com-github-bumptech-glide" } com-github-bumptech-glide-annotations = { module = "com.github.bumptech.glide:annotations", version.ref = "com-github-bumptech-glide" } -com-github-bumptech-glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "com-github-bumptech-glide" } +com-github-bumptech-glide-compiler = { module = "com.github.bumptech.glide:ksp", version.ref = "com-github-bumptech-glide" } com-google-android-material = "com.google.android.material:material:1.12.0" com-google-code-gson = "com.google.code.gson:gson:2.10.1" com-google-dagger = { module = "com.google.dagger:dagger", version.ref = "com-google-dagger" } @@ -92,3 +92,4 @@ org-robolectric = "org.robolectric:robolectric:4.12.1" [plugins] com-google-protobuf = "com.google.protobuf:0.9.1" +com-google-devtools-ksp = "com.google.devtools.ksp:2.0.0-1.0.22" From 03d6178e06313725bc951b4b8424b6e8316334f0 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Wed, 19 Jun 2024 11:57:41 +0900 Subject: [PATCH 09/10] migrate to K2 --- app/build.gradle | 3 ++- build.gradle | 3 ++- gradle/libs.versions.toml | 7 ++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5b07be5..b4c9861 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,8 +4,9 @@ plugins { id 'kotlin-kapt' id 'kotlinx-serialization' id 'dagger.hilt.android.plugin' - alias(libs.plugins.com.google.protobuf) alias(libs.plugins.com.google.devtools.ksp) + alias(libs.plugins.com.google.protobuf) + alias(libs.plugins.org.jetbrains.kotlin.plugin.compose) } android { diff --git a/build.gradle b/build.gradle index 0173f7b..d61fc8d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = libs.versions.org.jetbrains.kotlin + ext.kotlin_version = libs.versions.kotlin repositories { google() mavenCentral() @@ -19,6 +19,7 @@ buildscript { plugins { alias(libs.plugins.com.google.devtools.ksp) apply false + alias(libs.plugins.org.jetbrains.kotlin.plugin.compose) apply false } allprojects { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57dfa8f..c834b4c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +kotlin = "2.0.0" androidx-lifecycle = "2.8.0" androidx-room = "2.6.1" androidx-test = "1.5.0" @@ -13,7 +14,6 @@ com-github-bumptech-glide = "4.16.0" com-google-dagger = "2.51.1" com-squareup-okhttp3 = "4.12.0" com-squareup-retrofit2 = "2.10.0" -org-jetbrains-kotlin = "1.9.23" org-jetbrains-kotlinx = "1.8.0" [libraries] @@ -80,8 +80,8 @@ io-reactivex-rxjava2-rxandroid = "io.reactivex.rxjava2:rxandroid:2.1.1" io-reactivex-rxjava2-rxjava = "io.reactivex.rxjava2:rxjava:2.2.21" io-reactivex-rxjava2-rxkotlin = "io.reactivex.rxjava2:rxkotlin:2.4.0" junit = "junit:junit:4.13.2" -org-jetbrains-kotlin-kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } -org-jetbrains-kotlin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } +org-jetbrains-kotlin-kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +org-jetbrains-kotlin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" } org-jetbrains-kotlinx-kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "org-jetbrains-kotlinx" } org-jetbrains-kotlinx-kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "org-jetbrains-kotlinx" } org-jetbrains-kotlinx-kotlinx-coroutines-rx2 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2", version.ref = "org-jetbrains-kotlinx" } @@ -93,3 +93,4 @@ org-robolectric = "org.robolectric:robolectric:4.12.1" [plugins] com-google-protobuf = "com.google.protobuf:0.9.1" com-google-devtools-ksp = "com.google.devtools.ksp:2.0.0-1.0.22" +org-jetbrains-kotlin-plugin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } From 05c5f3cc3b0d34b1b17e4e73a22c4e1f542d9d97 Mon Sep 17 00:00:00 2001 From: EringiShimeji Date: Thu, 4 Jul 2024 12:48:13 +0900 Subject: [PATCH 10/10] add GithubRepoLocalDataSource --- .../data/GithubRepoRepository.kt | 37 ++++++++++++++++ .../GithubRepoCacheSerializer.kt | 2 +- .../GithubRepoLocalDataSource.kt} | 42 ++++++------------- .../practicalexam/di/DispatcherModule.kt | 15 +++++++ .../us/mitene/practicalexam/di/Dispatchers.kt | 6 +++ ...ource.kt => GithubRepoRemoteDataSource.kt} | 2 +- .../ui/screen/GithubReposViewModel.kt | 6 +-- 7 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/us/mitene/practicalexam/data/GithubRepoRepository.kt rename app/src/main/java/us/mitene/practicalexam/{data => datastore}/GithubRepoCacheSerializer.kt (94%) rename app/src/main/java/us/mitene/practicalexam/{data/GithubRepoCacheRepository.kt => datastore/GithubRepoLocalDataSource.kt} (54%) create mode 100644 app/src/main/java/us/mitene/practicalexam/di/DispatcherModule.kt create mode 100644 app/src/main/java/us/mitene/practicalexam/di/Dispatchers.kt rename app/src/main/java/us/mitene/practicalexam/network/{GithubApiDataSource.kt => GithubRepoRemoteDataSource.kt} (94%) diff --git a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoRepository.kt b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoRepository.kt new file mode 100644 index 0000000..9cfb31c --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/data/GithubRepoRepository.kt @@ -0,0 +1,37 @@ +package us.mitene.practicalexam.data + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import us.mitene.practicalexam.datastore.GithubRepoLocalDataSource +import us.mitene.practicalexam.network.GithubRepoRemoteDataSource +import java.time.ZonedDateTime +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class GithubRepoRepository @Inject constructor( + private val githubRepoLocalDataSource: GithubRepoLocalDataSource, + private val githubRepoRemoteDataSource: GithubRepoRemoteDataSource, +) { + private val reposCache = githubRepoLocalDataSource.repos + + suspend fun getNames(): Flow> { + val cache = reposCache.first() + val now = ZonedDateTime.now().toEpochSecond() - cache.fetchedAt + + if (now > CACHE_DURATION) { + val repos = githubRepoRemoteDataSource.getRepos() + githubRepoLocalDataSource.storeRepos(repos) + + return reposCache.map { it.namesList } + } + + return flowOf(cache.namesList) + } + + companion object { + private const val CACHE_DURATION = 30 // 秒で指定 + } +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheSerializer.kt b/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt similarity index 94% rename from app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheSerializer.kt rename to app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt index 6074787..529cec3 100644 --- a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheSerializer.kt +++ b/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoCacheSerializer.kt @@ -1,4 +1,4 @@ -package us.mitene.practicalexam.data +package us.mitene.practicalexam.datastore import androidx.datastore.core.CorruptionException import androidx.datastore.core.Serializer diff --git a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt b/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoLocalDataSource.kt similarity index 54% rename from app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt rename to app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoLocalDataSource.kt index 61db6a9..3b43aa6 100644 --- a/app/src/main/java/us/mitene/practicalexam/data/GithubRepoCacheRepository.kt +++ b/app/src/main/java/us/mitene/practicalexam/datastore/GithubRepoLocalDataSource.kt @@ -1,32 +1,32 @@ -package us.mitene.practicalexam.data +package us.mitene.practicalexam.datastore import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.dataStore import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext import timber.log.Timber import us.mitene.practicalexam.datastore.proto.GithubRepoCache -import us.mitene.practicalexam.network.GithubApiDataSource +import us.mitene.practicalexam.di.IoDispatcher +import us.mitene.practicalexam.network.GithubRepo import java.io.IOException import java.time.ZonedDateTime import javax.inject.Inject import javax.inject.Singleton @Singleton -class GithubRepoCacheRepository @Inject constructor( - private val github: GithubApiDataSource, +class GithubRepoLocalDataSource @Inject constructor( @ApplicationContext private val context: Context, + @IoDispatcher private val dispatcher: CoroutineDispatcher, ) { - private val Context.githubRepoCacheStore: DataStore by dataStore( + private val Context.githubRepoStore: DataStore by dataStore( fileName = DATA_STORE_FILE_NAME, serializer = GithubRepoCacheSerializer ) - private val repoCacheFlow = context.githubRepoCacheStore.data + + val repos = context.githubRepoStore.data .catch { exception -> // dataStore.data throws an IOException when an error is encountered when reading data if (exception is IOException) { @@ -37,25 +37,10 @@ class GithubRepoCacheRepository @Inject constructor( } } - suspend fun getNames(): Flow> { - val cache = repoCacheFlow.first() - Timber.tag(TAG).i("lastFetchedAt: ${cache.fetchedAt}") - val now = ZonedDateTime.now().toEpochSecond() - cache.fetchedAt - - if (now > CACHE_DURATION) { - fetch() - - return repoCacheFlow.map { it.namesList } - } - - return flowOf(cache.namesList) - } - - private suspend fun fetch() { - context.githubRepoCacheStore.updateData { cache -> - val names = github.getRepos().map { it.name } + suspend fun storeRepos(repos: List) = withContext(dispatcher) { + context.githubRepoStore.updateData { cache -> + val names = repos.map { it.name } val fetchedAt = ZonedDateTime.now().toEpochSecond() - Timber.tag(TAG).i("fetched cache at: $fetchedAt") cache.toBuilder() .setFetchedAt(fetchedAt) @@ -68,6 +53,5 @@ class GithubRepoCacheRepository @Inject constructor( companion object { private const val DATA_STORE_FILE_NAME = "github_repo_cache.pb" private const val TAG: String = "GithubRepoCacheRepo" - private const val CACHE_DURATION = 30 // 秒で指定 } } \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/di/DispatcherModule.kt b/app/src/main/java/us/mitene/practicalexam/di/DispatcherModule.kt new file mode 100644 index 0000000..2ea2e5c --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/di/DispatcherModule.kt @@ -0,0 +1,15 @@ +package us.mitene.practicalexam.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.Dispatchers + +@Module +@InstallIn(SingletonComponent::class) +object DispatcherModule { + @Provides + @IoDispatcher + internal fun providesIoDispatcher() = Dispatchers.IO +} \ No newline at end of file diff --git a/app/src/main/java/us/mitene/practicalexam/di/Dispatchers.kt b/app/src/main/java/us/mitene/practicalexam/di/Dispatchers.kt new file mode 100644 index 0000000..43f7f16 --- /dev/null +++ b/app/src/main/java/us/mitene/practicalexam/di/Dispatchers.kt @@ -0,0 +1,6 @@ +package us.mitene.practicalexam.di + +import javax.inject.Qualifier + +@Qualifier +annotation class IoDispatcher diff --git a/app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt b/app/src/main/java/us/mitene/practicalexam/network/GithubRepoRemoteDataSource.kt similarity index 94% rename from app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt rename to app/src/main/java/us/mitene/practicalexam/network/GithubRepoRemoteDataSource.kt index 374cb77..3c202fd 100644 --- a/app/src/main/java/us/mitene/practicalexam/network/GithubApiDataSource.kt +++ b/app/src/main/java/us/mitene/practicalexam/network/GithubRepoRemoteDataSource.kt @@ -14,7 +14,7 @@ interface GithubApi { } @Singleton -class GithubApiDataSource @Inject constructor() { +class GithubRepoRemoteDataSource @Inject constructor() { private val json = Json { ignoreUnknownKeys = true } private val retrofit = Retrofit.Builder() .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) diff --git a/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt index 182a1b9..d63e1e0 100644 --- a/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt +++ b/app/src/main/java/us/mitene/practicalexam/ui/screen/GithubReposViewModel.kt @@ -6,12 +6,12 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import us.mitene.practicalexam.data.GithubRepoCacheRepository +import us.mitene.practicalexam.data.GithubRepoRepository import javax.inject.Inject @HiltViewModel class GithubReposViewModel @Inject constructor( - private val githubRepoCacheRepository: GithubRepoCacheRepository, + private val githubRepoRepository: GithubRepoRepository, ) : ViewModel() { private val _uiState = MutableStateFlow(GithubReposUiState(emptyList())) val uiState = _uiState.asStateFlow() @@ -22,7 +22,7 @@ class GithubReposViewModel @Inject constructor( private fun fetch() { viewModelScope.launch { - githubRepoCacheRepository.getNames().collect { + githubRepoRepository.getNames().collect { _uiState.value = GithubReposUiState(it) } }