-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Artem
committed
Mar 6, 2021
1 parent
1cc3f08
commit cae68b4
Showing
13 changed files
with
711 additions
and
0 deletions.
There are no files selected for viewing
53 changes: 53 additions & 0 deletions
53
mad-base/src/main/java/ru/wearemad/mad_base/collection/CollectionExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package ru.wearemad.mad_base.collection | ||
|
||
fun <T> MutableList<T>.copyListAndReplaceItem( | ||
predicate: (T) -> Boolean, | ||
duplicator: (T) -> T, | ||
action: (T) -> Unit = {} | ||
): MutableList<T> { | ||
val newList = this.toMutableList() | ||
val itemPosition = newList.indexOfFirst(predicate) | ||
if (itemPosition != -1) { | ||
val copiedItem = duplicator(newList[itemPosition]) | ||
action(copiedItem) | ||
newList.removeAt(itemPosition) | ||
newList.add(itemPosition, copiedItem) | ||
} | ||
return newList | ||
} | ||
|
||
fun <T> MutableList<T>.replaceItem( | ||
predicate: (T) -> Boolean, | ||
duplicator: (T) -> T, | ||
action: (T) -> Unit = {} | ||
) { | ||
val itemPosition = indexOfFirst(predicate) | ||
if (itemPosition != -1) { | ||
val copiedItem = duplicator(get(itemPosition)) | ||
action(copiedItem) | ||
removeAt(itemPosition) | ||
add(itemPosition, copiedItem) | ||
} | ||
} | ||
|
||
fun <T> MutableList<T>.replaceItemByPosition( | ||
itemPosition: Int, | ||
duplicator: (T) -> T | ||
) { | ||
val copiedItem = duplicator(get(itemPosition)) | ||
removeAt(itemPosition) | ||
add(itemPosition, copiedItem) | ||
} | ||
|
||
fun <T> MutableList<T>.replaceItemFromOneListToAnother( | ||
source: List<T>, | ||
targetPredicate: (T) -> Boolean, | ||
sourcePredicate: (T) -> Boolean = targetPredicate | ||
) { | ||
val targetPosition = indexOfFirst(targetPredicate) | ||
val sourcePosition = source.indexOfFirst(sourcePredicate) | ||
if (targetPosition != -1 && sourcePosition != -1) { | ||
removeAt(targetPosition) | ||
add(targetPosition, source[sourcePosition]) | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
mad-base/src/main/java/ru/wearemad/mad_base/data_wrapper/DataWrapperExtension.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package ru.wearemad.mad_base.data_wrapper | ||
|
||
/** | ||
* Extension-функции для [DataWrapperInterface] | ||
*/ | ||
|
||
fun <T> Collection<DataWrapperInterface<T>>.getData(): Collection<T> = | ||
this.map { it.data } | ||
|
||
fun <T> List<DataWrapperInterface<T>>.getData(): List<T> = | ||
this.map { it.data } | ||
|
||
fun <T> Set<DataWrapperInterface<T>>.getData(): Set<T> = | ||
this.map { it.data }.toSet() | ||
|
||
/** | ||
* Найти объект(ы) в коллекции по filterPredicate | ||
* и изменить в соответствии с applyConsumer | ||
*/ | ||
fun <T, E : DataWrapperInterface<T>> filterAndApply( | ||
collection: Collection<E>, | ||
filterPredicate: (T) -> Boolean, | ||
applyConsumer: (E) -> Unit | ||
) { | ||
collection | ||
.filter { filterPredicate(it.data) } | ||
.forEach { applyConsumer(it) } | ||
} | ||
|
||
inline fun <reified T> List<*>.isListOfType(): Boolean { | ||
return all { it is T } | ||
} |
6 changes: 6 additions & 0 deletions
6
mad-base/src/main/java/ru/wearemad/mad_base/data_wrapper/DataWrapperInterface.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package ru.wearemad.mad_base.data_wrapper | ||
|
||
interface DataWrapperInterface<T : Any?> { | ||
|
||
var data: T | ||
} |
25 changes: 25 additions & 0 deletions
25
mad-base/src/main/java/ru/wearemad/mad_base/data_wrapper/checkable/CheckableData.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package ru.wearemad.mad_base.data_wrapper.checkable | ||
|
||
import ru.wearemad.mad_base.data_wrapper.DataWrapperInterface | ||
|
||
/** | ||
* Интерфейс сущности, если объект может быть выделяемым | ||
*/ | ||
interface CheckableDataInterface { | ||
|
||
var isChecked: Boolean | ||
|
||
fun toggleChecked() { | ||
isChecked = !isChecked | ||
} | ||
} | ||
|
||
/** | ||
* Поддерживает множество выделений, через расширение коллекций | ||
* Если необходимо одиночное выделение -> смотри [SelectableData] | ||
*/ | ||
data class CheckableData<T : Any?>( | ||
override var data: T, | ||
override var isChecked: Boolean = false | ||
) : DataWrapperInterface<T>, | ||
CheckableDataInterface |
125 changes: 125 additions & 0 deletions
125
mad-base/src/main/java/ru/wearemad/mad_base/data_wrapper/checkable/CheckableExtension.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package ru.wearemad.mad_base.data_wrapper.checkable | ||
|
||
import ru.wearemad.mad_base.data_wrapper.DataWrapperInterface | ||
import ru.wearemad.mad_base.data_wrapper.filterAndApply | ||
|
||
/** | ||
* Extension-функции для коллекции, использующая [CheckableData] | ||
* у [CheckableData] может быть несколько выделенных элементов | ||
* | ||
* Если необходимо одиночное выделение -> смотри [SelectableData] | ||
*/ | ||
|
||
/** | ||
* Изменить выделение для <T> на противоположный, | ||
* удовлетворающее предикату | ||
* | ||
* @param (T) -> Boolean | ||
*/ | ||
fun <T : Any?, E> Collection<E>.toggleChecked(predicate: (T) -> Boolean) | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
filterAndApply(this, { predicate(it) }, { it.toggleChecked() }) | ||
} | ||
|
||
/** | ||
* Поставить выделение для <T>, удовлетворающее предикату | ||
* | ||
* @param (T) -> Boolean | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setCheck(predicate: (T) -> Boolean) | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
filterAndApply(this, { predicate(it) }, { it.isChecked = true }) | ||
} | ||
|
||
/** | ||
* Убрать выделение для <T>, удовлетворающее предикату | ||
* | ||
* @param (T) -> Boolean | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setUncheck(predicate: (T) -> Boolean) | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
filterAndApply(this, { predicate(it) }, { it.isChecked = false }) | ||
} | ||
|
||
/** | ||
* Изменить выделение для <T> на противоположный | ||
* @param T | ||
*/ | ||
fun <T : Any?, E> Collection<E>.toggleChecked(value: T) | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
toggleChecked(predicate = { it == value }) | ||
} | ||
|
||
/** | ||
* Поставить выделение для <T> | ||
* @param T | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setCheck(value: T) | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
setCheck(predicate = { it == value }) | ||
} | ||
|
||
/** | ||
* Убрать выделение для <T> | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setUncheck(value: T) | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
setUncheck(predicate = { it == value }) | ||
} | ||
|
||
/** | ||
* @return коллекции с выделенными | ||
*/ | ||
fun <T : Any?, E> Collection<E>.getChecked(): Collection<T> | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
if (!isAnyChecked()) { | ||
throw IllegalStateException("нет выделенных элементов") | ||
} | ||
return this.filter { it.isChecked }.map { it.data } | ||
} | ||
|
||
/** | ||
* @return коллекции с выделенными. Если не найдено, то null | ||
*/ | ||
fun <T : Any?, E> Collection<E>.getCheckedNullable(): Collection<T>? | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface = | ||
this.filter { it.isChecked }.map { it.data } | ||
|
||
/** | ||
* Выделить все | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setCheckedAll() | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
this.forEach { | ||
it.apply { | ||
this.isChecked = true | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Убрать выделение у всех | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setUncheckedAll() | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
this.forEach { | ||
it.apply { | ||
this.isChecked = false | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Поставить выделение для первого | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setCheckedFirst() | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface { | ||
this.first().apply { this.isChecked = true } | ||
} | ||
|
||
/** | ||
* @return есть ли хотя бы один выделенный объект? | ||
*/ | ||
fun <T : Any?, E> Collection<E>.isAnyChecked(): Boolean | ||
where E : DataWrapperInterface<T>, E : CheckableDataInterface = | ||
this.find { it.isChecked } != null |
18 changes: 18 additions & 0 deletions
18
mad-base/src/main/java/ru/wearemad/mad_base/data_wrapper/selectable/SelectableData.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package ru.wearemad.mad_base.data_wrapper.selectable | ||
|
||
import ru.wearemad.mad_base.data_wrapper.DataWrapperInterface | ||
|
||
interface SelectableDataInterface { | ||
|
||
var isSelected: Boolean | ||
|
||
fun toggleSelected() { | ||
isSelected = !isSelected | ||
} | ||
} | ||
|
||
data class SelectableData<T : Any?>( | ||
override var data: T, | ||
override var isSelected: Boolean = false | ||
) : DataWrapperInterface<T>, | ||
SelectableDataInterface |
98 changes: 98 additions & 0 deletions
98
mad-base/src/main/java/ru/wearemad/mad_base/data_wrapper/selectable/SelectableExtension.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package ru.wearemad.mad_base.data_wrapper.selectable | ||
|
||
import ru.wearemad.mad_base.data_wrapper.DataWrapperInterface | ||
|
||
/** | ||
* Extension-функции для коллекции, использующая [SelectableData] | ||
* у [SelectableData] может быть выделен только один элемент | ||
* | ||
* Если необходимо множественное выделение -> смотри [CheckableData] | ||
*/ | ||
|
||
/** | ||
* Поставить выделение для <T>, используя предикат | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setSelected(predicate: (T) -> Boolean) | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface { | ||
setDeselected() | ||
findSingleAndApply(this, { predicate(it) }, { it.isSelected = true }) | ||
} | ||
|
||
/** | ||
* Поставить выделение для <T> | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setSelected(value: T) | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface { | ||
setSelected(predicate = { it == value }) | ||
} | ||
|
||
/** | ||
* @return возвращает выделенный объект <T>. | ||
*/ | ||
fun <T : Any?, E> Collection<E>.getSelectedData(): T | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface { | ||
return getSelectedDataNullable() | ||
?: throw IllegalStateException("ни одного выделенного элемента") | ||
} | ||
|
||
/** | ||
* @return возвращает выделенный объект <T>. Если ни один не выделен, то null | ||
*/ | ||
fun <T : Any?, E> Collection<E>.getSelectedDataNullable(): T? | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface { | ||
val foundedItems = this.filter { it.isSelected } | ||
if (foundedItems.size > 1) throw IllegalStateException("было найдено больше одного элемента") | ||
|
||
return if (foundedItems.isEmpty()) { | ||
null | ||
} else { | ||
foundedItems.first().data | ||
} | ||
} | ||
|
||
/** | ||
* убирает выделение у всей коллекции | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setDeselected() | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface { | ||
this.forEach { | ||
it.apply { | ||
this.isSelected = false | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* ставит выделение на первый элемент | ||
*/ | ||
fun <T : Any?, E> Collection<E>.setSelectedFirst() | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface { | ||
setDeselected() | ||
this.first().apply { | ||
this.isSelected = true | ||
} | ||
} | ||
|
||
/** | ||
* @return есть ли выделенный объект? | ||
*/ | ||
fun <T : Any?, E> Collection<E>.isAnySelected(): Boolean | ||
where E : DataWrapperInterface<T>, E : SelectableDataInterface = | ||
this.find { it.isSelected } != null | ||
|
||
/** | ||
* Найти объект (только один) в коллекции по findPredicate | ||
* и изменить в соответствии с applyConsumer | ||
*/ | ||
private fun <T : Any?, E : DataWrapperInterface<T>> findSingleAndApply( | ||
collection: Collection<E>, | ||
findPredicate: (T) -> Boolean, | ||
applyConsumer: (E) -> Unit | ||
) { | ||
val foundedItems = collection.filter { findPredicate(it.data) } | ||
if (foundedItems.size > 1) { | ||
throw IllegalStateException("было найдено больше одного элемента") | ||
} else { | ||
foundedItems.forEach(applyConsumer) | ||
} | ||
} |
Oops, something went wrong.