package com.flounder.fishDiary;
import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.flounder.fishDiary.data.AboutText;
import com.flounder.fishDiary.data.Constants;
import com.flounder.fishDiary.data.FishDiary;
import com.flounder.fishDiary.data.LePetitPrinceText;
import com.flounder.fishDiary.data.TextContent;
import com.flounder.fishDiary.image.ImageUtil;
import com.flounder.fishDiary.util.Utils;
import com.flounder.fishDiary.view.BaseStyleDialog;
import com.flounder.fishDiary.view.BaseStyleDialog.ICallBack;
import com.flounder.fishDiary.view.LinedEditText;
/**
* TODO: [Bug #1]:
* When user navigates to NoteActivity (from ListActivity) pressing the INSERT button,
* ListActivity refreshes with an inserted empty Note BEFORE NoteActivity gets loaded.
* I have tried the following approach:
* calling overridePendingTransition(0, 0) at onResume(), but things didn't get better.
*/
public class FishDiaryActivity extends Activity {
private Button mBtnSave;
private Button mBtnQuit;
private LinedEditText mEtText;
private EditText mEtTitle;
/** Creates a projection that returns the note ID and the note contents */
private static final String[] PROJECTION = new String[] {
FishDiary.Notes._ID,
FishDiary.Notes.COLUMN_NAME_TITLE,
FishDiary.Notes.COLUMN_NAME_NOTE
};
private static final int STATE_EDIT = 0;
private static final int STATE_INSERT = 1;
private static final int STATE_VIEW = 2;
private static final int STATE_CONTENT = 3;
private int mContentFlag;
private int mState;
private Uri mUri;
private QueryHandler mHandler;
/** A label for the saved state of the activity */
private static final String ORIGINAL_CONTENT = "origContent";
private static final String ORIGINAL_TITLE = "origTitle";
private String mOriginalContent;
private String mOriginalTitle;
private boolean isCanceled;
private boolean isNightMode = false;
private boolean isFullScreen = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fish_diary);
mHandler = new QueryHandler(getContentResolver());
handleIntent();
if (savedInstanceState != null) {
mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
mOriginalTitle = savedInstanceState.getString(ORIGINAL_TITLE);
}
}
private void handleIntent() {
// an intent to use when the Activity object's result is sent back to the caller
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
mState = STATE_VIEW;
mUri = intent.getData();
} else if (Intent.ACTION_INSERT.equals(action)) {
mState = STATE_INSERT;
// insert an empty record in the provider
mUri = getContentResolver().insert(intent.getData(), null);
if (mUri == null) {
Utils.loge("Failed to insert new note into " + getIntent().getData());
Utils.showErrorAndFinish(this, R.string.error_unknown);
return;
}
// Since the new entry was created, set the result to be returned
setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
} else if (Constants.ACTION_CONTENT.equals(action)) {
mContentFlag = intent.getIntExtra(Constants.ACTION_CONTENT,
Constants.CONTENT_ABOUT);
mState = STATE_CONTENT;
} else {
Utils.loge("Unknown action, exiting");
finish();
}
}
private void printContent() {
TextContent content = null;
switch (mContentFlag) {
case Constants.CONTENT_ABOUT:
content = new AboutText(this, mBtnSave, mBtnQuit, mEtText, mEtTitle);
break;
case Constants.CONTENT_READING:
content = new LePetitPrinceText(this,
mBtnSave, mBtnQuit, mEtText, mEtTitle);
break;
}
mEtText.setText(content.getContent(this));
mEtTitle.setText(content.getTitle());
}
/** Set background image. */
private void setBackground() {
Bitmap bgImage = ImageUtil.getBackgroundImage(this);
if (bgImage != null) {
BitmapDrawable drawable = new BitmapDrawable(getResources(), bgImage);
drawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
drawable.setDither(true);
mEtText.setBackgroundDrawable(drawable);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.fish_diary_activity_options_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.options_menu_night_mode:
switchToNightMode();
break;
case R.id.options_menu_full_screen:
switchToFullScreen();
break;
}
return true;
}
private void initView() {
mEtText = (LinedEditText) findViewById(R.id.et_story);
// If user switch to nightMode and onPause called,
// underline will be drawn here [fix]
if (!isNightMode)
mEtText.setUnderLine(FishPreferences.isUnderlineEnable(this));
mEtText.setDrawingCacheEnabled(true);
mEtText.setTextSize(FishPreferences.getTextSize(this));
mEtText.requestFocus();
mEtTitle = (EditText) findViewById(R.id.et_title);
mBtnSave = (Button) findViewById(R.id.btn_save);
mBtnQuit = (Button) findViewById(R.id.btn_back);
if (mState == STATE_CONTENT) {
printContent();
return;
}
if (!isNightMode)
setBackground();
if (mState == STATE_VIEW) {
mBtnSave.setText(R.string.button_edit);
mEtText.setFocusable(false);
mEtText.setCursorVisible(false);
mEtTitle.setFocusable(false);
}
mBtnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mState == STATE_VIEW) { // set state to "edit", allow user input
mState = STATE_EDIT;
mBtnSave.setText(R.string.button_save);
mEtTitle.setFocusableInTouchMode(true);
mEtText.setFocusableInTouchMode(true);
mEtText.setCursorVisible(true);
mEtText.requestFocus();
} else {
saveStory(); // set state to "view", disable user input
mState = STATE_VIEW;
mBtnSave.setText(R.string.button_edit);
mEtText.setFocusable(false);
mEtTitle.setFocusable(false);
mEtText.setCursorVisible(false);
}
}
});
mBtnQuit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
confirmQuit();
}
});
}
@Override
protected void onResume() {
super.onResume();
initView();
isCanceled = false;
if (mState != STATE_CONTENT)
mHandler.startQuery(0, null, mUri, PROJECTION, null, null, null);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString(ORIGINAL_CONTENT, mOriginalContent);
outState.putString(ORIGINAL_TITLE, mOriginalTitle);
}
/** Writes the user's work to the provider */
@Override
protected void onPause() {
super.onPause();
if (!needSave() || isCanceled) {
setResult(RESULT_CANCELED);
} else {
updateNote(mEtText.getText().toString(), mEtTitle.getText().toString()
.trim());
}
}
/** Replaces the current note contents with the text and title provided as arguments */
private void updateNote(String text, String title) {
// Sets up a map to contain values to be updated in the provider
ContentValues values = new ContentValues();
values.put(FishDiary.Notes.COLUMN_NAME_MODIFICATION_DATE,
System.currentTimeMillis());
values.put(FishDiary.Notes.COLUMN_NAME_TITLE, title);
values.put(FishDiary.Notes.COLUMN_NAME_NOTE, text);
mHandler.startUpdate(0, null, mUri, values, null, null);
}
/**
* Cancels the work done on a note. It deletes the note if it was newly created, or
* reverts to the original text of the note.
* cancelNote() takes care of revert(STATE_EDIT)/delete(STATE_INSERT) operations,
* add flag value to avoid duplicated update/delete at onPause().
*/
private void cancelNote() {
isCanceled = true;
if (mState == STATE_EDIT) {
// Put the original note text back into the database
ContentValues values = new ContentValues();
values.put(FishDiary.Notes.COLUMN_NAME_NOTE, mOriginalContent);
values.put(FishDiary.Notes.COLUMN_NAME_TITLE, mOriginalTitle);
mHandler.startUpdate(0, null, mUri, values, null, null);
} else if (mState == STATE_INSERT) {
// We inserted an empty note, make sure to delete it
mHandler.startDelete(0, null, mUri, null, null);
}
}
@Override
public void onBackPressed() {
confirmQuit();
}
private void saveStory() {
String title = mEtTitle.getText().toString().trim();
String text = mEtText.getText().toString();
updateNote(text, title);
// Update the state of note [fix]
mOriginalContent = text;
mOriginalTitle = title;
mState = STATE_EDIT;
Toast.makeText(this, R.string.hint_note_saved, Toast.LENGTH_SHORT).show();
}
private void confirmQuit() {
if (needSave()) {
showNeedSaveDialog();
} else {
finish();
}
}
private boolean needSave() {
if (mState == STATE_VIEW || mState == STATE_CONTENT)
return false;
String text = mEtText.getText().toString();
String title = mEtTitle.getText().toString().trim();
if (mState == STATE_INSERT) {
if (TextUtils.isEmpty(mEtText.getText())
&& TextUtils.isEmpty(mEtTitle.getText())) {
// Delete inserted note here
mHandler.startDelete(0, null, mUri, null, null);
return false;
}
}
if (mState == STATE_EDIT) {
if (text.equals(mOriginalContent) && title.equals(mOriginalTitle)) {
return false;
}
}
return true;
}
/** Display a dialog to ask whether save current story */
private void showNeedSaveDialog() {
BaseStyleDialog.ICallBack callback = new ICallBack() {
@Override
public void posButtonClicked() {
saveStory();
finish();
}
@Override
public void negButtonClicked() {
cancelNote();
finish();
}
};
BaseStyleDialog
.buildInfoDialog(this, R.string.dialog_confirm_save, callback, false);
}
private void switchToFullScreen() {
isFullScreen = !isFullScreen;
if (isFullScreen) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
private void switchToNightMode() {
isNightMode = true;
LinearLayout layout = (LinearLayout) findViewById(R.id.layout1);
layout.setBackgroundColor(getResources().getColor(
R.color.night_mode_bgcolor));
mEtText.setBackgroundColor(getResources().getColor(
R.color.night_mode_bgcolor));
mEtText.setTextColor(getResources().getColor(
R.color.dark_light));
mEtText.setUnderLine(false);
mEtTitle.setTextColor(getResources().getColor(
R.color.dark_light));
mEtTitle.setHintTextColor(getResources().getColor(
R.color.dark_light));
// Set cornered button
mBtnQuit.getBackground().setColorFilter(getResources().getColor(
R.color.dark_light), android.graphics.PorterDuff.Mode.MULTIPLY);
mBtnSave.getBackground().setColorFilter(getResources().getColor(
R.color.dark_light), android.graphics.PorterDuff.Mode.MULTIPLY);
}
/** Perform provider operations asynchronously on a handler thread */
private class QueryHandler extends AsyncQueryHandler {
public QueryHandler(ContentResolver cr) {
super(cr);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
super.onQueryComplete(token, cookie, cursor);
if (cursor != null) {
cursor.moveToFirst();
String note = cursor.getString(cursor
.getColumnIndex(FishDiary.Notes.COLUMN_NAME_NOTE));
mEtText.setTextKeepState(note);
String title = cursor.getString(cursor
.getColumnIndex(FishDiary.Notes.COLUMN_NAME_TITLE));
mEtTitle.setTextKeepState(title);
// Stores the original note text, to allow the user to revert changes
if (mOriginalContent == null) {
mOriginalContent = note;
mOriginalTitle = title;
}
}
}
}
}