All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.tidalwave.bluebill.mobile.android.observation.AndroidObservationUIController Maven / Gradle / Ivy

/***********************************************************************************************************************
 *
 * blueBill Mobile - open source birdwatching
 * ==========================================
 *
 * Copyright (C) 2009, 2010 by Tidalwave s.a.s. (http://www.tidalwave.it)
 * http://bluebill.tidalwave.it/mobile/
 *
 ***********************************************************************************************************************
 *
 * 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.
 *
 ***********************************************************************************************************************
 *
 * $Id: AndroidObservationUIController.java,v d808b6cb5d50 2010/07/10 21:19:33 fabrizio $
 *
 **********************************************************************************************************************/
package it.tidalwave.bluebill.mobile.android.observation;

import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import java.io.File;
import java.io.IOException;
import org.openide.util.NbBundle;
import it.tidalwave.util.logging.Logger;
import it.tidalwave.bluebill.observation.Observation;
import it.tidalwave.bluebill.observation.ObservationItem;
import it.tidalwave.bluebill.observation.ObservationManager;
import it.tidalwave.bluebill.observation.ObservationSet;
import it.tidalwave.mobile.ui.ActionEvent;
import it.tidalwave.mobile.ui.ActionListener;
import it.tidalwave.mobile.util.DateUpdater;
import it.tidalwave.bluebill.mobile.observation.DefaultObservationUIController;
import it.tidalwave.bluebill.mobile.observation.ObservationCountFormat;
import it.tidalwave.bluebill.mobile.observation.ObservationUI;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import it.tidalwave.netbeans.util.Locator;
import it.tidalwave.mobile.io.FileSystem;
import it.tidalwave.mobile.io.MasterFileSystem;
import it.tidalwave.bluebill.mobile.android.R;
import it.tidalwave.bluebill.mobile.android.taxonomy.factsheet.TaxonFactSheetControlFlow;
import it.tidalwave.bluebill.mobile.observation.share.Report;
import it.tidalwave.mobile.android.ui.AndroidUtilities;
import it.tidalwave.mobile.android.ui.ControlFlow;
import it.tidalwave.mobile.android.util.ProgressDialogController;
import java.io.FileOutputStream;

/***********************************************************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id: $
 *
 **********************************************************************************************************************/
