diff --git a/common.gradle b/common.gradle index 341b23d..27a0626 100644 --- a/common.gradle +++ b/common.gradle @@ -1,4 +1,4 @@ -ext.version = "1.2.0" +ext.version = "1.3.0" ext.group = "nz.co.trademe.konfigure" ext.repo = "konfigure" ext.org = "trademe" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 170d220..a0a8c9c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Aug 26 13:01:08 NZST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip diff --git a/konfigure-android/build.gradle b/konfigure-android/build.gradle index 213ff82..63fc5d9 100644 --- a/konfigure-android/build.gradle +++ b/konfigure-android/build.gradle @@ -13,7 +13,6 @@ buildscript { apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' ext { PUBLISH_VERSION = rootVersionName @@ -24,22 +23,24 @@ ext { apply from: '../common.gradle' apply from: '../publishing.gradle' -androidExtensions { - experimental = true -} +android { + namespace 'nz.co.trademe.konfigure.android' + buildFeatures { + viewBinding true + } +} dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) api project(":konfigure") - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$versions.coroutines" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$versions.coroutines" - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'com.google.android.material:material:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation "androidx.lifecycle:lifecycle-extensions:2.1.0" + implementation "androidx.appcompat:appcompat:$versions.appcompat" + implementation "com.google.android.material:material:$versions.material" + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" } diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/ConfigActivity.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/ConfigActivity.kt index b83f758..f1fa3e6 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/ConfigActivity.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/ConfigActivity.kt @@ -9,8 +9,8 @@ import android.view.inputmethod.InputMethodManager import androidx.annotation.CallSuper import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView -import kotlinx.android.synthetic.main.activity_config.* import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.ActivityConfigBinding import nz.co.trademe.konfigure.android.ui.view.ConfigView /** @@ -20,21 +20,22 @@ import nz.co.trademe.konfigure.android.ui.view.ConfigView * * To use, simply call [ConfigActivity.start] */ -open class ConfigActivity: AppCompatActivity() { +open class ConfigActivity : AppCompatActivity() { - val configurationView: ConfigView - get() = configView + private var _binding: ActivityConfigBinding? = null + protected val binding get() = _binding!! @CallSuper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_config) + _binding = ActivityConfigBinding.inflate(layoutInflater) + setContentView(binding.root) } @CallSuper override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) setTitle(R.string.configuration) supportActionBar?.apply { @@ -53,13 +54,13 @@ open class ConfigActivity: AppCompatActivity() { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { - configView.search(query ?: "") + binding.configView.search(query ?: "") hideSoftKeyboard() return true } override fun onQueryTextChange(newText: String?): Boolean { - configView.search(newText ?: "") + binding.configView.search(newText ?: "") return true } }) @@ -67,6 +68,11 @@ open class ConfigActivity: AppCompatActivity() { return true } + override fun onDestroy() { + super.onDestroy() + _binding = null + } + @CallSuper override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { @@ -74,6 +80,7 @@ open class ConfigActivity: AppCompatActivity() { finish() true } + else -> super.onOptionsItemSelected(item) } } diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BaseViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BaseViewHolder.kt index c4351c4..30bf858 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BaseViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BaseViewHolder.kt @@ -2,11 +2,11 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.view.View import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.extensions.LayoutContainer +import androidx.viewbinding.ViewBinding /** - * Simple base for ViewHolders which implements [LayoutContainer] + * Simple base for ViewHolders */ -internal open class BaseViewHolder( - override val containerView: View -): RecyclerView.ViewHolder(containerView), LayoutContainer \ No newline at end of file +internal open class BaseViewHolder( + protected val binding: VB +): RecyclerView.ViewHolder(binding.root) \ No newline at end of file diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BooleanConfigViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BooleanConfigViewHolder.kt index 4ce4839..a7785b1 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BooleanConfigViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/BooleanConfigViewHolder.kt @@ -1,29 +1,30 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.view.ViewGroup -import kotlinx.android.synthetic.main.view_holder_boolean.* -import nz.co.trademe.konfigure.android.R -import nz.co.trademe.konfigure.android.ui.adapter.ConfigAdapterModel +import nz.co.trademe.konfigure.android.databinding.ViewHolderBooleanBinding import nz.co.trademe.konfigure.android.extensions.applicationConfig +import nz.co.trademe.konfigure.android.ui.adapter.ConfigAdapterModel internal class BooleanConfigViewHolder( - parent: ViewGroup -) : BaseViewHolder(parent.inflate(R.layout.view_holder_boolean)) { + parent: ViewGroup, +) : BaseViewHolder(parent.inflate(ViewHolderBooleanBinding::inflate)) { fun bind(model: ConfigAdapterModel.BooleanConfig) { - itemView.setOnClickListener { - valueSwitch.toggle() - } + with(binding) { + itemView.setOnClickListener { + valueSwitch.toggle() + } - titleTextView.text = model.metadata.title - titleTextView.showAsModified(model.isModified) + titleTextView.text = model.metadata.title + titleTextView.showAsModified(model.isModified) - descriptionTextView.text = model.metadata.description + descriptionTextView.text = model.metadata.description - valueSwitch.setOnCheckedChangeListener(null) - valueSwitch.isChecked = model.value - valueSwitch.setOnCheckedChangeListener { _, newValue -> - itemView.context.applicationConfig.setValueOf(model.item, Boolean::class, newValue) + valueSwitch.setOnCheckedChangeListener(null) + valueSwitch.isChecked = model.value + valueSwitch.setOnCheckedChangeListener { _, newValue -> + itemView.context.applicationConfig.setValueOf(model.item, Boolean::class, newValue) + } } } } \ No newline at end of file diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/DividerViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/DividerViewHolder.kt index b80fe9f..048c6bd 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/DividerViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/DividerViewHolder.kt @@ -3,10 +3,11 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.view.ViewGroup import androidx.appcompat.content.res.AppCompatResources import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.ViewHolderDividerBinding internal class DividerViewHolder( parent: ViewGroup -) : BaseViewHolder(parent.inflate(R.layout.view_holder_divider)) { +) : BaseViewHolder(parent.inflate(ViewHolderDividerBinding::inflate)) { init { itemView.setBackgroundColor(AppCompatResources.getColorStateList(itemView.context, R.color.color_divider).defaultColor) diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/HeaderViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/HeaderViewHolder.kt index fa8efee..5881dc9 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/HeaderViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/HeaderViewHolder.kt @@ -1,14 +1,13 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.view.ViewGroup -import kotlinx.android.synthetic.main.view_holder_header.* -import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.ViewHolderHeaderBinding internal class HeaderViewHolder( parent: ViewGroup -) : BaseViewHolder(parent.inflate(R.layout.view_holder_header)) { +) : BaseViewHolder(parent.inflate(ViewHolderHeaderBinding::inflate)) { fun bind(title: String) { - titleTextView.text = title + binding.titleTextView.text = title } } \ No newline at end of file diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/NumberConfigViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/NumberConfigViewHolder.kt index 1e136fb..94d5448 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/NumberConfigViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/NumberConfigViewHolder.kt @@ -2,29 +2,31 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity -import kotlinx.android.synthetic.main.view_holder_number.* -import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.ViewHolderNumberBinding import nz.co.trademe.konfigure.android.ui.adapter.ConfigAdapterModel import nz.co.trademe.konfigure.android.ui.dialog.EditConfigDialogFragment internal class NumberConfigViewHolder( parent: ViewGroup -) : BaseViewHolder(parent.inflate(R.layout.view_holder_number)) { +) : BaseViewHolder(parent.inflate(ViewHolderNumberBinding::inflate)) { fun bind(model: ConfigAdapterModel.NumberConfig<*>) { - titleTextView.text = model.metadata.title - titleTextView.showAsModified(model.isModified) + with(binding) { + titleTextView.text = model.metadata.title + titleTextView.showAsModified(model.isModified) - descriptionTextView.text = model.metadata.description + descriptionTextView.text = model.metadata.description - currentValueTextView.text = model.value.toString() - currentValueTextView.applyMonospaceFont() + currentValueTextView.text = model.value.toString() + currentValueTextView.applyMonospaceFont() - itemView.setOnClickListener { - EditConfigDialogFragment.start( + itemView.setOnClickListener { + EditConfigDialogFragment.start( model.item, model.value.toString(), - (itemView.context as AppCompatActivity).supportFragmentManager) + (itemView.context as AppCompatActivity).supportFragmentManager + ) + } } } } \ No newline at end of file diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ResetToDefaultFooterViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ResetToDefaultFooterViewHolder.kt index 90894a5..5bf4b76 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ResetToDefaultFooterViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ResetToDefaultFooterViewHolder.kt @@ -1,15 +1,14 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.view.ViewGroup -import kotlinx.android.synthetic.main.view_holder_reset_to_default.* -import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.ViewHolderResetToDefaultBinding internal class ResetToDefaultFooterViewHolder( parent: ViewGroup -) : BaseViewHolder(parent.inflate(R.layout.view_holder_reset_to_default)) { +) : BaseViewHolder(parent.inflate(ViewHolderResetToDefaultBinding::inflate)) { fun bind(resetCallback: () -> Unit) { - resetToDefaultButton.setOnClickListener { + binding.resetToDefaultButton.setOnClickListener { resetCallback() } } diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/StringConfigViewHolder.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/StringConfigViewHolder.kt index 0b14383..2807d44 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/StringConfigViewHolder.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/StringConfigViewHolder.kt @@ -2,31 +2,33 @@ package nz.co.trademe.konfigure.android.ui.adapter.viewholder import android.annotation.SuppressLint import android.view.ViewGroup -import kotlinx.android.synthetic.main.view_holder_string.* -import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.ViewHolderStringBinding +import nz.co.trademe.konfigure.android.ui.ConfigActivity import nz.co.trademe.konfigure.android.ui.adapter.ConfigAdapterModel import nz.co.trademe.konfigure.android.ui.dialog.EditConfigDialogFragment -import nz.co.trademe.konfigure.android.ui.ConfigActivity internal class StringConfigViewHolder( parent: ViewGroup -) : BaseViewHolder(parent.inflate(R.layout.view_holder_string)) { +) : BaseViewHolder(parent.inflate(ViewHolderStringBinding::inflate)) { fun bind(model: ConfigAdapterModel.StringConfig) { - titleTextView.text = model.metadata.title - titleTextView.showAsModified(model.isModified) + with (binding) { + titleTextView.text = model.metadata.title + titleTextView.showAsModified(model.isModified) - descriptionTextView.text = model.metadata.description + descriptionTextView.text = model.metadata.description - @SuppressLint("SetTextI18n") - currentValueTextView.text = "\"${model.value}\"" - currentValueTextView.applyMonospaceFont() + @SuppressLint("SetTextI18n") + currentValueTextView.text = "\"${model.value}\"" + currentValueTextView.applyMonospaceFont() - itemView.setOnClickListener { - EditConfigDialogFragment.start( + itemView.setOnClickListener { + EditConfigDialogFragment.start( model.item, model.value, - (itemView.context as ConfigActivity).supportFragmentManager) + (itemView.context as ConfigActivity).supportFragmentManager + ) + } } } } \ No newline at end of file diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ViewHolderExtensions.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ViewHolderExtensions.kt index d113f34..8aa1a5c 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ViewHolderExtensions.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/adapter/viewholder/ViewHolderExtensions.kt @@ -6,13 +6,15 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.viewbinding.ViewBinding import nz.co.trademe.konfigure.android.R /** * Helper function for allowing simple ViewHolder view inflation */ -internal fun ViewGroup.inflate(@LayoutRes resource: Int): View = - LayoutInflater.from(context).inflate(resource, this, false) +internal fun ViewGroup.inflate(inflate: (LayoutInflater, ViewGroup, Boolean) -> VB): VB { + return inflate(LayoutInflater.from(context), this, false) +} internal fun TextView.applyMonospaceFont() { val typeface = Typeface.createFromAsset(context.assets, "fonts/RobotoMono-Regular.ttf") diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/dialog/EditConfigDialogFragment.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/dialog/EditConfigDialogFragment.kt index b8485b9..6895860 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/dialog/EditConfigDialogFragment.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/dialog/EditConfigDialogFragment.kt @@ -13,8 +13,8 @@ import android.view.View import android.view.WindowManager import android.view.inputmethod.EditorInfo import android.widget.TextView -import kotlinx.android.synthetic.main.edit_config_dialog.view.* import nz.co.trademe.konfigure.android.R +import nz.co.trademe.konfigure.android.databinding.EditConfigDialogBinding import nz.co.trademe.konfigure.android.extensions.applicationConfig import nz.co.trademe.konfigure.model.ConfigItem @@ -24,7 +24,8 @@ private const val TAG_EDIT_CONFIG = "tag_edit_config" internal class EditConfigDialogFragment : DialogFragment() { - private lateinit var contentView: View + private var _binding: EditConfigDialogBinding? = null + private val binding get() = _binding!! private val configItem: ConfigItem<*> get() = arguments?.getString(ARG_CONFIG_ITEM_KEY)?.let { key -> @@ -35,34 +36,36 @@ internal class EditConfigDialogFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { // Create our custom view with the edit text. val layoutInflater = LayoutInflater.from(context) - contentView = layoutInflater.inflate(R.layout.edit_config_dialog, null, false) - - // Handle the tick in the on-screen keyboard. - contentView.configTextInputEditText.setOnEditorActionListener { _: TextView, actionId: Int, _: KeyEvent? -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - onOkayClicked() - true - } else { - false + _binding = EditConfigDialogBinding.inflate(layoutInflater) + + with(binding) { + // Handle the tick in the on-screen keyboard. + configTextInputEditText.setOnEditorActionListener { _: TextView, actionId: Int, _: KeyEvent? -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + onOkayClicked() + true + } else { + false + } } - } - contentView.configTextInputEditText.inputType = when (configItem.defaultValue) { - is String -> InputType.TYPE_CLASS_TEXT - is Int, is Long -> InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_SIGNED - is Float, is Double -> InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL - else -> contentView.configTextInputEditText.inputType - } + configTextInputEditText.inputType = when (configItem.defaultValue) { + is String -> InputType.TYPE_CLASS_TEXT + is Int, is Long -> InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_SIGNED + is Float, is Double -> InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL + else -> configTextInputEditText.inputType + } - // Set the text on the input field - arguments?.getString(ARG_CURRENT_VALUE)?.let { - contentView.configTextInputEditText.append(it) + // Set the text on the input field + arguments?.getString(ARG_CURRENT_VALUE)?.let { + configTextInputEditText.append(it) + } } // Build the dialog. val dialog = AlertDialog.Builder(requireActivity()) .setTitle(R.string.edit_config) - .setView(contentView) + .setView(binding.root) .setPositiveButton(R.string.ok, null) .setNegativeButton(R.string.cancel, null) .create() @@ -81,15 +84,20 @@ internal class EditConfigDialogFragment : DialogFragment() { } } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + /** * Called when the user clicks the OK button. */ private fun onOkayClicked() { - val configValue = contentView.configTextInputEditText.text?.trim().toString() + val configValue = binding.configTextInputEditText.text?.trim().toString() // Don't allow updating to an empty String if (configValue.isEmpty()) { - contentView.configTextInputLayout.error = getString(R.string.config_blank_error) + binding.configTextInputLayout.error = getString(R.string.config_blank_error) return } @@ -116,7 +124,7 @@ internal class EditConfigDialogFragment : DialogFragment() { private inline fun setConfig(value: T) { @Suppress("UNCHECKED_CAST") - contentView.context.applicationConfig.setValueOf(configItem as ConfigItem, T::class, value) + requireContext().applicationConfig.setValueOf(configItem as ConfigItem, T::class, value) } companion object { diff --git a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/view/ConfigPresenter.kt b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/view/ConfigPresenter.kt index 6abf2e6..5d1af85 100644 --- a/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/view/ConfigPresenter.kt +++ b/konfigure-android/src/main/java/nz/co/trademe/konfigure/android/ui/view/ConfigPresenter.kt @@ -4,7 +4,11 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.ConflatedBroadcastChannel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow @@ -27,7 +31,7 @@ internal class ConfigPresenter( /** * Property acting as a search term relay for triggering async searching */ - private val searchTermRelay = ConflatedBroadcastChannel(value = EMPTY_SEARCH_TERM) + private val searchTermRelay = MutableStateFlow(EMPTY_SEARCH_TERM) /** * Property for emitting config changes as a flow @@ -37,7 +41,7 @@ internal class ConfigPresenter( emit(null) // Emit all config changes - emitAll(config.changes.openSubscription()) + emitAll(config.changes) } /** @@ -46,7 +50,7 @@ internal class ConfigPresenter( */ val models: Flow> = changeNotifier - .combine(searchTermRelay.asFlow()) { _, searchTerm -> + .combine(searchTermRelay.asStateFlow()) { _, searchTerm -> performSearch(searchTerm) } .flowOn(Dispatchers.IO) @@ -58,9 +62,7 @@ internal class ConfigPresenter( filters.add(filter) // Rerun the last search - searchTermRelay.valueOrNull?.let { - searchTermRelay.offer(it) - } + searchTermRelay.tryEmit(searchTermRelay.value) } /** @@ -69,7 +71,7 @@ internal class ConfigPresenter( * @param searchString The string to search using. */ fun search(searchString: String) { - searchTermRelay.offer(searchString) + searchTermRelay.tryEmit(searchString) } /** diff --git a/konfigure-android/src/main/res/layout/activity_config.xml b/konfigure-android/src/main/res/layout/activity_config.xml index fdbf192..71b86c4 100644 --- a/konfigure-android/src/main/res/layout/activity_config.xml +++ b/konfigure-android/src/main/res/layout/activity_config.xml @@ -24,10 +24,10 @@ android:layout_gravity="center" android:alpha="0.54" android:contentDescription="@null" - android:tint="?colorOnSurface" android:tintMode="src_in" app:srcCompat="@drawable/ic_search_black_24dp" - tools:targetApi="lollipop" /> + tools:targetApi="lollipop" + app:tint="?colorOnSurface" /> >() + private val _changes = MutableStateFlow?>(null) + val changes: Flow> = _changes.filterNotNull() /** * List of all config items binded to this config instance @@ -107,7 +115,7 @@ open class Config( overrideHandler.set(item.key, newValue.let(mapper.toString)) // Emit change - changes.offer( + _changes.tryEmit( ConfigChangeEvent( key = item.key, oldValue = oldValue, @@ -151,7 +159,7 @@ open class Config( // Publish events changeEvents.forEach { - changes.offer(it) + _changes.tryEmit(it) } } diff --git a/konfigure/src/main/java/nz/co/trademe/konfigure/internal/InMemoryOverrideHandler.kt b/konfigure/src/main/java/nz/co/trademe/konfigure/internal/InMemoryOverrideHandler.kt index 93bee63..10001ad 100644 --- a/konfigure/src/main/java/nz/co/trademe/konfigure/internal/InMemoryOverrideHandler.kt +++ b/konfigure/src/main/java/nz/co/trademe/konfigure/internal/InMemoryOverrideHandler.kt @@ -21,6 +21,6 @@ internal class InMemoryOverrideHandler: OverrideHandler { } override val all: Map - get() = backingMap + get() = backingMap.toMap() } \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 87485e0..b4fe9d6 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,10 +1,9 @@ apply plugin: 'com.android.application' - apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 29 + compileSdkVersion 33 + namespace 'nz.co.trademe.konfigure.sample' defaultConfig { applicationId "nz.co.trademe.konfigure.sample" versionCode 1 @@ -17,22 +16,21 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } -} - -androidExtensions { - experimental = true + buildFeatures { + viewBinding true + } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" - - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'com.google.android.material:material:1.1.0' - - implementation 'androidx.core:core-ktx:1.0.2' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha03' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin" implementation project(":konfigure-android") + + implementation "androidx.appcompat:appcompat:$versions.appcompat" + implementation "com.google.android.material:material:$versions.material" + + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index f05a117..27211dd 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -13,7 +13,9 @@ android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning"> - + diff --git a/sample/src/main/java/nz/co/trademe/konfigure/sample/MainActivity.kt b/sample/src/main/java/nz/co/trademe/konfigure/sample/MainActivity.kt index 8e6ba4b..2587960 100644 --- a/sample/src/main/java/nz/co/trademe/konfigure/sample/MainActivity.kt +++ b/sample/src/main/java/nz/co/trademe/konfigure/sample/MainActivity.kt @@ -3,7 +3,7 @@ package nz.co.trademe.konfigure.sample import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.recyclerview.widget.LinearLayoutManager -import kotlinx.android.synthetic.main.activity_main.* +import nz.co.trademe.konfigure.sample.databinding.ActivityMainBinding import nz.co.trademe.konfigure.sample.examples.AllExamples import nz.co.trademe.konfigure.sample.util.examples.ExamplesAdapter @@ -11,11 +11,13 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + with(ActivityMainBinding.inflate(layoutInflater)) { + setContentView(root) - exampleRecyclerView.layoutManager = LinearLayoutManager(this) - exampleRecyclerView.adapter = ExamplesAdapter().also { - it.submitList(AllExamples) + exampleRecyclerView.layoutManager = LinearLayoutManager(this@MainActivity) + exampleRecyclerView.adapter = ExamplesAdapter().also { + it.submitList(AllExamples) + } } } } diff --git a/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/filtering/FilteredConfigActivity.kt b/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/filtering/FilteredConfigActivity.kt index 9b5fbca..ae83735 100644 --- a/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/filtering/FilteredConfigActivity.kt +++ b/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/filtering/FilteredConfigActivity.kt @@ -18,6 +18,6 @@ class FilteredConfigActivity: ConfigActivity() { } } - configurationView.addFilter(filter) + binding.configView.addFilter(filter) } } \ No newline at end of file diff --git a/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/restart/ConfigRestartActivity.kt b/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/restart/ConfigRestartActivity.kt index 444afea..275fe99 100644 --- a/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/restart/ConfigRestartActivity.kt +++ b/sample/src/main/java/nz/co/trademe/konfigure/sample/examples/restart/ConfigRestartActivity.kt @@ -42,7 +42,6 @@ class ConfigRestartActivity : ConfigActivity() { // Observe changes and determine if a restart is required lifecycleScope.launch { applicationConfig.changes - .asFlow() // Only keep items which have restart information, and require tracking .filter { (it.metadata as? RestartMetadata)?.requiresRestart == true } diff --git a/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesAdapter.kt b/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesAdapter.kt index 3d71e42..b8fcca2 100644 --- a/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesAdapter.kt +++ b/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesAdapter.kt @@ -6,13 +6,14 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import nz.co.trademe.konfigure.sample.R +import nz.co.trademe.konfigure.sample.databinding.ViewholderExampleBinding import nz.co.trademe.konfigure.sample.examples.Example class ExamplesAdapter: ListAdapter(EXAMPLES_DIFF_CALLBACK) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExamplesViewHolder { - val view = LayoutInflater.from(parent.context).inflate(R.layout.viewholder_example, parent, false) - return ExamplesViewHolder(containerView = view) + val binding = ViewholderExampleBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ExamplesViewHolder(binding) } override fun onBindViewHolder(holder: ExamplesViewHolder, position: Int) { diff --git a/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesViewHolder.kt b/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesViewHolder.kt index 9871a2d..a20157a 100644 --- a/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesViewHolder.kt +++ b/sample/src/main/java/nz/co/trademe/konfigure/sample/util/examples/ExamplesViewHolder.kt @@ -1,22 +1,22 @@ package nz.co.trademe.konfigure.sample.util.examples -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.extensions.LayoutContainer +import nz.co.trademe.konfigure.sample.databinding.ViewholderExampleBinding import nz.co.trademe.konfigure.sample.examples.Example -import kotlinx.android.synthetic.main.viewholder_example.* class ExamplesViewHolder( - override val containerView: View -): RecyclerView.ViewHolder(containerView), LayoutContainer { + private val binding: ViewholderExampleBinding +) : RecyclerView.ViewHolder(binding.root) { fun bind(example: Example) { - exampleTitleTextView.text = example.title - exampleDescriptionTextView.text = example.description + with(binding) { + exampleTitleTextView.text = example.title + exampleDescriptionTextView.text = example.description - itemView.setOnClickListener { - example.onClick(it.context as AppCompatActivity) + itemView.setOnClickListener { + example.onClick(it.context as AppCompatActivity) + } } } } \ No newline at end of file diff --git a/versions.gradle b/versions.gradle index d11490f..b44f57f 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,13 +1,17 @@ ext { versions = [ "minSdkVersion" : 19, - "compileSdkVersion" : 30, - "targetSdkVersion" : 30, - "kotlin" : "1.3.50", - "coroutines" : "1.3.0", - "androidgradleplugin": '4.0.1', + "compileSdkVersion" : 33, + "targetSdkVersion" : 33, + "kotlin" : "1.8.10", + "coroutines" : "1.6.4", + "androidgradleplugin": "7.2.2", "androidmavenplugin" : "3.6.2", - "nexusPublish" : "1.1.0", - "dokka" : "1.6.10", + "nexusPublish" : "1.3.0", + "dokka" : "1.8.20", + "appcompat" : "1.6.1", + "material" : "1.9.0", + "firebaseConfig" : "21.4.1", + "firebaseAnalytics" : "21.3.0", ] } \ No newline at end of file