Move from java/ to kotlin/ directory

Android 12 dynamic color usage on login screen
This commit is contained in:
2021-08-31 02:18:29 +03:00
parent 2453e534ae
commit 1209c37e24
135 changed files with 140 additions and 57 deletions
@@ -0,0 +1,48 @@
package com.meloda.fast.base
import android.os.Bundle
import android.view.View
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import com.google.android.material.snackbar.Snackbar
abstract class BaseActivity : AppCompatActivity, LifecycleOwner {
constructor() : super()
constructor(@LayoutRes resId: Int) : super(resId)
protected lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
override fun onStart() {
super.onStart()
lifecycleRegistry.currentState = Lifecycle.State.STARTED
}
override fun onResume() {
super.onResume()
lifecycleRegistry.currentState = Lifecycle.State.RESUMED
}
override fun onDestroy() {
super.onDestroy()
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
val rootView: View? get() = findViewById(android.R.id.content)
fun requireRootView() = rootView!!
var errorSnackbar: Snackbar? = null
}
@@ -0,0 +1,12 @@
package com.meloda.fast.base
import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment
abstract class BaseFragment : Fragment {
constructor() : super()
constructor(@LayoutRes resId: Int) : super(resId)
}
@@ -0,0 +1,33 @@
package com.meloda.fast.base
import android.os.Bundle
import android.view.ViewGroup
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import com.meloda.fast.R
abstract class BaseFullscreenDialog : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.AppTheme_FullScreenDialog)
}
override fun onStart() {
super.onStart()
dialog?.let { dialog ->
val width = ViewGroup.LayoutParams.MATCH_PARENT
val height = ViewGroup.LayoutParams.MATCH_PARENT
dialog.window?.let {
it.setLayout(width, height)
it.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
it.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
it.setWindowAnimations(R.style.AppTheme_Slide)
}
}
}
}
@@ -0,0 +1,29 @@
package com.meloda.fast.base
import android.os.Bundle
import android.view.View
import androidx.annotation.LayoutRes
import androidx.lifecycle.lifecycleScope
import com.meloda.fast.base.viewmodel.BaseVM
import com.meloda.fast.base.viewmodel.VKEvent
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
abstract class BaseVMFragment<VM : BaseVM> : BaseFragment {
constructor() : super()
constructor(@LayoutRes resId: Int) : super(resId)
protected abstract val viewModel: VM
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.tasksEvent.onEach { onEvent(it) }.collect()
}
}
protected open fun onEvent(event: VKEvent) {}
}
@@ -0,0 +1,132 @@
package com.meloda.fast.base.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
@Suppress("UNCHECKED_CAST", "unused", "MemberVisibilityCanBePrivate", "CanBeParameter")
abstract class BaseAdapter<Item : BaseItem, VH : BaseHolder>(
var context: Context,
values: ArrayList<Item>,
diffUtil: DiffUtil.ItemCallback<Item>
) : ListAdapter<Item, VH>(diffUtil) {
val cleanValues = arrayListOf<Item>()
val values = arrayListOf<Item>()
init {
addAll(values)
}
protected var inflater: LayoutInflater = LayoutInflater.from(context)
var itemClickListener: OnItemClickListener? = null
var itemLongClickListener: OnItemLongClickListener? = null
open fun destroy() {
itemClickListener = null
itemLongClickListener = null
}
override fun getItem(position: Int): Item {
return values[position]
}
fun add(position: Int, item: Item) {
values.add(position, item)
cleanValues.add(position, item)
}
fun add(item: Item) {
values += item
cleanValues.add(item)
}
fun addAll(items: List<Item>) {
values += items
cleanValues.addAll(items)
}
fun addAll(position: Int, items: List<Item>) {
values.addAll(position, items)
cleanValues.addAll(position, items)
}
fun removeAll(items: List<Item>) {
values.removeAll(items)
cleanValues.removeAll(items)
}
fun removeAt(index: Int) {
values.removeAt(index)
cleanValues.removeAt(index)
}
fun remove(item: Item) {
values.remove(item)
cleanValues.remove(item)
}
fun clear() {
values.clear()
cleanValues.clear()
}
operator fun get(position: Int): Item {
return values[position]
}
operator fun set(position: Int, item: Item) {
values[position] = item
cleanValues[position] = item
}
open fun notifyChanges(oldList: List<Item>, newList: List<Item>) {}
fun isEmpty() = values.isEmpty()
fun isNotEmpty() = values.isNotEmpty()
fun view(resId: Int, viewGroup: ViewGroup, attachToRoot: Boolean = false): View {
return inflater.inflate(resId, viewGroup, attachToRoot)
}
fun updateValues(arrayList: ArrayList<Item>) {
values.clear()
values += arrayList
}
fun updateValues(list: List<Item>) = updateValues(ArrayList(list))
override fun onBindViewHolder(holder: VH, position: Int) {
onBindItemViewHolder(holder, position)
}
protected fun initListeners(itemView: View, position: Int) {
if (itemView is AdapterView<*>) return
itemView.setOnClickListener {
itemClickListener?.onItemClick(position)
}
itemView.setOnLongClickListener {
itemLongClickListener?.onItemLongClick(position)
return@setOnLongClickListener itemClickListener == null
}
}
override fun getItemCount(): Int {
return values.size
}
val size get() = itemCount
private fun onBindItemViewHolder(holder: VH, position: Int) {
initListeners(holder.itemView, position)
holder.bind(position)
}
}
@@ -0,0 +1,3 @@
package com.meloda.fast.base.adapter
abstract class BaseItem
@@ -0,0 +1,35 @@
package com.meloda.fast.base.adapter
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isInvisible
import androidx.recyclerview.widget.RecyclerView
import com.meloda.fast.util.AndroidUtils
import kotlin.math.roundToInt
class EmptyHeaderAdapter(
var context: Context
) : RecyclerView.Adapter<EmptyHeaderAdapter.Holder>() {
inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = Holder(generateHeaderView())
override fun onBindViewHolder(holder: Holder, position: Int) {
}
override fun getItemCount() = 1
private fun generateHeaderView() = View(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
AndroidUtils.px(56).roundToInt()
)
isClickable = false
isEnabled = false
isFocusable = false
isInvisible = true
}
}
@@ -0,0 +1,15 @@
package com.meloda.fast.base.adapter
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
abstract class BaseHolder(v: View) : RecyclerView.ViewHolder(v) {
open fun bind(position: Int) {}
open fun bind(position: Int, payloads: MutableList<Any>?) {}
}
abstract class BindingHolder<B : ViewBinding>(protected val binding: B) : BaseHolder(binding.root)
@@ -0,0 +1,9 @@
package com.meloda.fast.base.adapter
interface OnItemClickListener {
fun onItemClick(position: Int)
}
interface OnItemLongClickListener {
fun onItemLongClick(position: Int)
}
@@ -0,0 +1,33 @@
package com.meloda.fast.base.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.meloda.fast.api.Answer
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
abstract class BaseVM : ViewModel() {
protected val tasksEventChannel = Channel<VKEvent>()
val tasksEvent = tasksEventChannel.receiveAsFlow()
protected fun <T> makeJob(
job: suspend () -> Answer<T>,
onAnswer: suspend (T) -> Unit = {},
onStart: (suspend () -> Unit)? = null,
onEnd: (suspend () -> Unit)? = null,
onError: (suspend (String) -> Unit)? = null
) = viewModelScope.launch {
onStart?.invoke()
when (val response = job()) {
is Answer.Success -> onAnswer(response.data)
is Answer.Error -> onError?.invoke(response.errorString) ?: tasksEventChannel.send(
ShowDialogInfoEvent(null, response.errorString)
)
}
}.also { it.invokeOnCompletion { viewModelScope.launch { onEnd?.invoke() } } }
protected suspend fun <T : VKEvent> sendEvent(event: T) = tasksEventChannel.send(event)
}
@@ -0,0 +1,11 @@
package com.meloda.fast.base.viewmodel
data class ShowDialogInfoEvent(
val title: String? = null,
val message: String,
val positiveBtn: String? = null,
val negativeBtn: String? = null
) : VKEvent()
object StartProgressEvent : VKEvent()
object StopProgressEvent : VKEvent()
@@ -0,0 +1,3 @@
package com.meloda.fast.base.viewmodel
abstract class VKEvent