プロジェクト

全般

プロフィール

« | » 

リビジョン b153e4bb

高徹 高橋 徹 さんが約5年前に追加

refs #167 Implements with DataBinding, LiveData, ViewModel, Repository and Room.

差分を表示:

learn/android/TempRecorderJetpackKt/.idea/compiler.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
</component>
</project>
learn/android/TempRecorderJetpackKt/.idea/misc.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
learn/android/TempRecorderJetpackKt/app/build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 30
......
}
buildFeatures {
viewBinding true
dataBinding true
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
......
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.room:room-runtime:2.2.5'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
kapt "androidx.room:room-compiler:2.2.5"
implementation "androidx.room:room-ktx:2.2.5"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
annotationProcessor 'androidx.room:room-compiler:2.2.5'
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/BindingUtils.kt
package com.torutk.android.temprecorder.jetpackkt
import android.widget.TextView
import androidx.databinding.BindingAdapter
import com.torutk.android.temprecorder.jetpackkt.domain.Temperature
import java.time.format.DateTimeFormatter
@BindingAdapter("measuredAtFormatted")
fun TextView.setMeasuredAtFormatted(item: Temperature) {
val pattern = context.resources.getString(R.string.main_measured_at_format)
val formatter = DateTimeFormatter.ofPattern(pattern)
text = item.measuredAt.format(formatter)
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/MainActivity.kt
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import com.torutk.android.temprecorder.jetpackkt.databinding.ActivityMainBinding
import java.time.LocalDateTime
......
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding // ViewBinding
private val model: MainViewModel by viewModels() // ViewModel
private val temperatureViewModel: MainViewModel by viewModels { MainViewModel.Factory(this.application) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
setContentView(binding.root)
// 検温日時の変更監視と表示設定
val measuredAtObserver = Observer<LocalDateTime> {
binding.textviewMainMeasuredat.text = it.format(DATE_TIME_VIEW_FORMATTER)
}
model.measuredAt.observe(this, measuredAtObserver)
temperatureViewModel.measuredAt.observe(this, measuredAtObserver)
// 検温日時の増減操作
binding.buttonMainIncminite.setOnClickListener { model.incrementMeasuredAt(10) }
binding.buttonMainDecminite.setOnClickListener { model.decrementMeasuredAt(10) }
binding.buttonMainIncminite.setOnClickListener { temperatureViewModel.incrementMeasuredAt(10) }
binding.buttonMainDecminite.setOnClickListener { temperatureViewModel.decrementMeasuredAt(10) }
// 体温入力用のNumberPicker設定
with (binding.numberpickerMainIntegral) {
......
maxValue = 9
value = 5
}
// 体温の登録
binding.buttonMainSubmit.setOnClickListener {
val temperature = binding.numberpickerMainIntegral.value + binding.numberpickerMainFraction.value / 10f
temperatureViewModel.submitTemperature(temperature)
}
val adapter = TemperatureAdapter()
binding.recyclerviewMainRecord.adapter = adapter
temperatureViewModel.temperatureList.observe(this, Observer {
it?.let {
adapter.submitList(it)
}
})
}
override fun onResume() {
super.onResume()
model.currentMeasuredAt()
temperatureViewModel.currentMeasuredAt()
}
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/MainViewModel.kt
package com.torutk.android.temprecorder.jetpackkt
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import android.app.Application
import androidx.lifecycle.*
import com.torutk.android.temprecorder.jetpackkt.database.TemperatureDatabase
import com.torutk.android.temprecorder.jetpackkt.domain.Temperature
import com.torutk.android.temprecorder.jetpackkt.repository.TemperatureRepository
import kotlinx.coroutines.launch
import java.time.LocalDateTime
class MainViewModel : ViewModel() {
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val temperatureRepository = TemperatureRepository(TemperatureDatabase.getInstance(application))
val temperatureList = temperatureRepository.temperatures
private val _measuredAt: MutableLiveData<LocalDateTime> = MutableLiveData(LocalDateTime.now())
val measuredAt: LiveData<LocalDateTime>
get() = _measuredAt
init {
refreshDataFromRepository()
}
fun incrementMeasuredAt(minutes: Long) {
_measuredAt.value = _measuredAt.value?.plusMinutes(minutes)
}
......
fun currentMeasuredAt() {
_measuredAt.value = LocalDateTime.now()
}
private fun refreshDataFromRepository() {
viewModelScope.launch {
temperatureRepository.refreshTemperatures()
}
}
fun submitTemperature(measurement: Float) {
val temp = Temperature(
measuredAt = measuredAt.value ?: LocalDateTime.now(),
measurement = measurement
)
viewModelScope.launch {
temperatureRepository.insert(temp)
}
}
class Factory(val app: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MainViewModel(app) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/TemperatureAdapter.kt
package com.torutk.android.temprecorder.jetpackkt
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.torutk.android.temprecorder.jetpackkt.databinding.ItemTemperatureBinding
import com.torutk.android.temprecorder.jetpackkt.domain.Temperature
class TemperatureAdapter() : ListAdapter<Temperature, TemperatureAdapter.ViewHolder>(TemperatureDiffCallback()) {
class ViewHolder private constructor(val binding: ItemTemperatureBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: Temperature) {
binding.temperature = item
binding.executePendingBindings()
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemTemperatureBinding.inflate(layoutInflater, parent, false)
return ViewHolder(binding)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder.from(parent)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
}
}
class TemperatureDiffCallback : DiffUtil.ItemCallback<Temperature>() {
override fun areItemsTheSame(oldItem: Temperature, newItem: Temperature): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Temperature, newItem: Temperature): Boolean {
return oldItem == newItem
}
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/database/LocalDateTimeConverter.kt
package com.torutk.android.temprecorder.jetpackkt.database
import androidx.room.TypeConverter
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class LocalDateTimeConverter {
@TypeConverter
fun fromLocalDateTime(dateTime: LocalDateTime): String {
return dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
}
@TypeConverter
fun toLocalDateTime(dateTimeText: String): LocalDateTime {
return LocalDateTime.parse(dateTimeText) // Default format is ISO_LOCAL_DATE_TIME
}
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/database/TemperatureDao.kt
package com.torutk.android.temprecorder.jetpackkt.database
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
@Dao
interface TemperatureDao {
@Insert
suspend fun insert(temperature: TemperatureEntity)
@Update
fun update(temperature: TemperatureEntity)
@Query("SELECT * FROM Temperatures WHERE id = :key")
fun get(key: Long): TemperatureEntity?
@Query("SELECT * FROM Temperatures ORDER BY id DESC")
fun getAllTemperatures(): LiveData<List<TemperatureEntity>>
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/database/TemperatureDatabase.kt
package com.torutk.android.temprecorder.jetpackkt.database
import android.content.Context
import androidx.room.*
import com.torutk.android.temprecorder.jetpackkt.domain.Temperature
internal const val DATABASE_FILE_NAME = "temperatures.db"
@Database(entities = [TemperatureEntity::class], version = 1)
@TypeConverters(LocalDateTimeConverter::class)
abstract class TemperatureDatabase : RoomDatabase() {
abstract val temperatureDao: TemperatureDao
companion object {
@Volatile
private var INSTANCE: TemperatureDatabase? = null
fun getInstance(context: Context): TemperatureDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
TemperatureDatabase::class.java,
DATABASE_FILE_NAME
).fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/database/TemperatureEntity.kt
package com.torutk.android.temprecorder.jetpackkt.database
import androidx.annotation.NonNull
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.torutk.android.temprecorder.jetpackkt.domain.Temperature
import java.time.LocalDateTime
@Entity(tableName = "Temperatures")
data class TemperatureEntity(
@PrimaryKey(autoGenerate = true)
var id: Long = 0L,
@ColumnInfo(name = "measured_at")
val measuredAt: LocalDateTime,
val measurement: Float
)
// Map database entities to domain entities
fun List<TemperatureEntity>.asDomainModel(): List<Temperature> {
return map {
Temperature(
id = it.id,
measuredAt = it.measuredAt,
measurement = it.measurement
)
}
}
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/domain/Temperature.kt
package com.torutk.android.temprecorder.jetpackkt.domain
import java.time.LocalDateTime
data class Temperature(val id: Long = 0, val measuredAt: LocalDateTime, val measurement: Float)
learn/android/TempRecorderJetpackKt/app/src/main/java/com/torutk/android/temprecorder/jetpackkt/repository/TemperatureRepository.kt
package com.torutk.android.temprecorder.jetpackkt.repository
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.torutk.android.temprecorder.jetpackkt.database.TemperatureDatabase
import com.torutk.android.temprecorder.jetpackkt.database.TemperatureEntity
import com.torutk.android.temprecorder.jetpackkt.database.asDomainModel
import com.torutk.android.temprecorder.jetpackkt.domain.Temperature
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class TemperatureRepository(private val database: TemperatureDatabase) {
val temperatures: LiveData<List<Temperature>> = Transformations.map(database.temperatureDao.getAllTemperatures()) {
it.asDomainModel()
}
suspend fun insert(temperature: Temperature) {
database.temperatureDao.insert(
TemperatureEntity(
measuredAt = temperature.measuredAt,
measurement = temperature.measurement
)
)
}
suspend fun refreshTemperatures() {
withContext(Dispatchers.IO) {
// リモートデータソースから取得したデータを、ローカルデータベースに格納する等
}
}
}
learn/android/TempRecorderJetpackKt/app/src/main/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="@+id/textview_main_submittitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/main_submittitle"
android:textSize="18sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<data>
<variable
name="temperatureViewModel"
type="com.torutk.android.temprecorder.jetpackkt.MainViewModel" />
</data>
<TextView
android:id="@+id/textview_main_measuredat"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="monospace"
android:textAlignment="center"
android:textSize="36sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_main_submittitle"
tools:text="09.27 21:22" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_main_incminite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/main_incminite"
app:layout_constraintEnd_toStartOf="@+id/button_main_decminite"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_main_measuredat" />
<TextView
android:id="@+id/textview_main_submittitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/main_submittitle"
android:textSize="18sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_main_decminite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_decminite"
app:layout_constraintBottom_toBottomOf="@+id/button_main_incminite"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button_main_incminite"
app:layout_constraintTop_toTopOf="@+id/button_main_incminite" />
<TextView
android:id="@+id/textview_main_measuredat"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="monospace"
android:textAlignment="center"
android:textSize="36sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_main_submittitle"
tools:text="09.27 21:22" />
<NumberPicker
android:id="@+id/numberpicker_main_integral"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toStartOf="@+id/numberpicker_main_fraction"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_main_incminite" />
<Button
android:id="@+id/button_main_incminite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/main_incminite"
app:layout_constraintEnd_toStartOf="@+id/button_main_decminite"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_main_measuredat" />
<NumberPicker
android:id="@+id/numberpicker_main_fraction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/numberpicker_main_integral"
app:layout_constraintEnd_toStartOf="@+id/button_main_submit"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/numberpicker_main_integral"
app:layout_constraintTop_toTopOf="@+id/numberpicker_main_integral" />
<Button
android:id="@+id/button_main_decminite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_decminite"
app:layout_constraintBottom_toBottomOf="@+id/button_main_incminite"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button_main_incminite"
app:layout_constraintTop_toTopOf="@+id/button_main_incminite" />
<Button
android:id="@+id/button_main_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_submit"
app:layout_constraintBottom_toBottomOf="@+id/numberpicker_main_fraction"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/numberpicker_main_fraction"
app:layout_constraintTop_toTopOf="@+id/numberpicker_main_fraction" />
<NumberPicker
android:id="@+id/numberpicker_main_integral"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toStartOf="@+id/numberpicker_main_fraction"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_main_incminite" />
<TextView
android:id="@+id/textview_main_listtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="@string/main_listtitle"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/numberpicker_main_integral" />
<NumberPicker
android:id="@+id/numberpicker_main_fraction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/numberpicker_main_integral"
app:layout_constraintEnd_toStartOf="@+id/button_main_submit"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/numberpicker_main_integral"
app:layout_constraintTop_toTopOf="@+id/numberpicker_main_integral" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_main_record"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_main_listtitle" />
<Button
android:id="@+id/button_main_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_submit"
app:layout_constraintBottom_toBottomOf="@+id/numberpicker_main_fraction"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/numberpicker_main_fraction"
app:layout_constraintTop_toTopOf="@+id/numberpicker_main_fraction" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/textview_main_listtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="@string/main_listtitle"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/numberpicker_main_integral" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_main_record"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layoutManager="LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_main_listtitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
learn/android/TempRecorderJetpackKt/app/src/main/res/layout/item_temperature.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="temperature"
type="com.torutk.android.temprecorder.jetpackkt.domain.Temperature" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/measured_at"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="center"
android:textSize="16sp"
app:measuredAtFormatted="@{temperature}" />
<TextView
android:id="@+id/measurement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@{String.valueOf(temperature.measurement)}"
android:textAlignment="center"
android:textSize="16sp" />
</LinearLayout>
</layout>
learn/android/TempRecorderJetpackKt/app/src/main/res/values-ja/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">検温くん(Jetpack Kotlin)</string>
<string name="main_submittitle">体温を登録</string>
<string name="main_incminite">10分後</string>
<string name="main_decminite">10分前</string>
<string name="main_submit">登録</string>
<string name="main_listtitle">検温の履歴</string>
</resources>
learn/android/TempRecorderJetpackKt/app/src/main/res/values/strings.xml
<string name="main_decminite">-10 Minites</string>
<string name="main_submit">Submit</string>
<string name="main_listtitle">My Temperature Record</string>
<string name="main_measured_at_format">MM.dd HH:mm</string>
</resources>
learn/android/TempRecorderJetpackKt/build.gradle
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
classpath 'com.android.tools.build:gradle:4.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong

他の形式にエクスポート: Unified diff