1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

Page-icon-picker widget (#260)

This commit is contained in:
Evgenii Kozlov 2020-03-02 21:56:10 +03:00 committed by GitHub
parent 5fb40987f2
commit e84e8fd6fc
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 921 additions and 5 deletions

View file

@ -53,4 +53,4 @@ task clean(type: Delete) {
task runUnitTests(dependsOn: [':app:testDebugUnitTest']) {
description 'Run all unit tests'
}
}

View file

@ -159,4 +159,8 @@ ext {
annotations: "androidx.room:room-compiler:$room_version",
roomTesting: "androidx.room:room-testing:$room_version"
]
libraryPageIconPicker = [
emojiJava: "com.vdurmont:emoji-java:5.1.1"
]
}

View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,57 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
def config = rootProject.extensions.getByName("ext")
compileSdkVersion compile_sdk
defaultConfig {
minSdkVersion config["min_sdk"]
targetSdkVersion config["target_sdk"]
versionCode config["version_code"]
versionName config["version_name"]
testInstrumentationRunner config["test_runner"]
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
def applicationDependencies = rootProject.ext.mainApplication
def unitTestDependencies = rootProject.ext.unitTesting
def lib = rootProject.ext.libraryPageIconPicker
implementation lib.emojiJava
implementation project(':core-utils')
implementation project(':core-ui')
implementation applicationDependencies.appcompat
implementation applicationDependencies.kotlin
implementation applicationDependencies.coroutines
implementation applicationDependencies.androidxCore
implementation applicationDependencies.design
implementation applicationDependencies.recyclerView
implementation applicationDependencies.constraintLayout
implementation applicationDependencies.timber
testImplementation unitTestDependencies.junit
testImplementation unitTestDependencies.kotlinTest
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.androidXTestCore
}

View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1 @@
<manifest package="com.agileburo.anytype" />

View file

@ -0,0 +1,53 @@
package com.agileburo.anytype.library_page_icon_picker_widget.model
import com.agileburo.anytype.core_ui.common.ViewType
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_CHOOSE_EMOJI
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_CATEGORY_HEADER
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_FILTER
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_ITEM
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_PICK_RANDOM_EMOJI
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_UPLOAD_PHOTO
sealed class PageIconPickerView : ViewType {
/**
* @property alias short name or convenient name for an emoji.
*/
data class Emoji(
val alias: String = "",
val unicode: String
) : PageIconPickerView() {
override fun getViewType() = HOLDER_EMOJI_ITEM
}
/**
* @property category emoji category
*/
data class GroupHeader(
val category: String
) : PageIconPickerView() {
override fun getViewType() = HOLDER_EMOJI_CATEGORY_HEADER
}
/**
* Emoji filter.
*/
object EmojiFilter : PageIconPickerView() {
override fun getViewType() = HOLDER_EMOJI_FILTER
}
/**
* User actions related to emoji picker feature.
*/
sealed class Action : PageIconPickerView() {
object UploadPhoto : Action() {
override fun getViewType() = HOLDER_UPLOAD_PHOTO
}
object PickRandomly : Action() {
override fun getViewType() = HOLDER_PICK_RANDOM_EMOJI
}
object ChooseEmoji : Action() {
override fun getViewType() = HOLDER_CHOOSE_EMOJI
}
}
}

View file

@ -0,0 +1,20 @@
package com.agileburo.anytype.library_page_icon_picker_widget.model
import androidx.recyclerview.widget.DiffUtil
class PageIconPickerViewDiffUtil(
private val old: List<PageIconPickerView>,
private val new: List<PageIconPickerView>
) : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return old[oldItemPosition] == new[newItemPosition]
}
override fun getOldListSize() = old.size
override fun getNewListSize() = new.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return old[oldItemPosition] == new[newItemPosition]
}
}

View file

@ -0,0 +1,95 @@
package com.agileburo.anytype.library_page_icon_picker_widget.ui
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.RecyclerView
import com.agileburo.anytype.R
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_CHOOSE_EMOJI
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_CATEGORY_HEADER
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_FILTER
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_ITEM
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_PICK_RANDOM_EMOJI
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_UPLOAD_PHOTO
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_filter.view.*
class PageIconPickerAdapter(
private var views: List<PageIconPickerView>,
private val onUploadPhotoClicked: () -> Unit,
private val onSetRandomEmojiClicked: () -> Unit,
private val onFilterQueryChanged: (String) -> Unit
) : RecyclerView.Adapter<PageIconPickerViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageIconPickerViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
HOLDER_UPLOAD_PHOTO -> PageIconPickerViewHolder.UploadPhoto(
view = inflater.inflate(
R.layout.item_page_icon_picker_upload_photo,
parent,
false
)
).apply {
itemView.setOnClickListener { onUploadPhotoClicked() }
}
HOLDER_PICK_RANDOM_EMOJI -> PageIconPickerViewHolder.PickRandom(
view = inflater.inflate(
R.layout.item_page_icon_picker_pick_emoji_randomly,
parent,
false
)
).apply {
itemView.setOnClickListener { onSetRandomEmojiClicked() }
}
HOLDER_CHOOSE_EMOJI -> PageIconPickerViewHolder.ChooseEmoji(
view = inflater.inflate(
R.layout.item_page_icon_picker_choose_emoji,
parent,
false
)
)
HOLDER_EMOJI_CATEGORY_HEADER -> PageIconPickerViewHolder.CategoryHeader(
view = inflater.inflate(
R.layout.item_page_icon_picker_emoji_category_header,
parent,
false
)
)
HOLDER_EMOJI_ITEM -> PageIconPickerViewHolder.EmojiItem(
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_page_icon_picker_emoji_item,
parent,
false
)
)
HOLDER_EMOJI_FILTER -> PageIconPickerViewHolder.EmojiFilter(
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_page_icon_picker_emoji_filter,
parent,
false
)
).apply {
itemView.filterInputField.doOnTextChanged { text, _, _, _ ->
onFilterQueryChanged(text.toString())
}
}
else -> throw IllegalStateException("Unexpected view type: $viewType")
}
}
override fun getItemCount(): Int = views.size
override fun getItemViewType(position: Int) = views[position].getViewType()
override fun onBindViewHolder(holder: PageIconPickerViewHolder, position: Int) {
when (holder) {
is PageIconPickerViewHolder.CategoryHeader -> {
holder.bind(views[position] as PageIconPickerView.GroupHeader)
}
is PageIconPickerViewHolder.EmojiItem -> {
holder.bind(views[position] as PageIconPickerView.Emoji)
}
}
}
}

View file

@ -0,0 +1,48 @@
package com.agileburo.anytype.library_page_icon_picker_widget.ui
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_category_header.view.*
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_item.view.*
sealed class PageIconPickerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
class UploadPhoto(view: View) : PageIconPickerViewHolder(view)
class PickRandom(view: View) : PageIconPickerViewHolder(view)
class ChooseEmoji(view: View) : PageIconPickerViewHolder(view)
class CategoryHeader(view: View) : PageIconPickerViewHolder(view) {
private val category = itemView.category
fun bind(item: PageIconPickerView.GroupHeader) {
category.text = item.category
}
}
class EmojiItem(view: View) : PageIconPickerViewHolder(view) {
private val emoji = itemView.emoji
fun bind(
item: PageIconPickerView.Emoji
) {
emoji.text = item.unicode
}
}
class EmojiFilter(view: View) : PageIconPickerViewHolder(view)
companion object {
const val HOLDER_UPLOAD_PHOTO = 0
const val HOLDER_PICK_RANDOM_EMOJI = 1
const val HOLDER_CHOOSE_EMOJI = 2
const val HOLDER_EMOJI_CATEGORY_HEADER = 3
const val HOLDER_EMOJI_ITEM = 4
const val HOLDER_EMOJI_FILTER = 5
}
}

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#2C2B27"
android:fillType="evenOdd"
android:pathData="M11.999,21C16.9696,21 20.999,16.9706 20.999,12C20.999,7.0294 16.9696,3 11.999,3C7.0285,3 2.999,7.0294 2.999,12C2.999,16.9706 7.0285,21 11.999,21ZM11.999,23C18.0742,23 22.999,18.0751 22.999,12C22.999,5.9249 18.0742,1 11.999,1C5.9239,1 0.999,5.9249 0.999,12C0.999,18.0751 5.9239,23 11.999,23Z" />
<path
android:fillColor="#2C2B27"
android:pathData="M16.999,9.5C16.999,10.3284 16.3275,11 15.499,11C14.6706,11 13.999,10.3284 13.999,9.5C13.999,8.6716 14.6706,8 15.499,8C16.3275,8 16.999,8.6716 16.999,9.5Z" />
<path
android:fillColor="#2C2B27"
android:pathData="M9.999,9.5C9.999,10.3284 9.3274,11 8.499,11C7.6706,11 6.999,10.3284 6.999,9.5C6.999,8.6716 7.6706,8 8.499,8C9.3274,8 9.999,8.6716 9.999,9.5Z" />
<path
android:fillColor="#2C2B27"
android:fillType="evenOdd"
android:pathData="M5.2889,14C6.1495,16.8915 8.828,19 11.9991,19C15.1701,19 17.8486,16.8915 18.7092,14H5.2889Z" />
</vector>

