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); } }