Unverified Commit 96ff61f0 authored by 0xDEVARSH's avatar 0xDEVARSH Committed by GitHub

Add "RemoveItemAtIndex" block to ListView (#2789)


---------
Co-authored-by: default avatarEvan W. Patton <ewpatton@mit.edu>
parent bfcc1565
......@@ -1430,6 +1430,10 @@ public final class YoungAndroidFormUpgrader {
// Added ...
srcCompVersion = 6;
}
if (srcCompVersion < 7) {
// Added RemoveItemAtIndex method
srcCompVersion = 7;
}
return srcCompVersion;
}
......
......@@ -2413,7 +2413,10 @@ Blockly.Versioning.AllUpgradeMaps =
5: "noUpgrade",
// AI2:
// - Added ...
6: "noUpgrade"
6: "noUpgrade",
// AI2:
// - Added RemoveItemAtList method
7: "noUpgrade"
}, // End ListView upgraders
......
......@@ -128,6 +128,9 @@ import Foundation
// ImageBot Errors
case ERROR_IMAGEBOT_ERROR = 4300
// ListView Errors
case ERROR_LISTVIEW_INDEX_OUT_OF_BOUNDS = 4601
// CloudDB Errors
case ERROR_EMPTY_CLOUDDB_PROPERTY = 104001
case ERROR_CLOUDDB_JSON_MALFORMED = 104002
......@@ -353,6 +356,10 @@ import Foundation
case .ERROR_IMAGEBOT_ERROR:
return "Error from the ImageBot code: %d %@"
// ListView Errors
case .ERROR_LISTVIEW_INDEX_OUT_OF_BOUNDS:
return "The index %d is out of bounds for the list view."
// iOS Specific Errors
case .ERROR_IOS_INSTALLING_URLS_NOT_SUPPORTED:
return "Installing packages from URLs is not supported on iOS"
......
......@@ -332,6 +332,23 @@ open class ListView: ViewComponent, AbstractMethodsForViewComponent,
}
}
// MARK: Methods
@objc open func RemoveItemAtIndex(_ index: Int32) {
if index < 1 || index > max(_listData.count, _elements.count) {
_container?.form?.dispatchErrorOccurredEvent(self, "RemoveItemAtIndex",
ErrorMessage.ERROR_LISTVIEW_INDEX_OUT_OF_BOUNDS, index)
return
}
if _listData.count >= index {
_listData.remove(at: Int(index - 1))
}
if _elements.count >= index {
_elements.remove(at: Int(index - 1))
}
_view.reloadData()
}
// MARK: Events
@objc open func AfterPicking() {
......
......@@ -584,6 +584,7 @@ public class YaVersion {
// - TEXTTOSPEEECH_COMPONENT_VERSION was incremented to 6
// - TINYDB_COMPONENT_VERSION was incremented to 3
// For YOUNG_ANDROID_VERSION 225:
// - LISTVIEW_COMPONENT_VERSION was incremented to 7
// - WEB_COMPONENT_VERSION was incremented to 9
public static final int YOUNG_ANDROID_VERSION = 225;
......@@ -1145,7 +1146,9 @@ public class YaVersion {
// - Added SelectionColor Property
// For LISTVIEW_COMPONENT_VERSION 6:
// - Added ...
public static final int LISTVIEW_COMPONENT_VERSION = 6;
// For LISTVIEW_COMPONENT_VERSION 7:
// - Added RemoveItemAtIndex method
public static final int LISTVIEW_COMPONENT_VERSION = 7;
// For LOCATIONSENSOR_COMPONENT_VERSION 2:
// - The TimeInterval and DistanceInterval properties were added.
......
......@@ -143,7 +143,7 @@ public class ListAdapterWithRecyclerView
Arrays.fill(isVisible, Boolean.TRUE);
}
public ListAdapterWithRecyclerView(ComponentContainer container, YailList stringItems, int textMainColor, float textMainSize, String textMainFont, int backgroundColor, int selectionColor) {
public ListAdapterWithRecyclerView(ComponentContainer container, List<String> stringItems, int textMainColor, float textMainSize, String textMainFont, int backgroundColor, int selectionColor) {
// Legacy Support
this.container = container;
this.textMainSize = textMainSize;
......@@ -167,8 +167,7 @@ public class ListAdapterWithRecyclerView
// Build the list of strings into a list of dictionaries
this.items = new ArrayList<>();
// YailList is 1-indexed
for(int i = 1; i <= stringItems.size(); ++i) {
String itemString = YailList.YailListElementToString(stringItems.get(i));
for(String itemString : stringItems) {
YailDictionary itemDict = new YailDictionary();
itemDict.put(Component.LISTVIEW_KEY_MAIN_TEXT, itemString);
this.items.add(itemDict);
......
......@@ -80,7 +80,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
private RecyclerView recyclerView;
private ListAdapterWithRecyclerView listAdapterWithRecyclerView;
private YailList stringItems;
private List<String> stringItems;
private List<YailDictionary> dictItems;
private int selectionIndex;
private String selection;
......@@ -122,7 +122,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
super(container);
this.container = container;
stringItems = YailList.makeEmptyList();
stringItems = new ArrayList<>();
dictItems = new ArrayList<>();
linearLayout = new LinearLayout(container.$context());
......@@ -286,7 +286,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
category = PropertyCategory.BEHAVIOR)
public void Elements(YailList itemsList) {
dictItems.clear();
stringItems = YailList.makeEmptyList();
stringItems = new ArrayList<>();
if (itemsList.size() > 0) {
Object firstitem = itemsList.getObject(0);
// Check to see if this is a list of strings (backward compatibility) or a list of Dictionaries
......@@ -307,7 +307,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
}
} else {
// Support legacy single-string ListViews
stringItems = ElementsUtil.elements(itemsList, "Listview");
stringItems = ElementsUtil.elementsStrings(itemsList, "ListView");
}
}
setAdapterData();
......@@ -324,7 +324,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
if (dictItems.size() > 0) {
return YailList.makeList(dictItems);
} else {
return stringItems;
return ElementsUtil.makeYailListFromList(stringItems);
}
}
......@@ -340,7 +340,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
"such as: Cheese,Fruit,Bacon,Radish. Each word before the comma will be an element in the " +
"list.", category = PropertyCategory.BEHAVIOR)
public void ElementsFromString(String itemstring) {
stringItems = ElementsUtil.elementsFromString(itemstring);
stringItems = ElementsUtil.elementsListFromString(itemstring);
setAdapterData();
}
......@@ -409,13 +409,13 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
category = PropertyCategory.BEHAVIOR)
public void SelectionIndex(int index) {
if (!dictItems.isEmpty()) {
selectionIndex = ElementsUtil.selectionIndex(index, YailList.makeList(dictItems));
selectionIndex = ElementsUtil.selectionIndexInStringList(index, YailList.makeList(dictItems));
selection = dictItems.get(selectionIndex - 1).get(Component.LISTVIEW_KEY_MAIN_TEXT).toString();
selectionDetailText = ElementsUtil.toStringEmptyIfNull(dictItems.get(selectionIndex - 1).get(Component.LISTVIEW_KEY_DESCRIPTION).toString());
} else {
selectionIndex = ElementsUtil.selectionIndex(index, stringItems);
selectionIndex = ElementsUtil.selectionIndexInStringList(index, stringItems);
// Now, we need to change Selection to correspond to SelectionIndex.
selection = ElementsUtil.setSelectionFromIndex(index, stringItems);
selection = ElementsUtil.setSelectionFromIndexInStringList(index, stringItems);
selectionDetailText = "";
}
if (listAdapterWithRecyclerView != null) {
......@@ -423,6 +423,26 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
}
}
/**
* Removes Item from list at a given index
*/
@SimpleFunction(
description = "Removes Item from list at a given index")
public void RemoveItemAtIndex(int index) {
if (index < 1 || index > Math.max(dictItems.size(), stringItems.size())) {
container.$form().dispatchErrorOccurredEvent(this, "RemoveItemAtIndex",
ErrorMessages.ERROR_LISTVIEW_INDEX_OUT_OF_BOUNDS, index);
return;
}
if (dictItems.size() >= index) {
dictItems.remove(index - 1);
}
if (stringItems.size() >= index) {
stringItems.remove(index - 1);
}
setAdapterData();
}
/**
* Returns the text in the `ListView` at the position of {@link #SelectionIndex(int)}.
*/
......@@ -456,7 +476,7 @@ public final class ListView extends AndroidViewComponent implements AdapterView.
selectionIndex = 0;
}
} else {
selectionIndex = ElementsUtil.setSelectedIndexFromValue(value, stringItems);
selectionIndex = ElementsUtil.setSelectedIndexFromValueInStringList(value, stringItems);
}
SelectionIndex(selectionIndex);
}
......
......@@ -10,6 +10,8 @@ import com.google.appinventor.components.runtime.errors.YailRuntimeError;
import org.json.JSONObject;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
/**
* Utilities for Components that display a number of options on Screen such as ListPicker,
......@@ -26,6 +28,81 @@ public class ElementsUtil {
return items;
}
/** Check a Yail list of items to verify that they are all strings
*
* @param itemList
* @param componentName
* @return the original list
*/
public static List<String> elementsStrings(YailList itemList, String componentName){
Object[] objects = itemList.toStringArray();
for (int i = 0; i < objects.length; i++) {
if (!(objects[i] instanceof String)) {
throw new YailRuntimeError("Items passed to " + componentName + " must be Strings",
"Error");
}
}
// this is not changing itemlist. it's just checking that the items are strings
String[] strings = (String[]) objects;
List<String> ans = new ArrayList<>(Arrays.asList(strings));
return ans;
}
/**
* Returns a list of string from a comma-separated string
* @param itemString
* @return items
*/
public static List<String> elementsListFromString(String itemString){
List<String> items;
if (itemString.length() > 0) {
String[] words = itemString.split(" *, *");
items = new ArrayList<>(Arrays.asList(words));
} else {
items = new ArrayList();
}
return items;
}
/**
* Converts a List of string to YailList
* @param stringItems
* @return YailList
*/
public static YailList makeYailListFromList(List<String> stringItems) {
if (stringItems == null || stringItems.size() == 0) return YailList.makeEmptyList();
return YailList.makeList(stringItems);
}
public static int selectionIndexInStringList(int index, List<String> items){
if (index < 0 || index >= items.size()) {
return 0;
} else {
return index;
}
}
public static String setSelectionFromIndexInStringList(int index, List<String> items){
if (index < 0 || index >= items.size()) {
return "";
}
return items.get(index);
}
public static int setSelectedIndexFromValueInStringList(String value, List<String> items){
// Now, we need to change SelectionIndex to correspond to Selection.
// If multiple Selections have the same SelectionIndex, use the first.
// If none do, arbitrarily set the SelectionIndex to its default value
// of 0.
for (int i = 0; i < items.size(); i++) {
// The comparison is case-sensitive to be consistent with yail-equal?.
if (items.get(i).equals(value)) {
return i;
}
}
return 0;
}
/** Check a Yail list of items to verify that they are all strings and
*
* @param itemList
......
......@@ -310,7 +310,10 @@ public final class ErrorMessages {
// FilePicker Errors
public static final int ERROR_FILEPICKER_NO_URI_RETURNED = 4501;
// Start the next group of errors at 4600
// ListView Errors
public static final int ERROR_LISTVIEW_INDEX_OUT_OF_BOUNDS = 4601;
// Start the next group of errors at 4700
// Mapping of error numbers to error message format strings.
private static final Map<Integer, String> errorMessages;
......@@ -756,6 +759,10 @@ public final class ErrorMessages {
// FilePicker Errors
errorMessages.put(ERROR_FILEPICKER_NO_URI_RETURNED, "No URI returned to FilePicker");
// ListView Errors
errorMessages.put(ERROR_LISTVIEW_INDEX_OUT_OF_BOUNDS,
"The index %d is out of bounds for the list view.");
}
private ErrorMessages() {
......
......@@ -740,6 +740,8 @@ Valid values for the month field are 1-12 and 1-31 for the day field.</dd>
<dd>Get the Main Text of a ListView element.</dd>
<dt id="ListView.Refresh" class="method"><i></i> Refresh()</dt>
<dd>Reload the ListView to reflect any changes in the data.</dd>
<dt id="ListView.RemoveItemAtIndex" class="method"><i></i> RemoveItemAtIndex(<em class="number">index</em>)</dt>
<dd>Removes Item from list at a given index</dd>
</dl>
<h2 id="Notifier">Notifier</h2>
......
......@@ -787,6 +787,9 @@ This is a visible component that displays a list of text and image elements in y
{:id="ListView.Refresh" class="method"} <i/> Refresh()
: Reload the ListView to reflect any changes in the data.
{:id="ListView.RemoveItemAtIndex" class="method"} <i/> RemoveItemAtIndex(*index*{:.number})
: Removes Item from list at a given index
## Notifier {#Notifier}
The Notifier component displays alert messages and creates Android log entries through
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment