it.tidalwave.ui.android.app.AndroidViewHelper Maven / Gradle / Ivy
/***********************************************************************************************************************
*
* blueBill Mobile - Android - open source birding
* Copyright (C) 2009-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
***********************************************************************************************************************
*
* WWW: http://bluebill.tidalwave.it/mobile
* SCM: https://java.net/hg/bluebill-mobile~android-src
*
**********************************************************************************************************************/
package it.tidalwave.ui.android.app;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.util.Calendar;
import java.util.Date;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import it.tidalwave.util.thread.ThreadAssertions;
import it.tidalwave.util.thread.annotation.ThreadConfined;
import it.tidalwave.util.ui.UserNotification;
import it.tidalwave.util.ui.UserNotificationWithFeedback;
import it.tidalwave.util.ui.UserNotificationWithFeedback.Feedback;
import it.tidalwave.mobile.util.DateUpdater;
import it.tidalwave.mobile.util.ExceptionReporter;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.text.Html;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.DatePicker;
import android.widget.Toast;
import android.widget.TimePicker;
import it.tidalwave.mobile.android.ui.AndroidUtilities;
import lombok.RequiredArgsConstructor;
import static it.tidalwave.util.thread.ThreadType.*;
/***********************************************************************************************************************
*
* A facility class for some common UI-related tasks. In addition to providing a simplified API, this class also
* provides a consistent way to do some things (e.g. notifications, error notifications, etc...).
*
* While not explicitly noted, all methods can be called by any thread.
*
* @author Fabrizio Giudici
* @version $Id$
*
**********************************************************************************************************************/
@RequiredArgsConstructor
public class AndroidViewHelper
{
@Nonnull
private final View view;
/*******************************************************************************************************************
*
* Shows a light notification (by means of a {@link Toast}.
*
* @param notification the notification
*
******************************************************************************************************************/
@ThreadConfined(type=ANY)
public void showLightNotification (final @Nonnull UserNotification notification)
{
view.post(new Runnable()
{
public void run()
{
Toast.makeText(view.getContext(), notification.getText(), Toast.LENGTH_SHORT).show();
}
});
}
/*******************************************************************************************************************
*
* Shows a notification by means of a popup that must be dismissed by pressing a button.
*
* @param notification the object with the title and the message to show
*
******************************************************************************************************************/
@ThreadConfined(type=ANY)
public void showNotificationDialog (final @Nonnull UserNotificationWithFeedback notification)
{
view.post(new Runnable()
{
public void run()
{
showDialog(notification, false, android.R.drawable.ic_dialog_info);
}
});
}
/*******************************************************************************************************************
*
* Shows an error notification by means of a popup that must be dismissed by pressing a button.
*
* @param notification the object with the title and the message to show
*
******************************************************************************************************************/
@ThreadConfined(type=ANY)
public void showErrorDialog (final @Nonnull UserNotificationWithFeedback notification)
{
view.post(new Runnable()
{
public void run()
{
showDialog(notification, false, android.R.drawable.ic_dialog_alert);
}
});
}
/*******************************************************************************************************************
*
* Asks for a confirmation.
*
* @param notification the question with the feedback behaviour
*
******************************************************************************************************************/
@ThreadConfined(type=ANY)
public void showConfirmationDialog (final @Nonnull UserNotificationWithFeedback notification)
{
view.post(new Runnable()
{
public void run()
{
showDialog(notification, true, android.R.drawable.ic_dialog_info);
}
});
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@ThreadConfined(type=UI)
private void showDialog (final @CheckForNull UserNotificationWithFeedback notification,
final boolean canShowCancel,
final int icon)
{
ThreadAssertions.assertThread(UI);
final Builder builder = new AlertDialog.Builder(view.getContext());
builder.setIcon(icon)
.setTitle(notification.getCaption())
.setMessage(Html.fromHtml(notification.getText()))
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener()
{
@Override
public void onClick (final @Nonnull DialogInterface dialog, final int which)
{
try
{
notification.confirm();
}
catch (Throwable t)
{
ExceptionReporter.reportException(t);
}
}
});
// The positive button is always set as a dismiss button; the negative only if the positive behaviours exists
if (canShowCancel && overrides(notification.getFeedback(), "onConfirm") || overrides(notification.getFeedback(), "onCancel"))
{
builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener()
{
@Override
public void onClick (final @Nonnull DialogInterface dialog, final int which)
{
try
{
notification.cancel();
}
catch (Throwable t)
{
ExceptionReporter.reportException(t);
}
}
});
}
builder.show();
}
/*******************************************************************************************************************
*
*
*
******************************************************************************************************************/
@Nonnull @ThreadConfined(type=ANY)
public void openWebPage (final @Nonnull String url)
{
view.post(new Runnable()
{
public void run()
{
view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
});
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
protected static boolean overrides (final @Nonnull Feedback feedBack, final @Nonnull String methodName)
{
try
{
return !feedBack.getClass().getMethod(methodName).getDeclaringClass().equals(Feedback.class);
}
catch (NoSuchMethodException e)
{
throw new RuntimeException(e);
}
catch (SecurityException e)
{
throw new RuntimeException(e);
}
}
/*******************************************************************************************************************
*
* Expands the last group in an {@link ExpandableListView} and collapse all the previous others.
*
* @param expandableListView the {@code ExpandableListView} to work on
*
******************************************************************************************************************/
@ThreadConfined(type=ANY)
public void expandLastGroupAndCollapseOthers (final @Nonnull ExpandableListView expandableListView)
{
view.post(new Runnable() // TODO: move to AndroidUIHelper
{
public void run()
{
final int groupCount = expandableListView.getExpandableListAdapter().getGroupCount();
if (groupCount > 0)
{
for (int i = 0; i < groupCount - 1; i++)
{
expandableListView.collapseGroup(i);
}
// logger.info(">>>> expanding group %s...", groupCount - 1);
expandableListView.expandGroup(groupCount - 1);
}
}
});
}
/*******************************************************************************************************************
*
*
*
******************************************************************************************************************/
@Nonnull @ThreadConfined(type=UI)
public Dialog createTimePickerDialog (final @Nonnull ActionListener listener)
{
ThreadAssertions.assertThread(UI);
final Calendar calendar = Calendar.getInstance();
return new TimePickerDialog(view.getContext(), new OnTimeSetListener()
{
public void onTimeSet (final @Nonnull TimePicker timePicker, final int hour, final int minute)
{
final DateUpdater timeUpdater = new DateUpdater()
{
@Nonnull
public Date update (final @Nonnull Date date)
{
return AndroidUtilities.getDate(timePicker, date);
}
};
listener.actionPerformed(new ActionEvent(timeUpdater, ActionEvent.ACTION_PERFORMED, "actionPerformed"));
}
}, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true);
}
/*******************************************************************************************************************
*
*
*
******************************************************************************************************************/
@Nonnull @ThreadConfined(type=UI)
public Dialog createDatePickerDialog (final @Nonnull ActionListener listener)
{
ThreadAssertions.assertThread(UI);
final Calendar calendar = Calendar.getInstance();
return new DatePickerDialog(view.getContext(), new OnDateSetListener()
{
public void onDateSet (final @Nonnull DatePicker datePicker, final int year, final int month, final int day)
{
final DateUpdater dateUpdater = new DateUpdater()
{
@Nonnull
public Date update (final @Nonnull Date date)
{
return AndroidUtilities.getDate(datePicker, date);
}
};
listener.actionPerformed(new ActionEvent(dateUpdater, ActionEvent.ACTION_PERFORMED, "actionPerformed"));
}
}, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy