Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit eca78eb

Browse files
authored
Merge pull request #288 from icerockdev/fixes-for-chat
Fixes implemented in project development
2 parents 2cacf9a + 900794d commit eca78eb

File tree

13 files changed

+559
-3
lines changed

13 files changed

+559
-3
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import android.text.InputFilter.LengthFilter
8+
import android.view.View
9+
import android.view.ViewGroup
10+
import android.widget.EditText
11+
import dev.icerock.moko.widgets.core.ViewBundle
12+
import dev.icerock.moko.widgets.core.ViewFactory
13+
import dev.icerock.moko.widgets.core.ViewFactoryContext
14+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
15+
import dev.icerock.moko.widgets.core.utils.bind
16+
import dev.icerock.moko.widgets.core.widget.InputLengthWidget
17+
18+
actual open class InputLengthViewFactory actual constructor() : ViewFactory<InputLengthWidget<out WidgetSize>> {
19+
override fun <WS : WidgetSize> build(
20+
widget: InputLengthWidget<out WidgetSize>,
21+
size: WS,
22+
viewFactoryContext: ViewFactoryContext
23+
): ViewBundle<WS> {
24+
val bundle = widget.child.buildView(viewFactoryContext) as ViewBundle<WS>
25+
val editText: EditText = getEditText(bundle.view)
26+
?: throw IllegalArgumentException("EditText not found in child widget result view")
27+
28+
widget.maxLength.bind(viewFactoryContext.lifecycleOwner) { maxLength ->
29+
val filtersWithoutLength = editText.filters.filter { it !is LengthFilter }.toTypedArray()
30+
if (maxLength == null) {
31+
editText.filters = filtersWithoutLength
32+
} else {
33+
editText.filters = filtersWithoutLength.plus(LengthFilter(maxLength))
34+
}
35+
}
36+
37+
return bundle
38+
}
39+
40+
protected open fun getEditText(view: View): EditText? {
41+
when (view) {
42+
is EditText -> return view
43+
is ViewGroup -> {
44+
for (i in 0 until view.childCount) {
45+
val child = view.getChildAt(i)
46+
val editText = getEditText(child)
47+
if (editText != null) return editText
48+
}
49+
return null
50+
}
51+
else -> return null
52+
}
53+
}
54+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import androidx.recyclerview.widget.LinearLayoutManager
8+
import androidx.recyclerview.widget.RecyclerView
9+
import dev.icerock.moko.units.TableUnitItem
10+
import dev.icerock.moko.units.adapter.UnitsRecyclerViewAdapter
11+
import dev.icerock.moko.widgets.core.View
12+
import dev.icerock.moko.widgets.core.ViewBundle
13+
import dev.icerock.moko.widgets.core.ViewFactory
14+
import dev.icerock.moko.widgets.core.ViewFactoryContext
15+
import dev.icerock.moko.widgets.core.style.applyBackgroundIfNeeded
16+
import dev.icerock.moko.widgets.core.style.background.Background
17+
import dev.icerock.moko.widgets.core.style.background.Fill
18+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
19+
import dev.icerock.moko.widgets.core.utils.androidId
20+
import dev.icerock.moko.widgets.core.utils.bind
21+
import dev.icerock.moko.widgets.core.widget.ListWidget
22+
23+
actual class ReversedListWidgetFactory actual constructor(
24+
private val background: Background<Fill.Solid>?
25+
) : ViewFactory<ListWidget<out WidgetSize>> {
26+
27+
override fun <WS : WidgetSize> build(
28+
widget: ListWidget<out WidgetSize>,
29+
size: WS,
30+
viewFactoryContext: ViewFactoryContext
31+
): ViewBundle<WS> {
32+
val context = viewFactoryContext.androidContext
33+
val lifecycleOwner = viewFactoryContext.lifecycleOwner
34+
35+
val layoutManager = LinearLayoutManager(
36+
context,
37+
RecyclerView.VERTICAL,
38+
true
39+
)
40+
val unitsAdapter = UnitsRecyclerViewAdapter(lifecycleOwner)
41+
val recyclerView = RecyclerView(context).also {
42+
it.layoutManager = layoutManager
43+
it.adapter = unitsAdapter
44+
it.setHasFixedSize(true)
45+
46+
it.id = widget.id.androidId
47+
}
48+
49+
val resultView: View = recyclerView
50+
51+
widget.items.bind(lifecycleOwner) { units ->
52+
val list = units.orEmpty()
53+
val onReachEnd = widget.onReachEnd
54+
unitsAdapter.units = when (onReachEnd) {
55+
null -> list
56+
else -> list.observedEnd(onReachEnd)
57+
}
58+
}
59+
60+
with(resultView) {
61+
applyBackgroundIfNeeded(this@ReversedListWidgetFactory.background)
62+
}
63+
64+
return ViewBundle(
65+
view = resultView,
66+
size = size,
67+
margins = null
68+
)
69+
}
70+
71+
private fun List<TableUnitItem>.observedEnd(onReachEnd: () -> Unit): List<TableUnitItem> {
72+
if (this.isEmpty()) return this
73+
74+
val lastWrapped = TableUnitItemWrapper(
75+
item = this.last(),
76+
onBind = onReachEnd
77+
)
78+
return this.dropLast(1).plus(lastWrapped)
79+
}
80+
81+
private class TableUnitItemWrapper(
82+
private val item: TableUnitItem,
83+
private val onBind: () -> Unit
84+
) : TableUnitItem by item {
85+
override fun bindViewHolder(viewHolder: RecyclerView.ViewHolder) {
86+
item.bindViewHolder(viewHolder)
87+
onBind()
88+
}
89+
}
90+
}

widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/core/factory/StatefulViewFactory.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,13 @@ actual class StatefulViewFactory actual constructor(
6969
is State.Error -> errorView
7070
}
7171

72-
views.forEach { it.view.visibility = View.GONE }
73-
currentView.view.visibility = View.VISIBLE
72+
views.asSequence()
73+
.filter { it.view.visibility != View.GONE && it.view.id != currentView.view.id }
74+
.forEach { it.view.visibility = View.GONE }
75+
76+
if (currentView.view.visibility != View.VISIBLE) {
77+
currentView.view.visibility = View.VISIBLE
78+
}
7479
}
7580