View file

@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#00000000"
android:pathData="M4.998,3L18.9981,3A2,2 0,0 1,20.9981 5L20.9981,19A2,2 0,0 1,18.9981 21L4.998,21A2,2 0,0 1,2.998 19L2.998,5A2,2 0,0 1,4.998 3z"
android:strokeWidth="2"
android:strokeColor="#2C2B27" />
<path
android:fillColor="#2C2B27"
android:pathData="M7.9981,8m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="#2C2B27"
android:pathData="M15.998,8m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="#2C2B27"
android:pathData="M7.9981,16m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="#2C2B27"
android:pathData="M15.998,16m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
<path
android:fillColor="#2C2B27"
android:pathData="M11.998,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
</vector>

View file

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#00000000"
android:pathData="M10.998,11m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"
android:strokeWidth="2"
android:strokeColor="#ACA996" />
<path
android:fillColor="#00000000"
android:pathData="M18.998,19L15.998,16"
android:strokeWidth="2"
android:strokeColor="#ACA996"
android:strokeLineCap="round" />
</vector>

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#2C2B27"
android:pathData="M10.999,3C10.999,2.4477 11.4467,2 11.999,2C12.5513,2 12.999,2.4477 12.999,3V17C12.999,17.5523 12.5513,18 11.999,18C11.4467,18 10.999,17.5523 10.999,17V3Z" />
<path
android:fillColor="#2C2B27"
android:pathData="M4.999,22C4.4467,22 3.999,21.5523 3.999,21C3.999,20.4477 4.4467,20 4.999,20H18.999C19.5513,20 19.999,20.4477 19.999,21C19.999,21.5523 19.5513,22 18.999,22H4.999Z" />
<path
android:fillColor="#2C2B27"
android:fillType="evenOdd"
android:pathData="M11.999,1.5858L19.7061,9.2929C20.0967,9.6834 20.0967,10.3166 19.7061,10.7071C19.3156,11.0977 18.6824,11.0977 18.2919,10.7071L11.999,4.4142L5.7061,10.7071C5.3156,11.0977 4.6824,11.0977 4.2919,10.7071C3.9014,10.3166 3.9014,9.6834 4.2919,9.2929L11.999,1.5858Z" />
</vector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#DFDDD0" />
<corners android:radius="6dp" />
</shape>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F3F2EC" />
<corners android:radius="8dp" />
</shape>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/divider_color" />
<TextView
style="@style/PageIconPickerActionTitleStyle"
android:text="@string/page_icon_picker_choose_emoji" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_upload_photo"
android:src="@drawable/ic_page_icon_picker_choose_emoji" />
</FrameLayout>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/graphik_medium"
android:textColor="@color/emoji_category_text_color"
android:textSize="13sp" />
</FrameLayout>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:background="@drawable/page_icon_picker_filter_background"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:background="@drawable/ic_page_icon_picker_search"
android:contentDescription="@string/content_description_loop_icon" />
<EditText
android:maxLines="1"
android:singleLine="true"
android:id="@+id/filterInputField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="9dp"
android:layout_marginTop="7dp"
android:layout_marginEnd="9dp"
android:layout_marginBottom="7dp"
android:background="@null"
android:fontFamily="@font/graphik_regular"
android:hint="@string/page_icon_picker_emoji_filter"
android:inputType="textNoSuggestions"
android:textSize="15sp" />
</LinearLayout>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/emoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/emoji_color"
android:textSize="22sp"
tools:text="🎢" />
</FrameLayout>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/divider_color" />
<TextView
style="@style/PageIconPickerActionTitleStyle"
android:text="@string/page_icon_picker_pick_emoji_randomly" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_upload_photo"
android:src="@drawable/ic_page_icon_picker_random_emoji" />
</FrameLayout>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/divider_color" />
<TextView
style="@style/PageIconPickerActionTitleStyle"
android:text="@string/page_icon_picker_upload_photo" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_upload_photo"
android:src="@drawable/ic_page_icon_picker_upload_photo" />
</FrameLayout>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EEAFAF">
<LinearLayout
android:id="@+id/sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/rectangle_debug_background"
android:orientation="vertical"
app:layout_behavior="@string/bottom_sheet_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="12dp">
<View
android:id="@+id/dragger"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:background="@drawable/page_icon_picker_dragger_background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:fontFamily="@font/graphik_semibold"
android:text="@string/page_icon"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="30dp"
android:text="@string/page_icon_picker_remove_text"
android:textColor="#ACA996"
android:textSize="17sp" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyler"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="100dp" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="divider_color">#DFDDD0</color>
<color name="emoji_category_text_color">#ACA996</color>
</resources>

View file

@ -0,0 +1,11 @@
<resources>
<string name="app_name">Page Icon Widget</string>
<string name="page_icon_picker_upload_photo">Upload photo</string>
<string name="content_description_upload_photo">Upload photo image</string>
<string name="page_icon_picker_pick_emoji_randomly">Pick emoji randomly</string>
<string name="page_icon_picker_choose_emoji">Choose emoji</string>
<string name="page_icon_picker_emoji_filter">Filter</string>
<string name="content_description_loop_icon">Loop icon</string>
<string name="page_icon">Page icon</string>
<string name="page_icon_picker_remove_text">Remove</string>
</resources>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="PageIconPickerActionTitleStyle">
<item name="android:layout_gravity">center_vertical</item>
<item name="android:textColor">@color/black</item>
<item name="android:textSize">15sp</item>
<item name="android:fontFamily">@font/graphik_medium</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
</resources>

View file

@ -0,0 +1,159 @@
package com.agileburo.anytype.library_page_icon_picker_widget
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerViewDiffUtil
import org.junit.Test
import kotlin.test.assertEquals
class PageIconPickerViewDiffUtilTest {
@Test
fun `two emoji-filter items should be considered the same`() {
val old = listOf(
PageIconPickerView.EmojiFilter
)
val new = listOf(
PageIconPickerView.EmojiFilter
)
val util = PageIconPickerViewDiffUtil(
old = old,
new = new
)
val result = util.areItemsTheSame(0, 0)
assertEquals(
expected = true,
actual = result
)
}
@Test
fun `two upload-photo-action items should be considered the same`() {
val old = listOf(
PageIconPickerView.Action.UploadPhoto
)
val new = listOf(
PageIconPickerView.Action.UploadPhoto
)
val util = PageIconPickerViewDiffUtil(
old = old,
new = new
)
val result = util.areItemsTheSame(0, 0)
assertEquals(
expected = true,
actual = result
)
}
@Test
fun `two choose-emoji-action items should be considered the same`() {
val old = listOf(
PageIconPickerView.Action.ChooseEmoji
)
val new = listOf(
PageIconPickerView.Action.ChooseEmoji
)
val util = PageIconPickerViewDiffUtil(
old = old,
new = new
)
val result = util.areItemsTheSame(0, 0)
assertEquals(
expected = true,
actual = result
)
}
@Test
fun `two pick-random-emoji-action items should be considered the same`() {
val old = listOf(
PageIconPickerView.Action.PickRandomly
)
val new = listOf(
PageIconPickerView.Action.PickRandomly
)
val util = PageIconPickerViewDiffUtil(
old = old,
new = new
)
val result = util.areItemsTheSame(0, 0)
assertEquals(
expected = true,
actual = result
)
}
@Test
fun `two emoji items should be considered the same`() {
val old = listOf(
PageIconPickerView.Emoji(
alias = "grining",
unicode = "U+13131"
)
)
val new = listOf(
PageIconPickerView.Emoji(
alias = "grining",
unicode = "U+13131"
)
)
val util = PageIconPickerViewDiffUtil(
old = old,
new = new
)
val result = util.areItemsTheSame(0, 0)
assertEquals(
expected = true,
actual = result
)
}
@Test
fun `two emoji items should be considered different`() {
val old = listOf(
PageIconPickerView.Emoji(
alias = "smile",
unicode = "U+13131"
)
)
val new = listOf(
PageIconPickerView.Emoji(
alias = "grining",
unicode = "U+13131"
)
)
val util = PageIconPickerViewDiffUtil(
old = old,
new = new
)
val result = util.areItemsTheSame(0, 0)
assertEquals(
expected = false,
actual = result
)
}
}

