Skip to content

Commit

Permalink
feat(android): implement list and table editable and moveable functio…
Browse files Browse the repository at this point in the history
…nality
  • Loading branch information
garymathews authored and sgtcoolguy committed Jan 19, 2021
1 parent 52ae6e3 commit acb26f0
Show file tree
Hide file tree
Showing 16 changed files with 527 additions and 60 deletions.
10 changes: 10 additions & 0 deletions android/modules/ui/res/drawable/titanium_icon_delete.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#EEEEEE">
<path
android:fillColor="@android:color/black"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
import androidx.recyclerview.widget.RecyclerView;

import ti.modules.titanium.ui.widget.TiUITableView;
import ti.modules.titanium.ui.widget.listview.RecyclerViewProxy;
import ti.modules.titanium.ui.widget.tableview.TableViewAdapter;
import ti.modules.titanium.ui.widget.tableview.TiTableView;

@Kroll.proxy(
creatableInModule = UIModule.class,
propertyAccessors = {
TiC.PROPERTY_EDITABLE,
TiC.PROPERTY_EDITING,
TiC.PROPERTY_FILTER_ATTRIBUTE,
TiC.PROPERTY_FILTER_ANCHORED,
TiC.PROPERTY_FILTER_CASE_INSENSITIVE,
Expand All @@ -39,6 +42,8 @@
TiC.PROPERTY_SEPARATOR_STYLE,
TiC.PROPERTY_OVER_SCROLL_MODE,
TiC.PROPERTY_MIN_ROW_HEIGHT,
TiC.PROPERTY_MOVABLE,
TiC.PROPERTY_MOVING,
TiC.PROPERTY_HEADER_DIVIDERS_ENABLED,
TiC.PROPERTY_FOOTER_DIVIDERS_ENABLED,
TiC.PROPERTY_MAX_CLASSNAME,
Expand All @@ -47,7 +52,7 @@
TiC.PROPERTY_SHOW_VERTICAL_SCROLL_INDICATOR
}
)
public class TableViewProxy extends TiViewProxy
public class TableViewProxy extends RecyclerViewProxy
{
private static final String TAG = "TableViewProxy";

Expand Down Expand Up @@ -207,6 +212,49 @@ public TiUIView createView(Activity activity)
return new TiUITableView(this);
}

/**
* Delete a list item from specified adapter position.
*
* @param adapterIndex Index of item in adapter.
*/
public void swipeItem(int adapterIndex)
{
final TiTableView tableView = getTableView();

if (tableView != null) {
final TableViewRowProxy item = tableView.getAdapterItem(adapterIndex);
final TableViewSectionProxy section = (TableViewSectionProxy) item.getParent();

section.remove(item);
}
}

/**
* Move a list item from one position to another.
*
* @param fromAdapterIndex Index of item in adapter.
* @param toAdapterIndex Index of item in adapter.
*/
public void moveItem(int fromAdapterIndex, int toAdapterIndex)
{
final TiTableView tableView = getTableView();

if (tableView != null) {
final TableViewRowProxy fromItem = tableView.getAdapterItem(fromAdapterIndex);
final TableViewSectionProxy fromSection = (TableViewSectionProxy) fromItem.getParent();
final TableViewRowProxy toItem = tableView.getAdapterItem(toAdapterIndex);
final TableViewSectionProxy toSection = (TableViewSectionProxy) toItem.getParent();
final int toIndex = toItem.getIndexInSection();

fromSection.remove(fromItem);
toSection.add(toIndex, fromItem);

update();

fromItem.fireEvent(TiC.EVENT_MOVE, null);
}
}

