From a164f37bd75611511c40a9acd7d38a57d2006a27 Mon Sep 17 00:00:00 2001 From: atsumi Date: Wed, 16 Jul 2025 01:52:40 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20Android=E3=83=97=E3=83=AD=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=82=AF=E3=83=88=E3=82=92=E6=9C=80=E6=96=B0=E3=81=AE?= =?UTF-8?q?=E6=A7=8B=E6=88=90=E3=81=AB=E3=82=A2=E3=83=83=E3=83=97=E3=83=87?= =?UTF-8?q?=E3=83=BC=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主な変更内容: - Gradle Wrapperを8.0から8.9にアップデート - Android Gradle Pluginを8.1.1から8.7.3にアップデート - Kotlinを1.8.20から1.9.25にアップデート - targetSdk/compileSdkを33から35にアップデート - 各種依存関係を最新バージョンに更新 - BroadcastChannel(廃止)をSharedFlowに置き換え - gradle.propertiesの非推奨設定を修正 minSdkは23を維持し、ビルドの成功を確認済み。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- app/build.gradle | 2 +- .../kidspos/ui/common/ErrorDialogFragment.kt | 10 ++-- .../calculate/AccountResultDialogFragment.kt | 12 ++--- buildSrc/src/main/java/dependencies/Dep.kt | 2 +- .../src/main/java/dependencies/Versions.kt | 4 +- gradle.properties | 7 ++- gradle/libs.versions.toml | 50 +++++++++---------- gradle/wrapper/gradle-wrapper.properties | 2 +- 8 files changed, 44 insertions(+), 45 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f13e4c8..ccc0ac6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,6 +32,7 @@ android { buildFeatures { dataBinding true viewBinding true + buildConfig true } // ストアに出さないのでそのまま開発用 @@ -101,7 +102,6 @@ dependencies { implementation libs.kotlin.std.lib implementation libs.kotlinx.coroutines.android implementation libs.dagger.hilt.android - implementation libs.kotlinx.serialization implementation libs.kotlinx.serialization.json kapt libs.dagger.hilt.android.compiler diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/common/ErrorDialogFragment.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/common/ErrorDialogFragment.kt index 50b024c..84ffbd9 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/common/ErrorDialogFragment.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/common/ErrorDialogFragment.kt @@ -1,4 +1,3 @@ -@file:Suppress("EXPERIMENTAL_API_USAGE") package info.nukoneko.cuc.android.kidspos.ui.common @@ -11,7 +10,8 @@ import info.nukoneko.cuc.android.kidspos.R import info.nukoneko.cuc.android.kidspos.extensions.lazyWithArgs import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlin.coroutines.CoroutineContext @@ -24,7 +24,7 @@ class ErrorDialogFragment : DialogFragment(), CoroutineScope { OK } - private val channel = BroadcastChannel(1) + private val resultFlow = MutableSharedFlow(replay = 1) override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return AlertDialog.Builder(requireContext()) @@ -32,7 +32,7 @@ class ErrorDialogFragment : DialogFragment(), CoroutineScope { .setMessage(message) .setPositiveButton(android.R.string.ok) { _, _ -> launch { - channel.send(DialogResult.OK) + resultFlow.emit(DialogResult.OK) } } .setCancelable(false) @@ -55,7 +55,7 @@ class ErrorDialogFragment : DialogFragment(), CoroutineScope { } } fragment.show(fragmentManager, message) - return fragment.channel.openSubscription().receive() + return fragment.resultFlow.first() } } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/AccountResultDialogFragment.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/AccountResultDialogFragment.kt index 6968487..f6a3cdb 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/AccountResultDialogFragment.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/AccountResultDialogFragment.kt @@ -1,4 +1,3 @@ -@file:Suppress("EXPERIMENTAL_API_USAGE") package info.nukoneko.cuc.android.kidspos.ui.main.calculate @@ -15,7 +14,8 @@ import info.nukoneko.cuc.android.kidspos.databinding.FragmentAccountResultDialog import info.nukoneko.cuc.android.kidspos.extensions.lazyWithArgs import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlin.coroutines.CoroutineContext @@ -28,7 +28,7 @@ class AccountResultDialogFragment : DialogFragment(), CoroutineScope { Cancel } - private val channel = BroadcastChannel(1) + private val resultFlow = MutableSharedFlow(replay = 1) private lateinit var binding: FragmentAccountResultDialogBinding @@ -57,13 +57,13 @@ class AccountResultDialogFragment : DialogFragment(), CoroutineScope { } binding.result4.findViewById(R.id.ok).setOnClickListener { launch { - channel.send(DialogResult.OK) + resultFlow.emit(DialogResult.OK) dialog?.dismiss() } } binding.result4.findViewById(R.id.go_back).setOnClickListener { launch { - channel.send(DialogResult.Cancel) + resultFlow.emit(DialogResult.Cancel) dialog?.dismiss() } } @@ -75,7 +75,7 @@ class AccountResultDialogFragment : DialogFragment(), CoroutineScope { suspend fun showAndSuspend(fm: FragmentManager, tag: String? = null): DialogResult { show(fm, tag) - return channel.openSubscription().receive() + return resultFlow.first() } companion object { diff --git a/buildSrc/src/main/java/dependencies/Dep.kt b/buildSrc/src/main/java/dependencies/Dep.kt index 7e92045..40da79e 100644 --- a/buildSrc/src/main/java/dependencies/Dep.kt +++ b/buildSrc/src/main/java/dependencies/Dep.kt @@ -3,7 +3,7 @@ package dependencies @Suppress("SpellCheckingInspection") object Dep { object Koin { - const val android = "io.insert-koin:koin-android:3.1.2" + const val android = "io.insert-koin:koin-android:3.5.0" } object Zxing { diff --git a/buildSrc/src/main/java/dependencies/Versions.kt b/buildSrc/src/main/java/dependencies/Versions.kt index 21350d3..397f393 100644 --- a/buildSrc/src/main/java/dependencies/Versions.kt +++ b/buildSrc/src/main/java/dependencies/Versions.kt @@ -1,9 +1,9 @@ package dependencies object Versions { - const val compileSdk = 33 + const val compileSdk = 35 const val minSdk = 23 - const val targetSdk = 33 + const val targetSdk = 35 const val versionCode = 8 const val versionName = "1.0.7" diff --git a/gradle.properties b/gradle.properties index 902438c..ff4444b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,6 @@ -org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 org.gradle.parallel=true android.useAndroidX=true -android.enableJetifier=true -android.defaults.buildfeatures.buildconfig=true -android.nonTransitiveRClass=false +android.enableJetifier=false +android.nonTransitiveRClass=true android.nonFinalResIds=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ae5dc4f..5a1101f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,33 +1,33 @@ [versions] -desugar_jdk_libs = "2.0.3" -kotlin = "1.8.20" -kotlinx-coroutines = "1.7.2" -kotlinx-serialization = "1.6.0" -dagger = "2.46.1" +desugar_jdk_libs = "2.1.3" +kotlin = "1.9.25" +kotlinx-coroutines = "1.9.0" +kotlinx-serialization = "1.6.3" +dagger = "2.53.1" -android-gradle-plugin = "8.1.1" +android-gradle-plugin = "8.7.3" cookpad-lisence-plugin = "1.2.8" -core-ktx = "1.10.1" -activity-ktx = "1.7.2" -fragment-ktx = "1.6.0" -preference-ktx = "1.2.0" -viewmodel-ktx = "2.6.1" +core-ktx = "1.15.0" +activity-ktx = "1.9.3" +fragment-ktx = "1.8.5" +preference-ktx = "1.2.1" +viewmodel-ktx = "2.8.7" -appcompat = "1.6.1" -recyclerview = "1.3.0" -material = "1.9.0" +appcompat = "1.7.0" +recyclerview = "1.3.2" +material = "1.12.0" swiperefreshlayout = "1.1.0" -browser = "1.5.0" -exifinterface = "1.3.6" +browser = "1.8.0" +exifinterface = "1.3.7" installreferrer = "2.2" constraintlayout = "2.1.4" -okhttp = "4.10.0" -retrofit = "2.9.0" +okhttp = "4.12.0" +retrofit = "2.11.0" retrofit-kotlin-serialization-converter = "1.0.0" -mockito = "5.0.0" -robolectric = "4.10.3" +mockito = "5.15.2" +robolectric = "4.13" espresso = "3.5.1" [libraries] @@ -40,7 +40,7 @@ androidx-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx" androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" } -androidx-hilt-compiler = { module = "androidx.hilt:hilt-compiler", version = "1.0.0" } +androidx-hilt-compiler = { module = "androidx.hilt:hilt-compiler", version = "1.2.0" } android-material = { module = "com.google.android.material:material", version.ref = "material" } desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" } @@ -52,7 +52,7 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa dagger-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "dagger" } dagger-hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "dagger" } -firebase-bom = { module = "com.google.firebase:firebase-bom", version = "32.2.3" } +firebase-bom = { module = "com.google.firebase:firebase-bom", version = "33.7.0" } firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx" } firebase-crashlytics-ktx = { module = "com.google.firebase:firebase-crashlytics-ktx" } @@ -97,9 +97,9 @@ android-application = { id = "com.android.application", version.ref = "android-g android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinx-serialization" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -google-services = { id = "com.google.gms.google-services", version = "4.3.10" } -firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "2.8.1" } +google-services = { id = "com.google.gms.google-services", version = "4.4.2" } +firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.2" } dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "dagger" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 485b6ca..02ca2c3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Apr 20 15:46:52 JST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME From 808d458102f55e1876e00ba482f74d5dde01d452 Mon Sep 17 00:00:00 2001 From: atsumi Date: Wed, 16 Jul 2025 02:18:04 +0900 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20Data=20Binding=E3=81=8B?= =?UTF-8?q?=E3=82=89View=20Binding=E3=81=B8=E7=A7=BB=E8=A1=8C=E3=81=A8?= =?UTF-8?q?=E3=83=AC=E3=82=AC=E3=82=B7=E3=83=BC=E3=82=B3=E3=83=BC=E3=83=89?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主な変更内容: ## View Binding移行 - Data Bindingを無効化し、View Bindingに完全移行 - XMLレイアウトからタグとデータバインディング式を削除 - ViewModelのLiveDataを手動で観察する方式に変更 - クリックリスナーをコードで設定する方式に変更 ## レガシーコード削除 - Handler()の非推奨コンストラクタを修正(Looper.getMainLooper()を使用) - 未使用のStetho依存関係を削除 - 不要なItemStoreListContentViewModelクラスを削除 - onActivityResultをActivity Result APIに移行 - IntentIntegratorの廃止APIを新しいzxing-android-embeddedのAPIに更新 - FragmentExtensionsのBundle.get()を型別のgetメソッドに変更 これにより、将来的なKotlin 2.0への移行準備も整いました。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- app/build.gradle | 2 +- .../kidspos/extensions/FragmentExtensions.kt | 9 ++++- .../kidspos/ui/launch/LaunchActivity.kt | 3 +- .../android/kidspos/ui/main/MainActivity.kt | 9 ++--- .../calculate/CalculatorDialogFragment.kt | 30 +++++++++++--- .../ui/main/itemlist/ItemListFragment.kt | 36 +++++++++++++---- .../ItemStoreListContentViewModel.kt | 25 ------------ .../main/storelist/StoreListDialogFragment.kt | 29 +++++++++++--- .../ui/main/storelist/StoreListViewAdapter.kt | 39 +++++++------------ .../kidspos/ui/setting/SettingActivity.kt | 35 +++++++++++------ .../kidspos/ui/setting/SettingFragment.kt | 3 +- app/src/main/res/layout/activity_main.xml | 17 ++------ .../res/layout/fragment_calculator_dialog.xml | 27 ++++--------- .../main/res/layout/fragment_item_list.xml | 31 ++++++--------- .../res/layout/fragment_store_list_dialog.xml | 27 +++++-------- app/src/main/res/layout/item_store_list.xml | 17 ++------ gradle/libs.versions.toml | 3 +- 17 files changed, 167 insertions(+), 175 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ccc0ac6..a4d2d26 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,7 +30,7 @@ android { } buildFeatures { - dataBinding true + dataBinding false viewBinding true buildConfig true } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/extensions/FragmentExtensions.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/extensions/FragmentExtensions.kt index 1c5a3e9..6d36501 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/extensions/FragmentExtensions.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/extensions/FragmentExtensions.kt @@ -3,5 +3,12 @@ package info.nukoneko.cuc.android.kidspos.extensions import androidx.fragment.app.Fragment inline fun Fragment.lazyWithArgs(key: String): Lazy { - return lazy { arguments!!.get(key) as T } + return lazy { + when (T::class) { + String::class -> arguments!!.getString(key) as T + Int::class -> arguments!!.getInt(key) as T + Boolean::class -> arguments!!.getBoolean(key) as T + else -> arguments!!.getSerializable(key) as T + } + } } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/launch/LaunchActivity.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/launch/LaunchActivity.kt index 87a92e0..10433e9 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/launch/LaunchActivity.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/launch/LaunchActivity.kt @@ -2,13 +2,14 @@ package info.nukoneko.cuc.android.kidspos.ui.launch import android.os.Bundle import android.os.Handler +import android.os.Looper import androidx.appcompat.app.AppCompatActivity import info.nukoneko.cuc.android.kidspos.R import info.nukoneko.cuc.android.kidspos.ui.main.MainActivity class LaunchActivity : AppCompatActivity() { - private val handler = Handler() + private val handler = Handler(Looper.getMainLooper()) private val task = Runnable { if (isFinishing) return@Runnable MainActivity.createIntentWithClearTask(this@LaunchActivity) diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainActivity.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainActivity.kt index 30180f3..57e97d6 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainActivity.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/MainActivity.kt @@ -6,7 +6,6 @@ import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.view.GravityCompat -import androidx.databinding.DataBindingUtil import com.google.android.material.navigation.NavigationView import info.nukoneko.cuc.android.kidspos.ProjectSettings import info.nukoneko.cuc.android.kidspos.R @@ -60,7 +59,8 @@ class MainActivity : BaseBarcodeReadableActivity(), CoroutineScope { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = DataBindingUtil.setContentView(this, R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) setSupportActionBar(binding.toolbar) val toggle = ActionBarDrawerToggle( this, binding.drawerLayout, binding.toolbar, @@ -69,10 +69,7 @@ class MainActivity : BaseBarcodeReadableActivity(), CoroutineScope { binding.drawerLayout.addDrawerListener(toggle) toggle.syncState() binding.navView.setNavigationItemSelectedListener(navigationListener) - binding.viewModel = myViewModel.also { - it.listener = listener - } - binding.lifecycleOwner = this + myViewModel.listener = listener supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, ItemListFragment.newInstance(), "itemList") .commit() diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/CalculatorDialogFragment.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/CalculatorDialogFragment.kt index c1e24cf..ed3024b 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/CalculatorDialogFragment.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/calculate/CalculatorDialogFragment.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import android.widget.Toast -import androidx.databinding.DataBindingUtil import androidx.fragment.app.DialogFragment import info.nukoneko.cuc.android.kidspos.R import info.nukoneko.cuc.android.kidspos.databinding.FragmentCalculatorDialogBinding @@ -57,13 +56,12 @@ class CalculatorDialogFragment : DialogFragment(), CoroutineScope { container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = - DataBindingUtil.inflate(inflater, R.layout.fragment_calculator_dialog, container, false) - binding.lifecycleOwner = this + binding = FragmentCalculatorDialogBinding.inflate(inflater, container, false) setupNumberPanel() myViewModel.listener = listener myViewModel.setup(items, totalPrice) - binding.viewModel = myViewModel + setupViewModelObservers() + setupClickListeners() return binding.root } @@ -96,6 +94,28 @@ class CalculatorDialogFragment : DialogFragment(), CoroutineScope { binding.calculatorLayout.delete.setOnClickListener { myViewModel.onClearClick() } } + private fun setupViewModelObservers() { + myViewModel.getTotalPriceText().observe(viewLifecycleOwner) { price -> + binding.sumRiver.text = price + } + myViewModel.getDepositText().observe(viewLifecycleOwner) { deposit -> + binding.receiveRiver.text = deposit + } + myViewModel.getAccountButtonEnabled().observe(viewLifecycleOwner) { enabled -> + binding.done.isEnabled = enabled + binding.done.isClickable = enabled + } + } + + private fun setupClickListeners() { + binding.back.setOnClickListener { + myViewModel.onCancelClick(it) + } + binding.done.setOnClickListener { + myViewModel.onDoneClick(it) + } + } + companion object { private const val EXTRA_SUM_RIVER = "sum_price" private const val EXTRA_SALE_ITEMS = "sales_model" diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListFragment.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListFragment.kt index 8837a76..e385dd4 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListFragment.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/itemlist/ItemListFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast -import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -50,13 +49,12 @@ class ItemListFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - binding = DataBindingUtil.inflate(inflater, R.layout.fragment_item_list, container, false) - binding.viewModel = myViewModel.also { - it.listener = listener - } - binding.lifecycleOwner = this + ): View { + binding = FragmentItemListBinding.inflate(inflater, container, false) + myViewModel.listener = listener setupList(binding.recyclerView) + setupViewModelObservers() + setupClickListeners() return binding.root } @@ -80,6 +78,30 @@ class ItemListFragment : Fragment() { list.layoutManager = GridLayoutManager(list.context, 3) } + private fun setupViewModelObservers() { + myViewModel.getCurrentPriceText().observe(viewLifecycleOwner) { price -> + binding.priceView.text = price + } + myViewModel.getCurrentStaffText().observe(viewLifecycleOwner) { staff -> + binding.staffText.text = staff + } + myViewModel.getCurrentStaffVisibility().observe(viewLifecycleOwner) { visibility -> + binding.staffLayout.visibility = visibility + } + myViewModel.getAccountButtonEnabled().observe(viewLifecycleOwner) { enabled -> + binding.accountButton.isEnabled = enabled + } + } + + private fun setupClickListeners() { + binding.clearButton.setOnClickListener { + myViewModel.onClickClear(it) + } + binding.accountButton.setOnClickListener { + myViewModel.onClickAccount(it) + } + } + companion object { fun newInstance() = ItemListFragment() } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/ItemStoreListContentViewModel.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/ItemStoreListContentViewModel.kt index 2dc10b1..e69de29 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/ItemStoreListContentViewModel.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/ItemStoreListContentViewModel.kt @@ -1,25 +0,0 @@ -package info.nukoneko.cuc.android.kidspos.ui.main.storelist - -import android.view.View -import androidx.databinding.BaseObservable -import androidx.databinding.Bindable -import info.nukoneko.cuc.android.kidspos.entity.Store - -class ItemStoreListContentViewModel(private var store: Store, private val listener: Listener?) : - BaseObservable() { - @Bindable - val storeName = store.name - - fun onItemClick(@Suppress("UNUSED_PARAMETER") view: View?) { - listener?.onStoreSelected(store) - } - - fun setStore(store: Store) { - this.store = store - notifyChange() - } - - interface Listener { - fun onStoreSelected(store: Store) - } -} diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListDialogFragment.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListDialogFragment.kt index 7284676..ffe635e 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListDialogFragment.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListDialogFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast -import androidx.databinding.DataBindingUtil import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -44,11 +43,8 @@ class StoreListDialogFragment : DialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = - DataBindingUtil.inflate(inflater, R.layout.fragment_store_list_dialog, container, false) - binding.lifecycleOwner = this + binding = FragmentStoreListDialogBinding.inflate(inflater, container, false) myViewModel.listener = listener - binding.viewModel = myViewModel return binding.root } @@ -60,6 +56,8 @@ class StoreListDialogFragment : DialogFragment() { ) setupRecyclerView() setupSubscriber() + setupViewModelObservers() + setupClickListeners() } override fun onResume() { @@ -85,6 +83,27 @@ class StoreListDialogFragment : DialogFragment() { }) } + private fun setupViewModelObservers() { + myViewModel.getProgressVisibility().observe(viewLifecycleOwner) { visibility -> + binding.progressBar.visibility = visibility + } + myViewModel.getRecyclerViewVisibility().observe(viewLifecycleOwner) { visibility -> + binding.recyclerView.visibility = visibility + } + myViewModel.getErrorButtonVisibility().observe(viewLifecycleOwner) { visibility -> + binding.bottomView.visibility = visibility + } + } + + private fun setupClickListeners() { + binding.reloadButton.setOnClickListener { + myViewModel.onReload(it) + } + binding.closeButton.setOnClickListener { + myViewModel.onClose(it) + } + } + companion object { fun newInstance(): StoreListDialogFragment = StoreListDialogFragment() } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListViewAdapter.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListViewAdapter.kt index 65cc123..1344aac 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListViewAdapter.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/main/storelist/StoreListViewAdapter.kt @@ -2,10 +2,9 @@ package info.nukoneko.cuc.android.kidspos.ui.main.storelist import android.view.LayoutInflater import android.view.ViewGroup -import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import info.nukoneko.cuc.android.kidspos.R -import info.nukoneko.cuc.android.kidspos.databinding.ItemStoreListBinding +import android.widget.TextView import info.nukoneko.cuc.android.kidspos.entity.Store class StoreListViewAdapter : RecyclerView.Adapter() { @@ -14,15 +13,9 @@ class StoreListViewAdapter : RecyclerView.Adapter( - LayoutInflater.from(viewGroup.context), - R.layout.item_store_list, viewGroup, false - ) - return ViewHolder(binding, object : ViewHolder.Listener { - override fun onItemClick(store: Store) { - listener?.onStoreSelect(store) - } - }) + val view = LayoutInflater.from(viewGroup.context) + .inflate(R.layout.item_store_list, viewGroup, false) as TextView + return ViewHolder(view, listener) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -37,28 +30,22 @@ class StoreListViewAdapter : RecyclerView.Adapter + listener?.onStoreSelect(store) } } } fun bind(store: Store) { - if (binding.viewModel == null) { - binding.viewModel = ItemStoreListContentViewModel(store, listener) - } else { - binding.viewModel!!.setStore(store) - } - } - - interface Listener { - fun onItemClick(store: Store) + currentStore = store + textView.text = store.name } } } diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingActivity.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingActivity.kt index cd3149f..5080483 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingActivity.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingActivity.kt @@ -4,13 +4,26 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.webkit.URLUtil +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import com.google.zxing.integration.android.IntentIntegrator +import com.journeyapps.barcodescanner.ScanContract +import com.journeyapps.barcodescanner.ScanOptions import info.nukoneko.cuc.android.kidspos.di.GlobalConfig import org.koin.android.ext.android.inject class SettingActivity : AppCompatActivity() { private val config: GlobalConfig by inject() + + private val barcodeLauncher = registerForActivityResult( + ScanContract() + ) { result -> + if (result.contents != null) { + val serverAddress = result.contents + if (URLUtil.isValidUrl(serverAddress)) { + config.currentServerAddress = serverAddress + } + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -19,17 +32,15 @@ class SettingActivity : AppCompatActivity() { .replace(android.R.id.content, SettingFragment.newInstance()) .commit() } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) - if (result != null) { - val serverAddress = result.contents - if (URLUtil.isValidUrl(serverAddress)) { - config.currentServerAddress = serverAddress - } - } else { - super.onActivityResult(requestCode, resultCode, data) - } + + fun launchBarcodeScanner() { + val options = ScanOptions() + options.setDesiredBarcodeFormats(ScanOptions.QR_CODE) + options.setPrompt("QRコードをスキャンしてください") + options.setCameraId(0) + options.setBeepEnabled(false) + options.setBarcodeImageEnabled(true) + barcodeLauncher.launch(options) } companion object { diff --git a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingFragment.kt b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingFragment.kt index 8d654e7..e0c995b 100644 --- a/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingFragment.kt +++ b/app/src/main/kotlin/info/nukoneko/cuc/android/kidspos/ui/setting/SettingFragment.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment -import com.google.zxing.integration.android.IntentIntegrator import info.nukoneko.cuc.android.kidspos.databinding.FragmentSettingBinding import info.nukoneko.cuc.android.kidspos.di.GlobalConfig import info.nukoneko.cuc.android.kidspos.util.Mode @@ -51,7 +50,7 @@ class SettingFragment : Fragment() { private fun launchQrReader() { if (activity is SettingActivity) { - IntentIntegrator(activity).initiateScan() + (activity as SettingActivity).launchBarcodeScanner() } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index eadcd24..b607006 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,16 +1,8 @@ - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_calculator_dialog.xml b/app/src/main/res/layout/fragment_calculator_dialog.xml index e965a06..68b4a48 100644 --- a/app/src/main/res/layout/fragment_calculator_dialog.xml +++ b/app/src/main/res/layout/fragment_calculator_dialog.xml @@ -1,17 +1,9 @@ - - - - - - - - @@ -99,7 +91,7 @@ android:clickable="false" android:gravity="center_vertical|end" android:maxLines="1" - android:text="@{viewModel.depositText}" + tools:text="0" android:textStyle="bold" app:autoSizeTextType="uniform" /> @@ -119,7 +111,6 @@ android:layout_weight="0.5" android:autoSizeTextType="uniform" android:maxLines="1" - android:onClick="@{viewModel::onCancelClick}" android:paddingTop="16dp" android:paddingBottom="22dp" android:text="@string/go_back" @@ -133,15 +124,13 @@ android:layout_gravity="end|bottom" android:layout_weight="0.5" android:autoSizeTextType="uniform" - android:clickable="@{viewModel.accountButtonEnabled}" - android:enabled="@{viewModel.accountButtonEnabled}" + android:clickable="false" + android:enabled="false" android:maxLines="1" - android:onClick="@{viewModel::onDoneClick}" android:paddingTop="16dp" android:paddingBottom="22dp" android:text="@string/account" app:autoSizeTextType="uniform" /> - - + diff --git a/app/src/main/res/layout/fragment_item_list.xml b/app/src/main/res/layout/fragment_item_list.xml index bf19bb1..8dc52c7 100644 --- a/app/src/main/res/layout/fragment_item_list.xml +++ b/app/src/main/res/layout/fragment_item_list.xml @@ -1,16 +1,8 @@ - - - - - - - - @@ -53,7 +45,8 @@ android:layout_margin="4dp" android:layout_weight="1" android:orientation="vertical" - android:visibility="@{viewModel.currentStaffVisibility}"> + android:id="@+id/staff_layout" + android:visibility="invisible"> + android:id="@+id/staff_text" + tools:text="たんとう:" />