public class AndroidObservationUIController extends DefaultObservationUIController
  {
    private static final String CLASS = AndroidObservationUIController.class.getName();
    private static final Logger logger = Logger.getLogger(CLASS);

    private static final String ATTACHMENTS_FILE_NAME = "spool/attachments.zip";

    private final ObservationListAdapter listAdapter;

    private final ObservationSet observationSet;

    private final ObservationUI ui;

    @Nonnull
    private Provider masterFileSystem = Locator.createProviderFor(MasterFileSystem.class);

    private Observation contextMenuObservation;

    private ObservationItem contextMenuObservationItem;
    
    private final ObservationCountFormat observationCountFormat = new ObservationCountFormat();

    private final ControlFlow controlFlow;

    private final static int PROGRESS_DIALOG = 171717;

    private final ProgressDialogController progressDialogController;

    /*******************************************************************************************************************
     *
     * FIXME: pull up, after using ActionListener and ActionEvent from the patched Swing stuff
     *
     ******************************************************************************************************************/
    private final ActionListener changeDateTimeListener = new ActionListener()
      {
        public void actionPerformed (final @Nonnull ActionEvent event)
          {
            final Date date = event.as(DateUpdater.class).update(contextMenuObservation.getDate());
            contextMenuObservation.change().at(date).apply();
          }
      };

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public AndroidObservationUIController (final @Nonnull ObservationUI ui)
      {
        super(ui);
        this.ui = ui;
        this.controlFlow = ControlFlow.forActivity((Activity)ui);
        this.progressDialogController = new ProgressDialogController((Activity)ui);

        observationSet = Locator.find(ObservationManager.class).findOrCreateObservationSetById(null);
        listAdapter = new ObservationListAdapter(observationSet);

        listAdapter.registerDataSetObserver(new DataSetObserver()
          {
            @Override
            public void onChanged()
              {
                ui.setFooterText(observationCountFormat.format(listAdapter.getGroupCount()));
              }
          });
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public void fireRefresh()
      {
        listAdapter.notifyDataSetChanged();
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    public ObservationListAdapter getListAdapter()
      {
        return listAdapter;
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Override
    public void startNewObservationSequence()
      {
        logger.info("startNewObservationSequence()");
        super.startNewObservationSequence();
        controlFlow.start(AddObservationControlFlow.class);
      }

    /*******************************************************************************************************************
     *
     *
     *
     ******************************************************************************************************************/
    @Override
    public void browseToFactSheet()
      {
        logger.info("browseToFactSheet()");
        super.browseToFactSheet();
        controlFlow.start(TaxonFactSheetControlFlow.class);
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Override
    protected void shareObservations (final @Nonnull Report report)
      {
        logger.info("shareObservations(%s)", report);

        // It seems that using the internal file system it doesn't work
        final FileSystem fileSystem = masterFileSystem.get().getExternalFileSystem();
//        final FileSystem fileSystem = masterFileSystem.get().getInternalFileSystem();
        
        final String pickAService = NbBundle.getMessage(AndroidObservationUIController.class, "pickAService");
        final String[] recipients = report.getRecipients().toArray(new String[0]);
        final Intent sendIntent = new Intent(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_EMAIL, recipients);
        sendIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, recipients);
        sendIntent.putExtra(Intent.EXTRA_SUBJECT, report.getSubject());
        sendIntent.putExtra(Intent.EXTRA_TEXT, report.getBody());
        sendIntent.setType(report.getMimeType());

        if (!report.getAttachments().isEmpty())
          {
            try
              {
                final File attachmentFile = fileSystem.getFile(ATTACHMENTS_FILE_NAME);
                saveAttachment(attachmentFile, report);
                sendIntent.setType("application/zip");
                sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(attachmentFile));
                sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                // FIXME: how to delete after sent? We could listen for Activity completion notification,
                // but the user might decide to store the document as draft.
              }
            catch (IOException e)
              {
                logger.warning("Error while preparing the report: %s", e);
                logger.throwing(CLASS, "shareObservations()", e);
              }
          }

        ((Activity)ui).startActivity(Intent.createChooser(sendIntent, pickAService));
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public boolean onContextItemSelected (final @Nonnull MenuItem item)
      {
        final ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo)item.getMenuInfo();
        final int type = ExpandableListView.getPackedPositionType(info.packedPosition);
        final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);

        switch (type)
          {
            case ExpandableListView.PACKED_POSITION_TYPE_CHILD:
                final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
                contextMenuObservationItem = listAdapter.getChild(groupPosition, childPosition);

                switch (item.getItemId())
                  {
                    case R.id.deleteObservationItem:
                      deleteObservationItem(contextMenuObservationItem);
                      break;
                  }

                return true;

            case ExpandableListView.PACKED_POSITION_TYPE_GROUP:
                contextMenuObservation = listAdapter.getGroup(groupPosition);

                switch (item.getItemId())
                  {
                    case R.id.editDate:
                    case R.id.editTime:
                      ui.getCommonUITasks().showDialog(item.getItemId());
                      break;
                  }

                return true;
          }

        return false;
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    protected Dialog onCreateDialog (final int id)
      {
        switch (id)
          {
            case R.id.editTime:
                return (Dialog)ui.getCommonUITasks().createTimePickerDialog(changeDateTimeListener);

            case R.id.editDate:
                return (Dialog)ui.getCommonUITasks().createDatePickerDialog(changeDateTimeListener);

            case R.id.share:
                return createShareDialog();

            case PROGRESS_DIALOG:
                return progressDialogController.getProgressDialog();
          }

        throw new RuntimeException("Unknown dialog id: " + id);
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    protected void onPrepareDialog (final int id, final @Nonnull Dialog dialog)
      {
        switch (id)
          {
            case R.id.editTime:
                AndroidUtilities.setDate((TimePickerDialog)dialog, contextMenuObservation.getDate());
                break;

            case R.id.editDate:
                AndroidUtilities.setDate((DatePickerDialog)dialog, contextMenuObservation.getDate());
                break;
          }
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    public Dialog createShareDialog()
      {
        String shareOptions = NbBundle.getMessage(AndroidObservationUIController.class, "shareOptions");
        String attachKML = NbBundle.getMessage(AndroidObservationUIController.class, "attachKML");
        String ok = NbBundle.getMessage(AndroidObservationUIController.class, "ok");
        String cancel = NbBundle.getMessage(AndroidObservationUIController.class, "cancel");

        final CharSequence[] items = { attachKML };
        final boolean[] o = new boolean[1];

        final AlertDialog.Builder builder = new AlertDialog.Builder((Activity)ui);
        builder.setTitle(shareOptions);
        builder.setMultiChoiceItems(items, o, new DialogInterface.OnMultiChoiceClickListener()
          {
            public void onClick (DialogInterface di, int i, boolean bln)
              {
                o[i] = bln;
              }
          });
          
        builder.setPositiveButton(ok, new DialogInterface.OnClickListener()
          {
            public void onClick (final @Nonnull DialogInterface di, final int i)
              {
                final ShareOptions options = new ShareOptions();
                options.setKmlAttachment(o[0]);
                options.setProgressListener(progressDialogController);

                final Thread thread = new Thread()
                  {
                    @Override
                    public void run()
                      {
                        shareObservations(options);
                      }
                  };

                thread.start();
                ((Activity)ui).showDialog(PROGRESS_DIALOG);
              }
          });
          
        builder.setNegativeButton(cancel, null);

        return builder.create();
      }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    private void saveAttachment (final @Nonnull File file, final @Nonnull Report report)
      throws IOException
      {
        final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file));

        for (final Report attachment : report.getAttachments())
          {
            logger.info(">>>> storing attachment: %s", attachment.getSubject());
            final ZipEntry zipEntry = new ZipEntry(attachment.getSubject());
            zos.putNextEntry(zipEntry);
            zos.write(attachment.getBody().getBytes());
            zos.closeEntry();
          }

        zos.finish();
        zos.flush();
        zos.close();
        
        logger.info(">>>> Attachment saved to %s, %d bytes", file, file.length());
      }
  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy