How can I finish the ActionMode when no selected item? - java

I want to finish actionmode when there is no item selected. I tried the code below but it didn't work.
bookAdapter.setOnLongClickListener(new RecyclerViewAdapter.OnLongClickListener() {
#Override
public void onLongClick() {
if(mActionMode != null) {
if(bookAdapter.getSelectedBooks().isEmpty()) {
mActionMode.finish();
}
return;
}
ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.delete_book_menu, menu);
buttonAddBook.setVisibility(View.INVISIBLE);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete_book :
for(Book book : bookAdapter.getSelectedBooks()) {
bookViewModel.delete(book);
}
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
for(Book book : bookAdapter.getBookList()) {
book.setSelected(false);
bookAdapter.notifyDataSetChanged();
}
buttonAddBook.setVisibility(View.VISIBLE);
}
};
mActionMode = startSupportActionMode(mActionModeCallback);
}
});
But when I change the code, for example when I try to finish the mode when 2 items are selected, it works. As follows:
if(mActionMode != null) {
if(bookAdapter.getSelectedBooks().size() == 2) {
mActionMode.finish();
}
return;
}
What am I doing wrong? I will be grateful if you could help me. Thanks in advance.

Did you use the recyclerview-selection?
I think this article would be useful.
https://proandroiddev.com/a-guide-to-recyclerview-selection-3ed9f2381504

Related

Disable EditText Clip board actions in Java/Kotlin

How I can disable text copy and paste action on password kind of fields in Java/Kotlin code?
If you are using API level 11 or above then you can stop copy,paste,cut and custom context menus from appearing by.
edittext.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
Returning false from onCreateActionMode(ActionMode, Menu) will prevent the action mode from being started(Select All, Cut, Copy and Paste actions).
fun disableClipboardAction(context : Context, editText: EditText){
try {
editText.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
val clipboard: ClipboardManager =
context.getSystemService(AppCompatActivity.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("text", "")
clipboard.setPrimaryClip(clipData)
}
}
editText.customSelectionActionModeCallback =
object : android.view.ActionMode.Callback {
override fun onCreateActionMode(
mode: android.view.ActionMode?,
menu: Menu?
): Boolean {
return false
}
override fun onPrepareActionMode(
mode: android.view.ActionMode?,
menu: Menu?
): Boolean {
return false
}
override fun onActionItemClicked(
mode: android.view.ActionMode?,
item: MenuItem?
): Boolean {
return false
}
override fun onDestroyActionMode(mode: android.view.ActionMode?) {
}
}
} catch (exception: Exception) {
exception.printStackTrace()
}
}

android/java: stop a method from returning value until a part of the method is executed

