package se.dat255.grupp12;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import de.timroes.android.listview.EnhancedListView;
public class MainActivity extends Activity implements TextView.OnEditorActionListener {
private String[] drawerItems;
private String[] drawerTodoListItems;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
static final int PICK_DATE_REQUEST = 0;
private FrameLayout mFrameLayout;
private TextView listname;
private EnhancedListView listview;
private ListView drawerTodoListView;
private EditText new_task_text;
private ImageButton addTaskButton;
private MenuItem refreshItem;
private Menu menu;
private MenuItem thrashBin;
private MenuItem addCollaborator;
private FileHandler filehandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Listview inserted into the drawer layout
this.listview = (EnhancedListView) findViewById(R.id.listView);
this.drawerTodoListView = (ListView) findViewById(R.id.todo_list_view);
//Get local copy of lists
filehandler = new FileHandler();
ArrayList<TodoList> list = new ArrayList<TodoList>();
try {
list = (ArrayList<TodoList>) filehandler.readListFromJson(this, "list_file");
Modification.setLog((List<Modification>)filehandler.readListFromJson(this, "log_file"));
//Write IP address
filehandler.writeAddress(this);
} catch (IOException e) {
e.printStackTrace();
}
//Only read file if not first launch, else insert example lists
if (list.size()>0) {
TodoList.setTodoLists(list);
}else{
ArrayList<Task> tasksArray = new ArrayList<Task>();
tasksArray.add(new Task("Mjölk", Task.Priority.HIGH));
tasksArray.add(new Task("Ägg", Task.Priority.LOW));
tasksArray.add(new Task("Bröd", Task.Priority.MEDIUM));
ArrayList<Task> tasksArray2 = new ArrayList<Task>();
tasksArray2.add(new Task("Tvätta", Task.Priority.HIGH));
tasksArray2.add(new Task("Städa", Task.Priority.LOW));
tasksArray2.add(new Task("Plugga", Task.Priority.MEDIUM));
ArrayList<Task> tasksArray3 = new ArrayList<Task>();
tasksArray3.add(new Task("Koda", Task.Priority.HIGH));
tasksArray3.add(new Task("Dokumentera", Task.Priority.LOW));
tasksArray3.add(new Task("Möte", Task.Priority.MEDIUM));
TodoList testList1 = new TodoList("Handla", tasksArray);
TodoList testList2 = new TodoList("Att göra", tasksArray2);
TodoList testList3 = new TodoList("Projekt", tasksArray3);
TodoList.addTodoList(testList1);
TodoList.addTodoList(testList2);
TodoList.addTodoList(testList3);
}
TodoList.setCurrentList(TodoList.THE_ASSIGNED_LIST);
setupActivity();
}
public void setupActivity() {
TextView userEmail = (TextView) findViewById(R.id.logged_in_as);
userEmail.setText(User.getUserEmails().get(0).toString());
listname = (TextView) findViewById(R.id.todo_list_name);
listname.setText(TodoList.getCurrentList().getName());
final SwipeListViewAdapter adapter = new SwipeListViewAdapter(this);
final TodoListViewAdapter listsAdapter = new TodoListViewAdapter(this,
R.layout.drawer_list_item);
listview.setOnItemClickListener(new ListViewItemClickListener(this));
listview.setDismissCallback(new EnhancedListView.OnDismissCallback() {
@Override
public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView,
final int i,
final EnhancedListView.DismissDirection direction) {
final Task item = (Task) enhancedListView.getAdapter().getItem(i);
if (item.isDone()) {
if (direction == EnhancedListView.DismissDirection.END) {
// Log the task removal.
Modification.logTaskRemoval(item, TodoList.getCurrentList().getIdForPosition(item));
// Swipe towards right removes done items.
((SwipeListViewAdapter) enhancedListView.getAdapter()).remove(item);
notifyCurrentListViewOfDatasetChange();
return new EnhancedListView.Undoable() {
@Override
public void undo() {
((SwipeListViewAdapter) enhancedListView.getAdapter()).add(item);
notifyCurrentListViewOfDatasetChange();
Modification.logTaskAddition(item, TodoList.getCurrentList().getIdForPosition(item));
}
};
} else {
// Swipe towards left "undones" the item.
item.setDone(false);
notifyCurrentListViewOfDatasetChange();
Modification.logTaskEdit(item.getId(), TodoList.getCurrentList().getIdForPosition(item), new Modification.Change(
Modification.Change.TYPE_ISDONE,
"true",
"false"
));
return null;
}
} else {
item.setDone(true);
notifyCurrentListViewOfDatasetChange();
Modification.logTaskEdit(item.getId(), TodoList.getCurrentList().getIdForPosition(item), new Modification.Change(
Modification.Change.TYPE_ISDONE,
"false",
"true"
));
return new EnhancedListView.Undoable() {
@Override
public void undo() {
//((SwipeListViewAdapter) enhancedListView.getAdapter()).remove(item);
item.setDone(false);
//((SwipeListViewAdapter) enhancedListView.getAdapter()).add(i, item);
notifyCurrentListViewOfDatasetChange();
Modification.logTaskEdit(item.getId(), TodoList.getCurrentList().getIdForPosition(item), new Modification.Change(
Modification.Change.TYPE_ISDONE,
"true",
"false"
));
}
@Override
public String getTitle() {
return "Task marked as done";
}
};
}
}
});
listview.enableSwipeToDismiss();
listview.setRequireTouchBeforeDismiss(false);
listview.setUndoHideDelay(3000);
listview.setAdapter(adapter);
drawerTodoListView.setAdapter(listsAdapter);
// Setup the priority spinner.
Spinner spinner = (Spinner) findViewById(R.id.prio_spinner);
ArrayAdapter<CharSequence> prioAdapter = ArrayAdapter.createFromResource(this,
R.array.prio_names, android.R.layout.simple_spinner_item);
prioAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(prioAdapter);
spinner.setSelection(1);
TextView.OnEditorActionListener newTaskListener = new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
// Add the task when we press the return key.
if (i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
if(!(new_task_text.getText().toString().length() == 0)){
pressedAddNewTask(textView);
}
}
return true;
}
};
new_task_text = (EditText) findViewById(R.id.new_task_text);
new_task_text.setOnEditorActionListener(newTaskListener);
//Fetching pre-defined strings from xml-file and inserting themn into the drawer
drawerItems = getResources().getStringArray(R.array.drawer_items);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mFrameLayout = (FrameLayout) findViewById(R.id.left_drawer);
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */
R.string.drawer_open, /* description for drawer open */
R.string.drawer_close /* description for drawer closed */
) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
//currently unused
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
//Exit edit-title mode when drawer is opened
onEditorAction((TextView)findViewById(R.id.todo_list_name), 0, new KeyEvent(0,0));
}
};
//listen for events to open the drawer
mDrawerLayout.setDrawerListener(mDrawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
getActionBar().setDisplayShowTitleEnabled(false);
ListView mTodoListView = (ListView) mFrameLayout.findViewById(R.id.todo_list_view);
mTodoListView.setAdapter(listsAdapter);
// Set the list's click listener
mTodoListView.setOnItemClickListener(new DrawerItemClickListener());
notifyCurrentListViewOfDatasetChange();
final ArrayList<TodoList> defaultLists = (ArrayList<TodoList>) TodoList.getTodoLists();
Modification.sync(new Modification.SyncCallback() {
@Override
public void hasSynced(boolean succeeded) {
if (succeeded) {
Toast.makeText(getApplicationContext(), "Synccess!", Toast.LENGTH_SHORT).show();
} else {
TodoList.setTodoLists(defaultLists);
for (TodoList list : defaultLists) {
Modification.logListCreation(list);
}
}
notifyCurrentListViewOfDatasetChange();
}
});
Modification.setAutosyncCallback(new Modification.SyncCallback() {
@Override
public void hasSynced(boolean value) {
notifyCurrentListViewOfDatasetChange();
}
});
TodoList.sortListAfterPrio();
addTaskButton = (ImageButton) findViewById(R.id.add_task_button);
addTaskButton.setEnabled(false);
addTaskButton.setImageResource(R.drawable.action_new_disabled);
//Listener for disabling add button when task text field is empty
new_task_text.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
switchButtonState();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
switchButtonState();
}
@Override
public void afterTextChanged(Editable s) {
switchButtonState();
}
public void switchButtonState() {
if (new_task_text.getText().toString().length() == 0) {
addTaskButton.setEnabled(false);
addTaskButton.setImageResource(R.drawable.action_new_disabled);
} else {
addTaskButton.setEnabled(true);
addTaskButton.setImageResource(R.drawable.action_new_enabled);
}
}
});
}
//Life cycle related methods
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle other action bar items...
switch (item.getItemId()) {
case R.id.action_add_people:
this.addCollaborator(item);
break;
case R.id.action_refresh:
//refreshItem = (MenuItem) item;
this.animateSync();
this.pressedSync(item);
break;
case R.id.action_remove_list:
new AlertDialog.Builder(this)
.setTitle("Confirm removal")
.setMessage("Are you sure you want to remove this list?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
TodoList listToRemove = TodoList.getCurrentList();
TodoList.removeTodoList(listToRemove);
notifyCurrentListViewOfDatasetChange();
listname.setText(TodoList.getCurrentList().getName());
Toast.makeText(getApplicationContext(), "List removed!" , Toast.LENGTH_SHORT).show();
Modification.logTodoRemoval(listToRemove);
}
})
.setNegativeButton("No", null)
.show();
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
this.menu = menu;
getMenuInflater().inflate(R.menu.main_activity_actions, menu);
refreshItem = (MenuItem) menu.findItem(R.id.action_refresh);
thrashBin = (MenuItem) menu.findItem(R.id.action_remove_list);
addCollaborator = (MenuItem) menu.findItem(R.id.action_add_people);
if (ServerConnection.isConnectedToServer()) {
refreshItem.setVisible(true);
} else {
refreshItem.setVisible(false);
}
return true;
}
public void addCollaborator(MenuItem item){
Intent addPeople;
addPeople = new Intent(this, ContactTabsActivity.class);
startActivity(addPeople);
}
public void showCollaborator(View view){
Intent viewPeople;
viewPeople = new Intent(this, ViewCollaboratorsActivity.class);
startActivity(viewPeople);
}
/**
* onClick method for adding new task from the text field
* @param view
*/
public void pressedAddNewTask(View view) {
EditText editText = (EditText) findViewById(R.id.new_task_text);
Spinner prio_spinner = (Spinner) findViewById(R.id.prio_spinner);
Task.Priority prio = Task.Priority.LOW;
//set the priority from the spinner
switch (prio_spinner.getSelectedItemPosition()) {
case 0:
prio= Task.Priority.HIGH;
break;
case 1:
prio= Task.Priority.MEDIUM;
break;
case 2:
prio= Task.Priority.LOW;
break;
}
Task task = new Task(editText.getText().toString(), prio);
//Add task, and notify of dataset change
TodoList.getCurrentList().getTasks().add(0,task);
notifyCurrentListViewOfDatasetChange();
// Log the creation of a task so that we can sync it with the server.
Modification.logTaskAddition(task,TodoList.getCurrentList().getId());
// Clear the EditText
editText.setText("");
}
public void pressedSync(MenuItem item) {
Modification.sync(new Modification.SyncCallback() {
@Override
public void hasSynced(boolean value) {
notifyCurrentListViewOfDatasetChange();
if (value) {
Toast.makeText(getApplicationContext(), "Synccess!", Toast.LENGTH_SHORT).show();
}
finishAnimateSync();
}
});
}
public void toggleAutoSync(View toggleSwitch) {
Modification.toggleAutoSync(((Switch) toggleSwitch).isChecked());
}
/**
* onClick method, that chooses the active TodoList, and creates the list
* @param view
*/
public void pressedAddNewTodo(View view) {
EditText editText = (EditText) findViewById(R.id.new_todo_text);
//Add the new todo
String newTaskText = editText.getText().toString();
TodoList newTodo = new TodoList(newTaskText);
TodoList.addTodoList(newTodo);
((ArrayAdapter)this.drawerTodoListView.getAdapter()).notifyDataSetChanged();
// Clear the EditText and update title
listname.setText(newTaskText);
editText.setText("");
// Log the creation of a new list as a modification
Modification.logListCreation(newTodo);
//Close the drawer and show the newly created empty TodoList
mDrawerLayout.closeDrawers();
listname.setText(newTaskText);
TodoList.setCurrentList(newTodo);
notifyCurrentListViewOfDatasetChange();
}
/**
* Method for notifying the listview of dataset change, concerning the current chosen listview
*/
public void notifyCurrentListViewOfDatasetChange(){
((ArrayAdapter)this.listview.getAdapter()).notifyDataSetChanged();
((ArrayAdapter)this.drawerTodoListView.getAdapter()).notifyDataSetChanged();
TodoList.sortListAfterPrio();
RelativeLayout addTaskBar = (RelativeLayout) findViewById(R.id.add_task_bar);
LinearLayout currentListOptions = (LinearLayout) findViewById(R.id.current_list_options);
if (TodoList.getCurrentList()==TodoList.THE_ASSIGNED_LIST) {
addTaskBar.setVisibility(View.GONE);
currentListOptions.setVisibility(View.GONE);
try{
thrashBin.setVisible(false);
addCollaborator.setVisible(false);
} catch (NullPointerException ignored){}
} else {
addTaskBar.setVisibility(View.VISIBLE);
currentListOptions.setVisibility(View.VISIBLE);
try{
thrashBin.setVisible(true);
addCollaborator.setVisible(true);
} catch (NullPointerException ignored){} }
}
public void clickedFace(View view) {
Task task = TodoList.getCurrentList().getTasks().get((Integer)view.getTag());
task.setAssigned(!task.isAssigned());
// Log the assignment as a modification
Modification.logTaskEdit(task.getId(),TodoList.getCurrentList().getIdForPosition(task),new Modification.Change(
Modification.Change.TYPE_ASSIGNED,
task.isAssigned() ? "false" : "true",
task.isAssigned() ? "true" : "false"
));
notifyCurrentListViewOfDatasetChange();
}
/**
* Inner class listening to events in the side drawer
*/
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
TodoList.setCurrentList(TodoList.getTodoLists().get(position));
listname.setText(TodoList.getCurrentList().getName());
//Close the drawer and notify of dataset change
notifyCurrentListViewOfDatasetChange();
mDrawerLayout.closeDrawers();
}
}
/**
* This method passes on an intent to start a new activity showing a detailed view of the
* task that has been selected. The new activity is started with @startActivityForResult
* implying that the current activity will recieve a value when the new activity terminates
* @param task the task to show in the new activity
* @param adapterView not used
* @param i the tasks listindex
*/
public void showDetailedView(Task task, AdapterView<?> adapterView, int i){
Intent intent = new Intent(this, DetailedViewActivity.class);
intent.putExtra("task", task);
intent.putExtra("index", i);
intent.putExtra("listid", TodoList.getCurrentList().getIdForPosition(task));
startActivityForResult(intent, PICK_DATE_REQUEST);
}
/**
* Called when the @DetailedViewActivity finishes with a result. The result contains an updated
* task which, in the listview, replaces the old task.
* @param requestCode defines which type of result is to be requested
* @param resultCode defines which type of result that was returned
* @param data contains the updated task and its listindex
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_DATE_REQUEST) {
if (resultCode == RESULT_OK) {
Task editedtask = (Task) data.getExtras().get("task");
int i = data.getExtras().getInt("index");
Task task = TodoList.getCurrentList().getTasks().get(i);
task.setTitle(editedtask.getTitle());
task.setContent(editedtask.getContent());
task.setDone(editedtask.isDone());
task.setAssigned(editedtask.isAssigned());
task.setDate(editedtask.getDate());
task.setPriority(editedtask.getPriority());
notifyCurrentListViewOfDatasetChange();
}
}
}
/**
* Save current lists to file as soon as Toddler is paused or completely shut down
*/
@Override
public void onPause(){
super.onPause();
System.out.println("onpause");
List list = TodoList.getTodoListsWithoutAssigned();
try {
filehandler.writeListToJson(list, this, "list_file");
filehandler.writeListToJson(Modification.getLog(), this, "log_file");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Called when the title of a list is clicked. This makes the title editable.
* @param view the TextView that was clicked
*/
public void changeListName(View view){
if (TodoList.getCurrentList()==TodoList.THE_ASSIGNED_LIST) {
return;
}
if(view.getId() == findViewById(R.id.remove_list_from_drawer).getId()){
TextView textView = (TextView) findViewById(R.id.todo_list_name);
LinearLayout parent = (LinearLayout) textView.getParent();
int index = parent.indexOfChild(textView);
String oldName = textView.getText().toString();
parent.removeView(textView);
EditText editText = new EditText(this);
editText.setSingleLine(true);
editText.setText(oldName);
editText.setId(R.id.todo_list_name);
editText.setOnEditorActionListener(this);
editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
editText.setGravity(Gravity.CENTER);
parent.addView(editText, index);
mDrawerLayout.closeDrawers();
editText.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
} else {
TextView textView = (TextView) view;
LinearLayout parent = (LinearLayout) textView.getParent();
int index = parent.indexOfChild(textView);
String oldName = textView.getText().toString();
parent.removeView(textView);
EditText editText = new EditText(this);
editText.setSingleLine(true);
editText.setText(oldName);
editText.setId(R.id.todo_list_name);
editText.setOnEditorActionListener(this);
editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
editText.setGravity(Gravity.CENTER);
parent.addView(editText, index);
}
}
/**
* Called when the user has pressed enter after deiting the name of a list
* @param textView the view containing the list title
* @param i the index of the textview in its parent
* @param keyEvent the event that triggered this method
* @return true
*/
@Override
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
int keyAction;
try {
keyAction = keyEvent.getAction();
}catch (NullPointerException e) {
keyAction = KeyEvent.KEYCODE_ENTER;
}
String newText = textView.getText().toString();
if (!newText.equals(TodoList.getCurrentList().getName()) &&
TodoList.getCurrentList() != TodoList.THE_ASSIGNED_LIST &&
keyAction == KeyEvent.ACTION_DOWN) {
//also change the name in the list
TodoList.getCurrentList().setName(newText);
((ArrayAdapter)this.drawerTodoListView.getAdapter()).notifyDataSetChanged();
notifyCurrentListViewOfDatasetChange();
//log as modification
Modification.logTodoListNameChange(TodoList.getCurrentList(), newText);
}
ViewGroup parent = (ViewGroup) textView.getParent();
int index = parent.indexOfChild(textView);
parent.removeView(textView);
//Only set new text if text isn't null, else use old text
if(newText.length()>0 ){
listname.setText(newText);
}
parent.addView(listname, index);
return true;
}
@Override
public void onBackPressed() {
/*If user is currently editing a list title the back button works as an exit button out
* of this mode. Else it works like usual, navigating up or "back"*/
if(!(findViewById(R.id.todo_list_name) instanceof EditText)){
new AlertDialog.Builder(this)
.setTitle("Confirm logout")
.setMessage("Do you really want to log out?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton("No", null)
.show();
}else{
onEditorAction((TextView)findViewById(R.id.todo_list_name), 0,
new KeyEvent(KeyEvent.KEYCODE_BACK, 0));
}
}
public void animateSync() {
/* Attach a rotating ImageView to the refresh item as an ActionView */
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ImageView iv = (ImageView) inflater.inflate(R.layout.refresh_icon, null);
Animation rotation = AnimationUtils.loadAnimation(this, R.anim.rotate_icon);
rotation.setRepeatCount(Animation.INFINITE);
iv.startAnimation(rotation);
refreshItem.setActionView(iv);
}
public void finishAnimateSync() {
refreshItem.getActionView().clearAnimation();
refreshItem.setActionView(null);
}
}