7681
return ViewBundle(
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import android.widget.LinearLayout
8+
import dev.icerock.moko.widgets.core.ViewBundle
9+
import dev.icerock.moko.widgets.core.ViewFactory
10+
import dev.icerock.moko.widgets.core.ViewFactoryContext
11+
import dev.icerock.moko.widgets.core.style.ext.applyMargin
12+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
13+
import dev.icerock.moko.widgets.core.widget.VerticalPageWidget
14+
15+
actual open class VerticalPageViewFactory actual constructor() :
16+
ViewFactory<VerticalPageWidget<out WidgetSize>> {
17+
18+
override fun <WS : WidgetSize> build(
19+
widget: VerticalPageWidget<out WidgetSize>,
20+
size: WS,
21+
viewFactoryContext: ViewFactoryContext
22+
): ViewBundle<WS> {
23+
val context = viewFactoryContext.androidContext
24+
25+
val container = LinearLayout(context).apply {
26+
orientation = LinearLayout.VERTICAL
27+
}
28+
29+
val childContext = viewFactoryContext.copy(parent = container)
30+
31+
widget.header?.let { header ->
32+
val childBundle = header.buildView(childContext)
33+
container.addView(childBundle.view)
34+
}
35+
36+
val bodyBundle = widget.body.buildView(childContext)
37+
val layoutParams = LinearLayout.LayoutParams(
38+
LinearLayout.LayoutParams.MATCH_PARENT,
39+
0,
40+
1f
41+
).apply {
42+
bodyBundle.margins?.let { applyMargin(context, it) }
43+
}
44+
container.addView(bodyBundle.view, layoutParams)
45+
46+
widget.footer?.let { footer ->
47+
val childBundle = footer.buildView(childContext)
48+
container.addView(childBundle.view)
49+
}
50+
51+
return ViewBundle(
52+
view = container,
53+
size = size,
54+
margins = null
55+
)
56+
}
57+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import dev.icerock.moko.widgets.core.ViewFactory
8+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
9+
import dev.icerock.moko.widgets.core.widget.InputLengthWidget
10+
11+
expect open class InputLengthViewFactory() : ViewFactory<InputLengthWidget<out WidgetSize>>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import dev.icerock.moko.widgets.core.ViewFactory
8+
import dev.icerock.moko.widgets.core.style.background.Background
9+
import dev.icerock.moko.widgets.core.style.background.Fill
10+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
11+
import dev.icerock.moko.widgets.core.widget.ListWidget
12+
13+
expect class ReversedListWidgetFactory(
14+
background: Background<Fill.Solid>?
15+
) : ViewFactory<ListWidget<out WidgetSize>>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import dev.icerock.moko.widgets.core.ViewFactory
8+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
9+
import dev.icerock.moko.widgets.core.widget.VerticalPageWidget
10+
11+
expect open class VerticalPageViewFactory() : ViewFactory<VerticalPageWidget<out WidgetSize>>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.widget
6+
7+
import dev.icerock.moko.mvvm.livedata.LiveData
8+
import dev.icerock.moko.widgets.core.OptionalId
9+
import dev.icerock.moko.widgets.core.Theme
10+
import dev.icerock.moko.widgets.core.ViewBundle
11+
import dev.icerock.moko.widgets.core.ViewFactory
12+
import dev.icerock.moko.widgets.core.ViewFactoryContext
13+
import dev.icerock.moko.widgets.core.Widget
14+
import dev.icerock.moko.widgets.core.WidgetDef
15+
import dev.icerock.moko.widgets.core.factory.InputLengthViewFactory
16+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
17+
18+
@WidgetDef(InputLengthViewFactory::class)
19+
class InputLengthWidget<WS : WidgetSize>(
20+
private val factory: ViewFactory<InputLengthWidget<out WidgetSize>>,
21+
override val id: Id?,
22+
val child: InputWidget<WS>,
23+
val maxLength: LiveData<Int?>
24+
) : Widget<WS>(), OptionalId<InputLengthWidget.Id> {
25+
override val size: WS = child.size
26+
27+
override fun buildView(viewFactoryContext: ViewFactoryContext): ViewBundle<WS> {
28+
return factory.build(this, size, viewFactoryContext)
29+
}
30+
31+
interface Id : Theme.Id<InputLengthWidget<out WidgetSize>>
32+
interface Category : Theme.Category<InputLengthWidget<out WidgetSize>>
33+
34+
object DefaultCategory : Category
35+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.widget
6+
7+
import dev.icerock.moko.widgets.core.OptionalId
8+
import dev.icerock.moko.widgets.core.Theme
9+
import dev.icerock.moko.widgets.core.ViewBundle
10+
import dev.icerock.moko.widgets.core.ViewFactory
11+
import dev.icerock.moko.widgets.core.ViewFactoryContext
12+
import dev.icerock.moko.widgets.core.Widget
13+
import dev.icerock.moko.widgets.core.WidgetDef
14+
import dev.icerock.moko.widgets.core.factory.VerticalPageViewFactory
15+
import dev.icerock.moko.widgets.core.style.view.SizeSpec
16+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
17+
18+
@WidgetDef(VerticalPageViewFactory::class)
19+
class VerticalPageWidget<WS : WidgetSize>(
20+
private val factory: ViewFactory<VerticalPageWidget<out WidgetSize>>,
21+
override val size: WS,
22+
override val id: Id?,
23+
val header: Widget<out WidgetSize>? = null,
24+
val body: Widget<WidgetSize.Const<SizeSpec.AsParent, SizeSpec.MatchConstraint>>,
25+
val footer: Widget<out WidgetSize>? = null
26+
) : Widget<WS>(), OptionalId<VerticalPageWidget.Id> {
27+
28+
override fun buildView(viewFactoryContext: ViewFactoryContext): ViewBundle<WS> {
29+
return factory.build(this, size, viewFactoryContext)
30+
}
31+
32+
interface Id : Theme.Id<VerticalPageWidget<out WidgetSize>>
33+
interface Category : Theme.Category<VerticalPageWidget<out WidgetSize>>
34+
35+
object DefaultCategory : Category
36+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.icerock.moko.widgets.core.factory
6+
7+
import dev.icerock.moko.mvvm.livedata.mergeWith
8+
import dev.icerock.moko.widgets.core.ViewBundle
9+
import dev.icerock.moko.widgets.core.ViewFactory
10+
import dev.icerock.moko.widgets.core.ViewFactoryContext
11+
import dev.icerock.moko.widgets.core.style.view.WidgetSize
12+
import dev.icerock.moko.widgets.core.widget.InputLengthWidget
13+
14+
actual open class InputLengthViewFactory actual constructor() :
15+
ViewFactory<InputLengthWidget<out WidgetSize>> {
16+
override fun <WS : WidgetSize> build(
17+
widget: InputLengthWidget<out WidgetSize>,
18+
size: WS,
19+
viewFactoryContext: ViewFactoryContext
20+
): ViewBundle<WS> {
21+
val bundle = widget.child.buildView(viewFactoryContext) as ViewBundle<WS>
22+
23+
widget.maxLength.mergeWith(widget.child.field.data) { maxLength, userInput ->
24+
if (maxLength != null && userInput.length > maxLength) {
25+
widget.child.field.data.value = userInput.take(maxLength)
26+
}
27+
}
28+
29+
return bundle
30+
}
31+
}

0 commit comments

Comments
 (0)