/* ApicAday - Everyday.. is different, your mood, your life. Copyright (c) 2010 Oliver Selinger <oliver.selinger@autburst.com>, Michael Greifeneder <michael.greifeneder@autburst.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.autburst.picture; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import org.apache.commons.codec.binary.Base64; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.format.DateFormat; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.CompoundButton.OnCheckedChangeListener; public class MainActivity extends Activity implements OnItemClickListener, OnCheckedChangeListener { private static final String TAG = MainActivity.class.getSimpleName(); static final int DIALOG_CREATE_ALBUM_ID = 0; static final int DIALOG_SHOW_ALBUM_ID = 1; static final int DIALOG_CREATE_ALBUM_INPUT_ERROR = 2; static final int DIALOG_ALBUM_NAME_ALREADY_EXIST = 3; private ListView albumsList; private ArrayAdapter<String> adapter; private LayoutInflater inflater; private ImageButton deleteButton; private ImageButton openButton; private List<Button> openAlbumButtons = new ArrayList<Button>(); private List<CheckBox> deleteAlbumCheckBoxes = new ArrayList<CheckBox>(); private LinearLayout deletionPanel; private Button cancelDeletion; private Button deleteCheckedAlbums; private List<Integer> checkedAlbums = new ArrayList<Integer>(); // gui status for disabling or enabling the delete and open buttons private boolean openButtonsVisible = false; private boolean deleteCheckboxesVisible = false; private MainActivityController controller; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "------ onCreate MainActivity ------"); setContentView(R.layout.main); albumsList = (ListView) findViewById(R.id.albumList); inflater = getLayoutInflater(); List<String> albumsAsList = Utilities.getAlbumsAsList(); adapter = new AlbumAdapter(inflater, this, R.layout.row, albumsAsList); adapter.sort(Utilities.getAlbumNameComparator()); albumsList.setAdapter(adapter); albumsList.setOnItemClickListener(this); cancelDeletion = (Button) findViewById(R.id.cancelDeletion); cancelDeletion.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { hideDeletionPanelAndCB(MainActivityController.DELETE_BUTTON_PRESSED); } }); deleteCheckedAlbums = (Button) findViewById(R.id.deleteCheckedAlbums); deleteCheckedAlbums.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { List<String> albums = Utilities.getAlbumsAsList(); Collections.sort(albums, Utilities.getAlbumNameComparator()); for (int i = 0; i < checkedAlbums.size(); i++) { // get checked rows int rowIndex = checkedAlbums.get(i); String albumName = albums.get(rowIndex); Log.d(TAG, "delete album: " + albumName + " at rowIndex: " + rowIndex + " decodedName: " + new String(Base64.decodeBase64(albumName .getBytes()))); // delete albums // remove files on sdcard File album = Utilities.getAlbumDirectory(albumName); File[] file = album.listFiles(); for (File file2 : file) { file2.delete(); Log.d(TAG, "deleted file: " + file2.getName()); } album.delete(); // remove shared preferences entry SharedPreferences preferences = getSharedPreferences( Utilities.PIC_STORE, 0); Editor edit = preferences.edit(); String pref0 = albumName + ".id"; String pref1 = albumName + ".portrait"; String pref2 = albumName + ".videoId"; String pref3 = albumName + ".frameRate"; if (preferences.contains(pref0)) { edit.remove(pref0); Log.d(TAG, "deleted pref .id"); } if (preferences.contains(pref1)) { edit.remove(pref1); Log.d(TAG, "deleted pref .portrait"); } if (preferences.contains(pref2)) { edit.remove(pref2); Log.d(TAG, "deleted pref .videoId"); } if (preferences.contains(pref3)) { edit.remove(pref3); Log.d(TAG, "deleted pref .frameRate"); } edit.commit(); adapter.remove(albumName); adapter.sort(Utilities.getAlbumNameComparator()); } // hide deletion panel and checkboxes hideDeletionPanelAndCB(MainActivityController.DELETED_ALBUMS); // reload list adapter.notifyDataSetChanged(); controller.transformGUI(MainActivityController.DELETED_ALBUMS); } }); deletionPanel = (LinearLayout) findViewById(R.id.deletionPanel); deleteButton = (ImageButton) findViewById(R.id.deleteButton); deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { controller .transformGUI(MainActivityController.DELETE_BUTTON_PRESSED); if (deleteCheckboxesVisible) { // hide checkboxes deleteCheckboxesVisible = false; // make checkboxes invisible for (CheckBox cbToDelete : deleteAlbumCheckBoxes) { if (cbToDelete.getVisibility() == View.VISIBLE) { Animation myFadeInAnimation = AnimationUtils .loadAnimation(MainActivity.this, R.anim.slight_left_cb); cbToDelete.startAnimation(myFadeInAnimation); cbToDelete.setVisibility(View.GONE); if (cbToDelete.isChecked()) cbToDelete.setChecked(false); Log.d(TAG, "set delete checkbox GONE"); } } } else { // show checkboxes deleteCheckboxesVisible = true; for (CheckBox cbToDelete : deleteAlbumCheckBoxes) { if (cbToDelete.getVisibility() == View.GONE) { // checkboxes Animation myFadeInAnimation = AnimationUtils .loadAnimation(MainActivity.this, R.anim.slight_right_cb); cbToDelete.startAnimation(myFadeInAnimation); cbToDelete.setVisibility(View.VISIBLE); Log.d(TAG, "set delete checkbox visible"); } } } } }); openButton = (ImageButton) findViewById(R.id.openButton); openButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if (openButtonsVisible) { // hide open Buttons AnimationHelper.fadeInFromLeftToRight(MainActivity.this, deleteButton); // make buttons gone for (Button openAlbum : openAlbumButtons) { if (openAlbum.getVisibility() == View.VISIBLE) { Animation myFadeInAnimation = AnimationUtils .loadAnimation(MainActivity.this, R.anim.slight_right); openAlbum.startAnimation(myFadeInAnimation); openAlbum.setVisibility(View.GONE); } } openButtonsVisible = false; } else { // show open buttons AnimationHelper.fadeOutToLeftSide(MainActivity.this, deleteButton); // make buttons visible for (Button openAlbum : openAlbumButtons) { if (openAlbum.getVisibility() == View.GONE) { Animation myFadeInAnimation = AnimationUtils .loadAnimation(MainActivity.this, R.anim.slight_left); openAlbum.startAnimation(myFadeInAnimation); openAlbum.setVisibility(View.VISIBLE); } } openButtonsVisible = true; } } }); controller = new MainActivityController(this, openButton, deleteButton, deletionPanel); } @Override public void onRestart() { super.onRestart(); Log.d(TAG, "------ onRestart MainActivity ------"); controller.reset(); } @Override public void onStart() { super.onStart(); Log.d(TAG, "------ onStart MainActivity ------"); controller.transformGUI(MainActivityController.STARTED); } private void hideDeletionPanelAndCB(int mainActivityCommand) { deleteCheckboxesVisible = false; controller.transformGUI(mainActivityCommand); // make checkboxes invisible for (CheckBox cbToDelete : deleteAlbumCheckBoxes) { if (cbToDelete.getVisibility() == View.VISIBLE) { Animation myFadeInAnimation = AnimationUtils.loadAnimation( MainActivity.this, R.anim.slight_left_cb); cbToDelete.startAnimation(myFadeInAnimation); cbToDelete.setVisibility(View.GONE); if (cbToDelete.isChecked()) cbToDelete.setChecked(false); } } } private class AlbumAdapter extends ArrayAdapter<String> { private LayoutInflater inflater; private List<String> albums; public AlbumAdapter(LayoutInflater inflater, Context context, int layout, List<String> albums) { super(context, layout, albums); this.inflater = inflater; this.albums = albums; openAlbumButtons.clear(); deleteAlbumCheckBoxes.clear(); super.setNotifyOnChange(false); Log.d(TAG, "constructed AlbumAdapter"); } @Override public int getCount() { Log.d(TAG, "getCount " + (albums.size() + 1)); return albums.size() + 1; } @Override public void notifyDataSetChanged() { Log.d(TAG, "notifyDataSetChanged"); openAlbumButtons.clear(); deleteAlbumCheckBoxes.clear(); super.notifyDataSetChanged(); super.setNotifyOnChange(false); } @Override public View getView(final int position, View convertView, ViewGroup parent) { Log.d(TAG, "getView: " + position); View row; if (position == 0) { if (null == convertView || convertView.getId() != R.id.createAlbumRow) { row = inflater.inflate(R.layout.create_album_row, null); } else row = convertView; Log.d(TAG, "LOAD create album row!"); } else { final int albumListPosition = position - 1; if (null == convertView || convertView.getId() == R.id.createAlbumRow) { row = inflater.inflate(R.layout.row, null); } else { row = convertView; } int color = RowColorController.getColorId(position); Log.d(TAG, "Color of row is: " + color + " position " + position); row.setBackgroundResource(color); ImageView firstImage = (ImageView) row .findViewById(R.id.rowImage); // get checkbox to delete an album CheckBox cbToDelete = (CheckBox) row .findViewById(R.id.cbToDelete); cbToDelete.setTag(albumListPosition); cbToDelete.setOnCheckedChangeListener(MainActivity.this); addCheckBoxToDelete(cbToDelete); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 10; options.inPurgeable = true; File[] listFiles = Utilities.getAlbumDirectory( this.getItem(albumListPosition)).listFiles(); if (listFiles != null && listFiles.length > 0) { File selectedPic = listFiles[0]; Bitmap bm = null; try { bm = Bitmap.createBitmap(BitmapFactory.decodeFile( selectedPic.getAbsolutePath(), options)); } catch (Exception e) { Log .d( TAG, "normal behavior; async image saver was still saving the image! So it cannot be displayed yet!"); } firstImage.setImageBitmap(bm); // button to open an album Button openAlbum = (Button) row .findViewById(R.id.openAlbum); addOpenAlbumButton(openAlbum); openAlbum.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // open gallery Intent intent = new Intent(MainActivity.this, GalleryActivity.class); intent.putExtra("albumName", getItem(albumListPosition)); startActivity(intent); // set the openAlbum buttons to gone for (Button openAlbum : openAlbumButtons) openAlbum.setVisibility(View.GONE); controller .transformGUI(MainActivityController.OPEN_ALBUM); openButtonsVisible = false; } }); } else firstImage.setImageBitmap(null); // set album name TextView albumName = (TextView) row .findViewById(R.id.rowAlbumName); String decodedName = new String(Base64.decodeBase64(this .getItem(albumListPosition).getBytes())); albumName.setText(decodedName); // set date of last taken picture in row Date newestPic = null; for (File file : listFiles) { Date creationDate = new Date(file.lastModified()); if (newestPic == null || creationDate.after(newestPic)) newestPic = creationDate; } TextView albumLastPicture = (TextView) row .findViewById(R.id.rowAlbumLastPicture); Resources res = getResources(); if (newestPic != null) { albumLastPicture.setText(String.format(res.getString(R.string.last_picture_from), DateFormat.format("dd.MM.yyyy kk:mm", newestPic))); } else { albumLastPicture.setText(String.format(res.getString(R.string.last_picture_from), "")); } Log.d(TAG, "LOAD ROW: " + decodedName + " encoded name: " + this.getItem(albumListPosition)); } return row; } } private void addCheckBoxToDelete(CheckBox cb) { if (deleteAlbumCheckBoxes.contains(cb)) return; else deleteAlbumCheckBoxes.add(cb); } private void addOpenAlbumButton(Button button) { if (openAlbumButtons.contains(button)) return; else openAlbumButtons.add(button); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case Utilities.MSG_FINISHED_PIC_SAVING: Log.d(TAG, "finished saving; notify dataset has changed!"); adapter.sort(Utilities.getAlbumNameComparator()); adapter.notifyDataSetChanged(); // if openbutton is disabled, because no album and pic existed // before, -> enable it (now the first pic was taken) controller.transformGUI(MainActivityController.PIC_SAVED); break; default: break; } } }; @Override protected Dialog onCreateDialog(int id) { final Dialog dialog; final Context mContext = this; switch (id) { case DIALOG_CREATE_ALBUM_ID: AlertDialog.Builder builder2 = new AlertDialog.Builder(this); builder2.setTitle(R.string.new_gallery); View view = getLayoutInflater() .inflate(R.layout.create_album, null); final EditText edit = (EditText) view .findViewById(R.id.albumNameEditText); final RadioGroup rg = (RadioGroup) view .findViewById(R.id.formatRadioGroup); builder2.setView(view); builder2.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { String name = edit.getText().toString(); Log.d(TAG, "Entered name: " + name); // base64 encode string String encodedName = new String(Base64 .encodeBase64(name.getBytes())); Log.d(TAG, "base64 encoded name: " + encodedName); // check if album with the same name already exist if (Utilities.existsAlbumName(encodedName)) { // fehler showDialog(DIALOG_ALBUM_NAME_ALREADY_EXIST); return; } // create folder Utilities.getAlbumDirectory(encodedName); // get format int checkedRadioButtonId = rg .getCheckedRadioButtonId(); final Boolean portrait; if (checkedRadioButtonId == R.id.portraitRB) portrait = true; else portrait = false; SharedPreferences settings = getSharedPreferences( Utilities.PIC_STORE, 0); Editor edit2 = settings.edit(); edit2.putBoolean(encodedName + ".portrait", portrait); edit2.putFloat(encodedName + ".frameRate", Utilities.MEDIUM_FRAME_RATE); edit2.commit(); Log.d(TAG, "portrait: " + portrait + " settingsname: " + encodedName + ".portrait frameRate: " + Utilities.MEDIUM_FRAME_RATE); // reset editView edit.setText(""); // update table adapter.add(encodedName); adapter.sort(Utilities.getAlbumNameComparator()); adapter.notifyDataSetChanged(); dialog.dismiss(); controller .transformGUI(MainActivityController.CREATED_ALBUM); } }); builder2.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); // reset editView edit.setText(""); // showDialog(DIALOG_CREATE_ALBUM_ID); } }); AlertDialog create = builder2.create(); dialog = create; break; case DIALOG_ALBUM_NAME_ALREADY_EXIST: AlertDialog.Builder builder3 = new AlertDialog.Builder(this); builder3.setTitle(R.string.warning); builder3 .setMessage(R.string.gallery_exists); builder3.setNegativeButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // dialog.dismiss(); showDialog(DIALOG_CREATE_ALBUM_ID); } }); dialog = builder3.create(); break; default: dialog = null; } return dialog; } @Override public boolean onCreateOptionsMenu(Menu menu) { new MenuInflater(this).inflate(R.menu.mainmenu, menu); return super.onCreateOptionsMenu(menu); } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (arg2 == 0) { // open create album dialog showDialog(DIALOG_CREATE_ALBUM_ID); } else { int albumListPosition = arg2 - 1; List<String> albums = Utilities.getAlbumsAsList(); Collections.sort(albums, Utilities.getAlbumNameComparator()); Intent intent = new Intent(this, CameraActivity.class); intent.putExtra("albumName", albums.get(albumListPosition)); startActivityForResult(intent, 0); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // handler.handleMessage(Utilities.MSG_FINISHED_PIC_SAVING); } @Override public void onCheckedChanged(CompoundButton arg0, boolean arg1) { Integer index = (Integer) arg0.getTag(); if (arg1) { checkedAlbums.add(index); Log.d(TAG, "added cbToDelete: " + index + " to list"); } else { checkedAlbums.remove(index); Log.d(TAG, "removed cbToDelete: " + index + " from list"); } } }