/**
* Delete row from table.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
TiC.PROPERTY_HAS_CHECK,
TiC.PROPERTY_HAS_CHILD,
TiC.PROPERTY_HAS_DETAIL,
TiC.PROPERTY_EDITABLE,
TiC.PROPERTY_MOVABLE,
TiC.PROPERTY_CLASS_NAME,
TiC.PROPERTY_LAYOUT,
TiC.PROPERTY_LEFT_IMAGE,
Expand Down Expand Up @@ -350,6 +352,12 @@ public void onPropertyChanged(String name, Object value)
}
}

/**
* Process property set on proxy.
*
* @param name Property name.
* @param value Property value.
*/
private void processProperty(String name, Object value)
{
if (name.equals(TiC.PROPERTY_SELECTED_BACKGROUND_COLOR)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2020 by Axway, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
package ti.modules.titanium.ui.widget.listview;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import org.appcelerator.titanium.R;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.proxy.TiViewProxy;

public class ItemTouchHandler extends ItemTouchHelper.SimpleCallback
{
private TiRecyclerViewAdapter adapter;
private RecyclerViewProxy recyclerViewProxy;

private Drawable icon;
private final ColorDrawable background;

public ItemTouchHandler(TiRecyclerViewAdapter adapter, RecyclerViewProxy recyclerViewProxy)
{
super(0, 0);

this.adapter = adapter;
this.recyclerViewProxy = recyclerViewProxy;

this.icon = this.adapter.getContext().getResources().getDrawable(R.drawable.titanium_icon_delete);
this.background = new ColorDrawable(Color.RED);
}

/**
* Override drag direction flags.
*
* @param recyclerView Current RecyclerView.
* @param viewHolder Current Holder.
* @return Integer containing drag flags.
*/
@Override
public int getDragDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder)
{
final TiRecyclerViewHolder holder = (TiRecyclerViewHolder) viewHolder;
final TiViewProxy holderProxy = holder.getProxy();

String moveProperty = TiC.PROPERTY_MOVABLE;
if (holderProxy instanceof ListItemProxy) {

// Set to `canMove` property for ListItem.
moveProperty = TiC.PROPERTY_CAN_MOVE;
}

// Obtain default move value from RecyclerView proxy.
final boolean defaultValue = this.recyclerViewProxy.getProperties().optBoolean(moveProperty, false);

// Obtain move value from current holder proxy.
final boolean canMove = holderProxy.getProperties().optBoolean(moveProperty, defaultValue);

if ((isEditing() || isMoving()) && canMove) {
return ItemTouchHelper.UP | ItemTouchHelper.DOWN;
}
return 0;
}

/**
* Override swipe direction flags.
*
* @param recyclerView Current RecyclerView.
* @param viewHolder Current Holder.
* @return Integer containing swipe flags.
*/
@Override
public int getSwipeDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder)
{
final TiRecyclerViewHolder holder = (TiRecyclerViewHolder) viewHolder;
final TiViewProxy holderProxy = holder.getProxy();

String editProperty = TiC.PROPERTY_EDITABLE;
if (holderProxy instanceof ListItemProxy) {
editProperty = TiC.PROPERTY_CAN_EDIT;
}

// Obtain default edit value from RecyclerView proxy.
final boolean defaultValue = this.recyclerViewProxy.getProperties().optBoolean(editProperty, false);

// Obtain edit value from current holder proxy.
final boolean canSwipe = holderProxy.getProperties().optBoolean(editProperty, defaultValue);

if ((isEditing() || isMoving()) && canSwipe) {
return ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return 0;
}

/**
* Override movement flags to update our swipe and drag properties.
*
* @param recyclerView Current RecyclerView.
* @param viewHolder Current Holder.
* @return Integer containing movement flags.
*/
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder)
{
// Update drag and swipe directions.
setDefaultDragDirs(getDragDirs(recyclerView, viewHolder));
setDefaultSwipeDirs(getDragDirs(recyclerView, viewHolder));

return super.getMovementFlags(recyclerView, viewHolder);
}

/**
* Determine if `editing` mode is enabled for proxy.
*
* @return Boolean
*/
private boolean isEditing()
{
return this.recyclerViewProxy.getProperties().optBoolean(TiC.PROPERTY_EDITING, false);
}

/**
* Determine if `moving` mode is enabled for proxy.
*
* @return Boolean
*/
private boolean isMoving()
{
return this.recyclerViewProxy.getProperties().optBoolean(TiC.PROPERTY_MOVING, false);
}

/**
* Called when moving an item from one position to another.
*
* @param recyclerView Current RecyclerView.
* @param fromHolder Holder to move from current position.
* @param toHolder Holder at specified move position.
* @return
*/
@Override
public boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder fromHolder,
@NonNull RecyclerView.ViewHolder toHolder)
{
this.recyclerViewProxy.moveItem(fromHolder.getAdapterPosition(), toHolder.getAdapterPosition());
return true;
}

/**
* Called when swiping an item.
*
* @param viewHolder Holder being swiped.
* @param direction Direction of swipe.
*/
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction)
{
this.recyclerViewProxy.swipeItem(viewHolder.getAdapterPosition());
}

/**
* Override draw method to display background behind swipe-item.
*
* @param c Canvas
* @param recyclerView Current RecyclerView.
* @param viewHolder Holder to draw.
* @param dX X-axis offset.
* @param dY Y-axis offset.
* @param actionState Current action state.
* @param isCurrentlyActive Is currently active.
*/
@Override
public void onChildDraw(@NonNull Canvas c,
@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
float dX,
float dY,
int actionState,
boolean isCurrentlyActive)
{
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

if ((!isEditing() && !isMoving()) || dX == 0) {

// No swipe, do not render.
return;
}

final View view = viewHolder.itemView;

final int iconMargin = view.getHeight() - icon.getIntrinsicHeight();
final int iconTop = view.getTop() + (view.getHeight() - icon.getIntrinsicHeight()) / 2;
final int iconBottom = iconTop + icon.getIntrinsicHeight();
final int backgroundWidth = view.getMeasuredWidth() / 2;

if (dX > 0) {
final int iconLeft = view.getLeft() + iconMargin;
final int iconRight = view.getLeft() + iconMargin + icon.getIntrinsicWidth();
final int backgroundRight = view.getLeft() + ((int) dX) + backgroundWidth;

// Set bounds for right swipe.
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(view.getLeft(), view.getTop(), backgroundRight, view.getBottom());

} else if (dX < 0) {
final int iconLeft = view.getRight() - iconMargin - icon.getIntrinsicWidth();
final int iconRight = view.getRight() - iconMargin;
final int backgroundLeft = view.getRight() + ((int) dX) - backgroundWidth;

// Set bounds for left swipe.
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(backgroundLeft, view.getTop(), view.getRight(), view.getBottom());
}

background.draw(c);
icon.draw(c);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
creatableInModule = ti.modules.titanium.ui.UIModule.class,
propertyAccessors = {
TiC.PROPERTY_ACCESSORY_TYPE,
TiC.PROPERTY_CAN_EDIT,
TiC.PROPERTY_CAN_MOVE,
TiC.PROPERTY_ITEM_ID,
TiC.PROPERTY_SEARCHABLE_TEXT
}
Expand Down Expand Up @@ -533,6 +535,12 @@ public void onPropertyChanged(String name, Object value)
processProperty(name, value);
}

/**
* Process property set on proxy.
*
* @param name Property name.
* @param value Property value.
*/
private void processProperty(String name, Object value)
{
// Handle convenience properties for default template.
Expand Down
Loading

0 comments on commit acb26f0

Please sign in to comment.