Skip to content

[DO NOT MERGE] Modern solution #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 98 additions & 81 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ plugins {
id 'kotlin-kapt'
id 'kotlinx-serialization'
id 'dagger.hilt.android.plugin'
alias(libs.plugins.com.google.devtools.ksp)
alias(libs.plugins.com.google.protobuf)
alias(libs.plugins.org.jetbrains.kotlin.plugin.compose)
}

android {
compileSdkVersion 34

defaultConfig {
applicationId "us.mitene.practicalexam"
minSdkVersion 26
targetSdkVersion 34
versionCode 1
versionName "1.0"
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()
versionName libs.versions.app.versionName.get()

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand All @@ -41,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()
Expand All @@ -54,112 +56,127 @@ 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)
ksp 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
ksp 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 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 libs.androidx.datastore
implementation libs.com.google.protobuf.protobuf.javalite
}

protobuf {
protoc {
artifact = libs.com.google.protobuf.protoc.get()
}

generateProtoTasks {
all().each { task ->
task.builtins {
java {
option 'lite'
}
}
}
}
}
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PracticalExam">
android:theme="@style/Theme.PracticalExam"
android:name=".MainApplication">
<activity
android:name=".MainActivity"
android:exported="true">
Expand Down
14 changes: 12 additions & 2 deletions app/src/main/java/us/mitene/practicalexam/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
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

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

setContent {
PracticalExamTheme {
GithubReposScreen()
}
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/us/mitene/practicalexam/MainApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package us.mitene.practicalexam

import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber

@HiltAndroidApp
class MainApplication : Application(){
override fun onCreate() {
super.onCreate()

Timber.plant(Timber.DebugTree())
}
}
Original file line number Diff line number Diff line change
@@ -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<List<String>> {
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 // 秒で指定
}
}
Original file line number Diff line number Diff line change
@@ -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<GithubRepoCache> {
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)
}
Loading