Hi I have a boolean return type method in my android app. How ever in my method I am calling an api but my method immidately returns the first boolean value without waiting for the api callback part of the code.. how do i solve this? please take a look at the following code:
public boolean validateForm() {
flag=true;
//---- THIS CODE DOES NOT EXECUTE.. THE RETURN STATEMENT IS DIRECTLY EXECUTED---
checkSourceCode(new BooleanCallBack() {
#Override
public void onSuccess(boolean result) {
validateCode = result;
if (!validateSourceCode(result)) {
flag = false;
}
if (flag) {
saveData();
}
}
});
//---- THE ABOVE CODE DOES NOT EXECUTE.. THE RETURN STATEMENT BELOW IS DIRECTLY EXECUTED
return flag; //This part is directly RETURNED without waiting for the above part of the code to execute
}
If i follow the answer given by Juan Felippo I have another issue to deal with then:
This is where I am calling the validateForm() method:
public boolean validate(int position) {
switch (position) {
case 0:
if (signUp_bgp_1.validateForm()) {
signUp_bgp_2.updateFields();
return true;
} else {
return false;
}
case 1:
signUp_bgp_2.validateForm(new BooleanCallBack() {
#Override
public void onSuccess(boolean result) {
return result; // I GET ERROR HERE "CANNOT RETURN A VALUE FROM A VOID RETURN TYPE"
}
});
case 2:
return signUp_bgp_3.validateForm();
HERE IS MY COMPLETE CODE:
*I call validateForm method on case 1
public boolean validate(int position) {
switch (position) {
case 0:
if (signUp_bgp_1.validateForm()) {
signUp_bgp_2.updateFields();
return true;
} else {
return false;
}
case 1:
signUp_bgp_2.validateForm(new BooleanCallBack() {
#Override
public void onSuccess(boolean result) {
bool =result; //CANNOT RETURN BOOLEAN HERE HOW TO HANDLE THIS?
}
});
case 2:
return signUp_bgp_3.validateForm();
case 3:
if (signUp_bgp_4.validateForm()) {
signUp_bgp_5.updateDetails();
return true;
} else {
return false;
}
case 4:
if (signUp_bgp_5.validateForm()) {
// signUp_bgp_5.updateDetails();
return true;
} else {
return false;
}
default:
return signUp_bgp_1.validateForm();
}
}
*My modified validateForm method according to Juan Fellipo's answer
public void validateForm(final BooleanCallBack mainCallback) {
flag=true;
checkSourceCode(new BooleanCallBack() {
#Override
public void onSuccess(boolean result) {
validateCode = result;
if (!validateSourceCode(result)) {
flag = false;
}
if (!accept_checkbox.isChecked()) {
Toast.makeText(getActivity().getBaseContext(), "Accept The Terms & Conditions To Proceed", Toast.LENGTH_LONG).show();
// accept_checkbox.requestFocus();
flag = false;
}
if (!validateAddress()) {
flag = false;
}
if (!validateCountry()) {
flag = false;
}
if (!validatelandmark()) {
flag = false;
}
if (!validateDistrict()) {
flag = false;
}
// if (!validateCity()) {
// flag = false;
// }
// if (!validateMobilenumber()) {
// flag = false;
// }
if (!validatePincode()) {
flag = false;
}
if (!validateFullfillment()) {
flag = false;
}
if (flag) {
saveData();
}
mainCallback.onSuccess(flag);
}
});
}
The api method is asynchronous while your method is synchronous. You can provide a callback when response is ready.
Try:
public void validateForm(final BooleanCallBack mainCallback) {
flag=true;
checkSourceCode(new BooleanCallBack() {
#Override
public void onSuccess(boolean result) {
validateCode = result;
if (!validateSourceCode(result)) {
flag = false;
}
if (flag) {
saveData();
}
mainCallback.onSuccess(flag)
}
});
}
and call the method:
someObject.validateForm(new BooleanCallBack() {
#Override
public void onSuccess(boolean result) {
//DO STH WITH RESULT
}
});
More info about sync/async and callbacks see :
What is a callback in java

Stop multiple ListCell Context Menus from Showing

I made a Custom ListView Cell so i can add a Context Menu but it keeps opening multiple context menus when you click more than once and the old ones just raise Exceptions when used.
Here is my SongCell class
public SongCell(ListView<Song> list, Playlist playlist) {
setAlignment(Pos.CENTER_LEFT);
ContextMenu listContextMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Remove");
MenuItem editID3Item = new MenuItem("Edit ID3");
MenuItem playNextItem = new MenuItem("Play Next");
removeItem.setOnAction((ActionEvent event) -> {
list.getItems().remove(getIndex());
});
editID3Item.setOnAction((ActionEvent event) -> {
Optional<Pair<String, String>> show = new FXID3Edit(getItem()).show();
});
playNextItem.setOnAction((ActionEvent event) -> {
Song song = getItem();
list.getItems().remove(song);
playlist.addSongRequest(new SongRequest(song, SongRequest.type.NEXT));
});
listContextMenu.getItems().add(removeItem);
listContextMenu.getItems().add(playNextItem);
listContextMenu.getItems().add(editID3Item);
setOnMousePressed(event -> {
if (event.getButton().equals(MouseButton.SECONDARY)) {
if (getItem() != null) {
if (getItem().equals(playlist.getSong())) {
playNextItem.setDisable(true);
removeItem.setDisable(true);
} else {
playNextItem.setDisable(false);
removeItem.setDisable(false);
}
listContextMenu.show(list, event.getScreenX(), event.getScreenY());
}
}
if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
playlist.setIndex(this.getIndex());
playlist.play();
}
event.consume();
});
}
#Override
protected void updateItem(Song item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
this.setText(item.toString());
} else {
this.setText("");
}
}
I also greatly appreciate help on my Coding Style
Instead of registering a mouse listener to show the context menu, use the built-in setContextMenu(...) property. I.e.:
public SongCell(ListView<Song> list, Playlist playlist) {
// ...
setOnMousePressed(event -> {
if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2) {
playlist.setIndex(this.getIndex());
playlist.play();
}
event.consume();
});
}
#Override
public void updateItem(Song item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
this.setText(item.toString());
this.setContextMenu(listContextMenu);
} else {
this.setText("");
this.setContextMenu(null);
}
}

Login/Logout with Action Bar/Menu Item