View file

@ -32,8 +32,11 @@ android {
dependencies {
implementation 'com.vdurmont:emoji-java:5.1.1'
implementation project(':core-utils')
implementation project(':core-ui')
implementation project(':library-page-icon-picker-widget')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

View file

@ -1,18 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.agileburo.anytype.sample">
<application
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity" />
<activity android:name=".PageIconPickerSampleActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

View file

@ -0,0 +1,65 @@
package com.agileburo.anytype.sample
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerAdapter
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder
import com.vdurmont.emoji.EmojiManager
import kotlinx.android.synthetic.main.sample_page_icon_picker_activity.*
class PageIconPickerSampleActivity : AppCompatActivity(R.layout.sample_page_icon_picker_activity) {
private val emojis by lazy {
EmojiManager
.getAll()
.map { emoji ->
PageIconPickerView.Emoji(
unicode = emoji.unicode
)
}
}
private val pageIconPickerAdapter = PageIconPickerAdapter(
views = listOf(
PageIconPickerView.Action.UploadPhoto,
PageIconPickerView.Action.PickRandomly,
PageIconPickerView.Action.ChooseEmoji,
PageIconPickerView.EmojiFilter
) + emojis,
onUploadPhotoClicked = {},
onSetRandomEmojiClicked = {},
onFilterQueryChanged = {}
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
recyler.apply {
setItemViewCacheSize(100)
setHasFixedSize(true)
layoutManager = GridLayoutManager(context, PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT).apply {
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) =
when (val type = pageIconPickerAdapter.getItemViewType(position)) {
PageIconPickerViewHolder.HOLDER_UPLOAD_PHOTO -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
PageIconPickerViewHolder.HOLDER_CHOOSE_EMOJI -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
PageIconPickerViewHolder.HOLDER_PICK_RANDOM_EMOJI -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
PageIconPickerViewHolder.HOLDER_EMOJI_CATEGORY_HEADER -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
PageIconPickerViewHolder.HOLDER_EMOJI_FILTER -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
PageIconPickerViewHolder.HOLDER_EMOJI_ITEM -> 1
else -> throw IllegalStateException("Unexpected view type: $type")
}
}
}
adapter = pageIconPickerAdapter.apply {
setHasStableIds(true)
}
}
}
companion object {
const val PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT = 8
}
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#DFDDD0" />
<corners android:radius="6dp" />
</shape>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EEAFAF">
<LinearLayout
android:id="@+id/sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/rectangle_debug_background"
android:orientation="vertical"
app:layout_behavior="@string/bottom_sheet_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="12dp">
<View
android:id="@+id/dragger"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:background="@drawable/page_icon_picker_dragger_background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:fontFamily="@font/graphik_semibold"
android:text="Page icon"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="30dp"
android:text="Remove"
android:textColor="#ACA996"
android:textSize="17sp" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyler"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="100dp" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -8,4 +8,5 @@ include ':app',
':data',
':presentation',
':core-ui',
':library-kanban-widget'
':library-kanban-widget',
':library-page-icon-picker-widget'