mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-21 05:09:00 +00:00
Add submenu for new add task button
This commit is contained in:
parent
a05ea079d1
commit
e657a2262d
16 changed files with 203 additions and 9 deletions
BIN
Habitica/res/drawable-hdpi/fab_submenu_background.png
Normal file
BIN
Habitica/res/drawable-hdpi/fab_submenu_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3 KiB |
BIN
Habitica/res/drawable-mdpi/fab_submenu_background.png
Normal file
BIN
Habitica/res/drawable-mdpi/fab_submenu_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Habitica/res/drawable-xhdpi/fab_submenu_background.png
Normal file
BIN
Habitica/res/drawable-xhdpi/fab_submenu_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
Habitica/res/drawable-xxhdpi/fab_submenu_background.png
Normal file
BIN
Habitica/res/drawable-xxhdpi/fab_submenu_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
BIN
Habitica/res/drawable-xxxhdpi/fab_submenu_background.png
Normal file
BIN
Habitica/res/drawable-xxxhdpi/fab_submenu_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
5
Habitica/res/drawable/bottom_submenu_label_bg.xml
Normal file
5
Habitica/res/drawable/bottom_submenu_label_bg.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="#d5c8ff" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
|
|
@ -123,7 +123,6 @@
|
|||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:layout_alignParentBottom="true"
|
||||
app:layout_behavior="com.habitrpg.android.habitica.ui.helpers.FloatingActionMenuBehavior"
|
||||
android:padding="0dp"
|
||||
android:layout_margin="0dp">
|
||||
<FrameLayout
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
tools:text="@string/habits"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:letterSpacing="0.05"
|
||||
android:fontFamily="@string/font_family_regular"
|
||||
android:paddingStart="@dimen/spacing_small"
|
||||
android:paddingEnd="@dimen/spacing_small"
|
||||
/>
|
||||
|
|
@ -31,6 +33,7 @@
|
|||
tools:text="@string/habits"
|
||||
android:layout_gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:letterSpacing="0.05"
|
||||
android:fontFamily="@string/font_family_medium"
|
||||
android:paddingStart="@dimen/spacing_small"
|
||||
android:paddingEnd="@dimen/spacing_small"
|
||||
|
|
|
|||
35
Habitica/res/layout/bottom_navigation_submenu.xml
Normal file
35
Habitica/res/layout/bottom_navigation_submenu.xml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="android.widget.RelativeLayout">
|
||||
<TextView
|
||||
android:id="@+id/title_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bottom_submenu_label_bg"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="@string/habit"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="10sp"
|
||||
android:letterSpacing="0.15"
|
||||
android:textColor="@color/brand_300"
|
||||
android:layout_marginStart="36dp"
|
||||
android:layout_alignStart="@id/icon_view"
|
||||
android:paddingStart="41dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:gravity="center_horizontal"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/icon_view"
|
||||
android:layout_width="73dp"
|
||||
android:layout_height="73dp"
|
||||
tools:src="@drawable/add_habit"
|
||||
android:scaleType="center"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="@drawable/fab_submenu_background"/>
|
||||
</merge>
|
||||
|
|
@ -8,10 +8,10 @@
|
|||
tools:parentTag="android.widget.RelativeLayout">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottom_navigation_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="62dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:gravity="center_vertical"
|
||||
android:clickable="true">
|
||||
<View
|
||||
|
|
@ -32,8 +32,7 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="62dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:gravity="center_vertical">
|
||||
<com.habitrpg.android.habitica.ui.views.navigation.BottomNavigationItem
|
||||
android:id="@+id/tab_habits"
|
||||
|
|
@ -50,7 +49,7 @@
|
|||
app:title="@string/dailies"
|
||||
app:iconDrawable="@drawable/icon_dailies_selected"/>
|
||||
<androidx.legacy.widget.Space
|
||||
android:layout_width="40dp"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content" />
|
||||
<com.habitrpg.android.habitica.ui.views.navigation.BottomNavigationItem
|
||||
android:id="@+id/tab_todos"
|
||||
|
|
@ -74,6 +73,15 @@
|
|||
android:layout_height="80dp"
|
||||
android:src="@drawable/fab_plus"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@drawable/fab_background" />
|
||||
android:layout_alignBottom="@id/bottom_navigation_background"
|
||||
android:layout_marginBottom="21dp"
|
||||
android:background="@drawable/fab_background"
|
||||
android:contentDescription="@string/new_task" />
|
||||
<LinearLayout
|
||||
android:id="@+id/submenu_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/add"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"/>
|
||||
</merge>
|
||||
|
|
@ -934,4 +934,5 @@
|
|||
<string name="switch_to_list_view">Switch to list view</string>
|
||||
<string name="switch_to_grid_view">Switch to grid view</string>
|
||||
<string name="confirm_deletion">Confirm deletion</string>
|
||||
<string name="new_task">New Task</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -44,5 +44,9 @@
|
|||
<key>supportEmail</key>
|
||||
<value>admin@habitica.com</value>
|
||||
</entry>
|
||||
<entry>
|
||||
<key>flipAddTaskBehaviour</key>
|
||||
<value>true</value>
|
||||
</entry>
|
||||
</defaultsMap>
|
||||
<!-- END xml_defaults -->
|
||||
|
|
@ -62,4 +62,8 @@ class AppConfigManager {
|
|||
fun enableLocalTaskScoring(): Boolean {
|
||||
return remoteConfig.getBoolean("enableLocalTaskScoring")
|
||||
}
|
||||
|
||||
fun flipAddTaskBehaviour(): Boolean {
|
||||
return remoteConfig.getBoolean("flipAddTaskBehaviour")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.habitrpg.android.habitica.components.UserComponent
|
|||
import com.habitrpg.android.habitica.data.TagRepository
|
||||
import com.habitrpg.android.habitica.events.TaskTappedEvent
|
||||
import com.habitrpg.android.habitica.helpers.AmplitudeManager
|
||||
import com.habitrpg.android.habitica.helpers.AppConfigManager
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.helpers.TaskFilterHelper
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
|
|
@ -30,6 +31,8 @@ class TasksFragment : BaseMainFragment() {
|
|||
lateinit var taskFilterHelper: TaskFilterHelper
|
||||
@Inject
|
||||
lateinit var tagRepository: TagRepository
|
||||
@Inject
|
||||
lateinit var appConfigManager: AppConfigManager
|
||||
|
||||
private var refreshItem: MenuItem? = null
|
||||
private var floatingMenu: FloatingActionMenu? = null
|
||||
|
|
@ -70,6 +73,7 @@ class TasksFragment : BaseMainFragment() {
|
|||
bottomNavigation?.onAddListener = {
|
||||
openNewTaskActivity(it)
|
||||
}
|
||||
bottomNavigation?.flipAddBehaviour = appConfigManager.flipAddTaskBehaviour()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package com.habitrpg.android.habitica.ui.views.navigation
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
|
||||
class BottomNavigationSubmenuItem @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : RelativeLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
val measuredTitleWidth: Int
|
||||
get() {
|
||||
titleView.measure(width, height)
|
||||
return titleView.measuredWidth
|
||||
}
|
||||
private val iconView: ImageView by bindView(R.id.icon_view)
|
||||
private val titleView: TextView by bindView(R.id.title_view)
|
||||
|
||||
var icon: Drawable? = null
|
||||
set(value) {
|
||||
field = value
|
||||
iconView.setImageDrawable(value)
|
||||
}
|
||||
var title: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
titleView.text = title
|
||||
}
|
||||
|
||||
init {
|
||||
inflate(R.layout.bottom_navigation_submenu, true)
|
||||
}
|
||||
|
||||
fun setTitleWidth(width: Int) {
|
||||
val layoutParams = titleView.layoutParams as? LayoutParams
|
||||
layoutParams?.width = width
|
||||
titleView.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,10 @@ package com.habitrpg.android.habitica.ui.views.navigation
|
|||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.children
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
|
|
@ -13,6 +16,8 @@ class HabiticaBottomNavigationView @JvmOverloads constructor(
|
|||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : RelativeLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
var flipAddBehaviour = true
|
||||
private var isShowingSubmenu: Boolean = false
|
||||
var selectedPosition: Int
|
||||
get() {
|
||||
return when (activeTaskType) {
|
||||
|
|
@ -44,6 +49,7 @@ class HabiticaBottomNavigationView @JvmOverloads constructor(
|
|||
private val todosTab: BottomNavigationItem by bindView(R.id.tab_todos)
|
||||
private val rewardsTab: BottomNavigationItem by bindView(R.id.tab_rewards)
|
||||
private val addButton: ImageButton by bindView(R.id.add)
|
||||
private val submenuWrapper: LinearLayout by bindView(R.id.submenu_wrapper)
|
||||
|
||||
init {
|
||||
inflate(R.layout.main_navigation_view, true)
|
||||
|
|
@ -52,11 +58,90 @@ class HabiticaBottomNavigationView @JvmOverloads constructor(
|
|||
todosTab.setOnClickListener { activeTaskType = Task.TYPE_TODO }
|
||||
rewardsTab.setOnClickListener { activeTaskType = Task.TYPE_REWARD }
|
||||
addButton.setOnClickListener {
|
||||
onAddListener?.invoke(activeTaskType)
|
||||
if (flipAddBehaviour) {
|
||||
if (isShowingSubmenu) {
|
||||
hideSubmenu()
|
||||
} else {
|
||||
onAddListener?.invoke(activeTaskType)
|
||||
}
|
||||
} else {
|
||||
showSubmenu()
|
||||
}
|
||||
}
|
||||
addButton.setOnLongClickListener {
|
||||
if (flipAddBehaviour) {
|
||||
showSubmenu()
|
||||
} else {
|
||||
onAddListener?.invoke(activeTaskType)
|
||||
}
|
||||
true
|
||||
}
|
||||
updateItemSelection()
|
||||
}
|
||||
|
||||
private fun showSubmenu() {
|
||||
isShowingSubmenu = true
|
||||
var pos = 4
|
||||
submenuWrapper.removeAllViews()
|
||||
for (taskType in listOf(Task.TYPE_HABIT, Task.TYPE_DAILY, Task.TYPE_TODO, Task.TYPE_REWARD)) {
|
||||
val view = BottomNavigationSubmenuItem(context)
|
||||
when (taskType) {
|
||||
Task.TYPE_HABIT -> {
|
||||
view.icon = context.getDrawable(R.drawable.add_habit)
|
||||
view.title = context.getString(R.string.habit)
|
||||
}
|
||||
Task.TYPE_DAILY -> {
|
||||
view.icon = context.getDrawable(R.drawable.add_daily)
|
||||
view.title = context.getString(R.string.daily)
|
||||
}
|
||||
Task.TYPE_TODO -> {
|
||||
view.icon = context.getDrawable(R.drawable.add_todo)
|
||||
view.title = context.getString(R.string.todo)
|
||||
}
|
||||
Task.TYPE_REWARD -> {
|
||||
view.icon = context.getDrawable(R.drawable.add_rewards)
|
||||
view.title = context.getString(R.string.reward)
|
||||
}
|
||||
}
|
||||
view.setOnClickListener {
|
||||
onAddListener?.invoke(taskType)
|
||||
hideSubmenu()
|
||||
}
|
||||
submenuWrapper.addView(view)
|
||||
view.alpha = 0f
|
||||
view.scaleY = 0.7f
|
||||
ViewCompat.animate(view).alpha(1f).setDuration(250.toLong()).startDelay = (100 * pos).toLong()
|
||||
ViewCompat.animate(view).scaleY(1f).setDuration(250.toLong()).startDelay = (100 * pos).toLong()
|
||||
pos -= 1
|
||||
}
|
||||
var widestWidth = 0
|
||||
for (view in submenuWrapper.children) {
|
||||
if (view is BottomNavigationSubmenuItem) {
|
||||
val width = view.measuredTitleWidth
|
||||
if (widestWidth < width) {
|
||||
widestWidth = width
|
||||
}
|
||||
}
|
||||
}
|
||||
for (view in submenuWrapper.children) {
|
||||
if (view is BottomNavigationSubmenuItem) {
|
||||
view.setTitleWidth(widestWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideSubmenu() {
|
||||
isShowingSubmenu = false
|
||||
var pos = 0
|
||||
for (view in submenuWrapper.children) {
|
||||
view.alpha = 1f
|
||||
view.scaleY = 1f
|
||||
ViewCompat.animate(view).alpha(0f).setDuration(200.toLong()).startDelay = (150 * pos).toLong()
|
||||
ViewCompat.animate(view).scaleY(0.7f).setDuration(250.toLong()).setStartDelay((100 * pos).toLong()).withEndAction { submenuWrapper.removeView(view) }
|
||||
pos += 1
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateItemSelection() {
|
||||
habitsTab.isActive = activeTaskType == Task.TYPE_HABIT
|
||||
dailiesTab.isActive = activeTaskType == Task.TYPE_DAILY
|
||||
|
|
|
|||
Loading…
Reference in a new issue