I have a single menu item that shows up in my action bar and I would like it to display "Log In" or "Log Out" depending on whether the user is logged in or logged out. However, I cannot get it to change text because in order to do so I have to call invalidateOptionsMenu() from inside my onOptionsSelected() method. I currently have a method that updates the text that should show, and this works fine, but in order to display that text I have to recreate the options menu.
Here is some of my code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
this.menu = menu;
updateMenuTitles();
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.login:
if (!loggedIn) {
Authentication();
} else {
loggedIn = false;
authentication = false;
updateMenuTitles();
Toast.makeText(getApplicationContext(),"Log Out Successful",Toast.LENGTH_SHORT).show();
}
break;
}
return super.onOptionsItemSelected(item);
}
private void updateMenuTitles() {
MenuItem bedMenuItem = menu.findItem(R.id.login);
if (loggedIn) {
bedMenuItem.setTitle("Log Out");
}else {
bedMenuItem.setTitle("Login");
}
}
As I'm using firebase, I'm checking if user is null or not. Based on that I'm adding which menu option I need.
Something like this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
if (firebaseUser!=null){
inflater.inflate(R.menu.landing_logout,menu);
}else {
inflater.inflate(R.menu.landing_login, menu);
}
return true;
}
I'd suggest to have two different buttons in your menu and switch their visibility according to the needs.
Something like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.login:
loggedIn = true;
Authentication();
updateMenuTitles();
break;
case R.id.logout:
loggedIn = false;
authentication = false;
updateMenuTitles();
Toast.makeText(getApplicationContext(),"Log Out Successful",Toast.LENGTH_SHORT).show();
break;
}
return super.onOptionsItemSelected(item);
}
private void updateMenuTitles() {
MenuItem loginMenuItem = menu.findItem(R.id.login);
MenuItem logoutMenuItem = menu.findItem(R.id.logout);
if (loggedIn) {
loginMenuItem.setVisibility(View.VISIBLE);
logoutMenuItem.setVisibility(View.GONE);
}else {
logoutMenuItem.setVisibility(View.VISIBLE);
loginMenuItem.setVisibility(View.GONE);
}
}

Changing a icon in ActionBar depending on a condition

I am updating a record in a SQLite database when the user presses an icon on the ActionBar. The information being updated is a flag that adds a record to a Favourites page.
PROBLEM
When the user adds or removes the record to favourites, I would like the icon in the ActionBar to change. I have a full star icon and a empty star icon.
The setIcon method displays the the full star icon if the record is a favourite, and a empty star icon if the record is not a favourite.
In the code below you will see I am using a boolean isInFavourite, which is true when String fav = "y".
When entering the Activity, the icon displayed is correct.
When the user clicks on the icon to invoke the onMenuItemClick() method, the record is successfully updated but the icon does not change.
I am unable to change the boolean isInFavourite when the record has been updated because Eclipse wants all the variables to be set as final
Can anyone help me change the icon to once the record has been updated.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
db = new DBHelper(this);
db.createDataBase();
db.openDataBase();
Bundle bundle = getIntent().getExtras();
final String rowid = bundle.getString("id");
final String fav = bundle.getString("fav");
//Boolean to check if record is a favourite
final boolean isInFavourite = fav.contentEquals("y");
menu.add("Add to Favourites")
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
String toggle;
String message;
//Logic to add or remove row from recording.
if (isInFavourite) {
toggle = "n";
message = "Recipe removed from Favourites";
} else {
toggle = "y";
message = "Recipe added to Favourites";
}
//Update favourite record in database
db.updateFavourite(rowid, toggle);
db.close();
Toast.makeText(getApplicationContext(), message,
Toast.LENGTH_LONG).show();
return true;
}
})
//Set icon depending on whether record is a favourite or not.
.setIcon(isInFavourite ? R.drawable.fav_true : R.drawable.fav_false)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return true;
}
Thanks to #dmon for the solution
SOLUTION
private DBHelper db = null;
public String fav = null;
public String rowid = null;
public boolean isFav;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Bundle bundle = getIntent().getExtras();
rowid = bundle.getString("id");
fav = bundle.getString("fav");
if (fav.contentEquals("y")) {
isFav = true;
} else {
isFav = false;
}
try {
db = new DBHelper(this);
db.createDataBase();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.menu_settings, menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem fave = menu.findItem(R.id.add);
MenuItem unfave = menu.findItem(R.id.remove);
fave.setVisible(isFav);
unfave.setVisible(!isFav);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
case R.id.add:
fav = "n";
isFav = false;
updateFav();
supportInvalidateOptionsMenu();
Toast("Removed from Favourites");
return true;
case R.id.remove:
fav = "y";
isFav = true;
updateFav();
supportInvalidateOptionsMenu();
Toast("Added to Favourites");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void updateFav (){
db.openDataBase();
db.updateFavourite(rowid, fav);
db.close();
}
XML File: res/menu/menu_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/add"
android:icon="#drawable/good"
android:showAsAction="always"
/>
<item
android:id="#+id/remove"
android:icon="#drawable/bad"
android:showAsAction="always"/>
The easiest way is to just provide two different buttons and hide/show them accordingly:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inf = new MenuInflater(this);
inf.inflate(R.menu.menu_xml, menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem fave = menu.findItem(R.id.favorite);
MenuItem unfave = menu.findItem(R.id.unfavorite);
fave.setVisible(!isFave);
unfave.setVisible(isFave);
return true;
}
Then you invalidate the options menu when the state has changed. Note that you have to have a global variable that has the current state of the item (where isFave is coming from)
invalidateOptionsMenu();
Make the isInFavourite variable a global field (declare it outside of the method, just in the class). Any local variables must be final for a scope below them to use them. However, if you make it global, and declare it above, it doesn't need to be final.

Categories