dess15proj5.fau.cs.osr_amos.mobiletimerecording.ui.SelectedProjectFragment.java Source code

Java tutorial

Introduction

Here is the source code for dess15proj5.fau.cs.osr_amos.mobiletimerecording.ui.SelectedProjectFragment.java

Source

/*
 *     Mobile Time Accounting
 *     Copyright (C) 2015
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package dess15proj5.fau.cs.osr_amos.mobiletimerecording.ui;

import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.CursorIndexOutOfBoundsException;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.view.*;
import android.widget.*;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.R;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.businesslogic.SessionValidator;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.models.Session;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.persistence.DataAccessObjectFactory;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.persistence.PersistenceHelper;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.persistence.ProjectsDAO;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.persistence.SessionsDAO;
import dess15proj5.fau.cs.osr_amos.mobiletimerecording.utility.ProjectTimer;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

public class SelectedProjectFragment extends Fragment {
    private String projectId;
    private String projectName;
    private Date finalDate;
    private Session session;
    private SessionArrayAdapter adapter;
    private ListView sessionListView;

    private TextView projectNameTextView;
    private ProjectTimer timer;
    private FloatingActionButton startStopBtn;

    private boolean firstTimeStartup = true;
    private View selectedView;
    private int selectedPosition;

    /**
     * This method is called in the android lifecycle when the fragment is created.
     *
     * @param savedInstanceState this param contains several key value pairs in order to save the instance state
     * methodtype initialization method
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);

        if (getArguments() != null) {
            setArgumentsFromBundle();
            saveArgumentsIntoSharedPreferences();
        }
    }

    /**
     * This method extracts the arguments from the bundle and sets the attributes.
     *
     * methodtype command method
     */
    private void setArgumentsFromBundle() {
        projectId = getArguments().getString("project_id");
        projectName = getArguments().getString("project_name");
        finalDate = new Date(getArguments().getLong("final_date"));
    }

    /**
     * This method saves the arguments into shared preferences.
     *
     * methodtype command method
     */
    private void saveArgumentsIntoSharedPreferences() {
        SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putString("project_id", projectId);
        editor.putString("project_name", projectName);
        editor.putLong("final_date", finalDate.getTime());
        editor.apply();
    }

    /**
     * This method is called in the android lifecycle when the view of the fragment is created.
     *
     * @param inflater this param contains the layout inflater which is used to generate the gui
     * @param container the container is used by the layout inflater
     * @param savedInstanceState this param contains several key value pairs in order to save the instance state
     * methodtype initialization method
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.selected_project, container, false);
    }

    /**
     * This method is called in the android lifecycle when the application is resumed.
     *
     * methodtype command method
     */
    @Override
    public void onResume() {
        super.onResume();

        addSessionsToAdapter();

        SharedPreferences sharedPref = getActivity().getSharedPreferences("selectedProject", Context.MODE_PRIVATE);
        boolean isRecording = sharedPref.getBoolean("isRecording", false);
        if (isRecording) {
            long sessionId = sharedPref.getLong("sessionId", 0L);
            try {
                SessionsDAO sessionsDAO = DataAccessObjectFactory.getInstance().createSessionsDAO(getActivity());
                session = sessionsDAO.load(sessionId);
                Date startTime = session.getStartTime();
                Date stopTime = session.getStopTime();
                if (startTime.equals(stopTime)) {
                    startStopBtn.setImageDrawable(
                            ContextCompat.getDrawable(getActivity(), R.drawable.ic_stop_white_24dp));
                    long elapsedRealTimeOffset = System.currentTimeMillis() - SystemClock.elapsedRealtime();
                    Long difference = startTime.getTime() - elapsedRealTimeOffset;
                    timer.start();
                    timer.setBase(difference);
                }
            } catch (CursorIndexOutOfBoundsException e) {
                Toast.makeText(getActivity(), "Could not load session due to database errors!", Toast.LENGTH_LONG)
                        .show();
            } catch (SQLException e) {
                Toast.makeText(getActivity(), "Could not load session due to database errors!", Toast.LENGTH_LONG)
                        .show();
            }
        }
    }

    /**
     * This method is called in the android lifecycle when the activity is created.
     *
     * @param savedInstanceState this param contains several key value pairs in order to save the instance state
     * methodtype initialization method
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setArgumentsFromSharedPreferences();
        setWidgets();
        if (attributesAreNull()) {
            setTextViewToNoProjectSelected();
        } else {
            projectNameTextView.setText(projectName);
            startStopBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (timer.isRunning()) {
                        stopCurrentSession(startStopBtn);
                    } else if (isProjectRecordingExpired()) {
                        showToastFinalDateExpiredMessage();
                    } else {
                        startNewSession(startStopBtn);
                    }
                }

                private void startNewSession(FloatingActionButton button) {
                    try {
                        SessionsDAO sessionsDAO = DataAccessObjectFactory.getInstance()
                                .createSessionsDAO(getActivity());
                        session = sessionsDAO.create(projectId, new Date());

                        SessionValidator sessionValidator = SessionValidator.getInstance(getActivity());
                        sessionValidator.checkDay(session);

                        timer.start();
                        button.setImageDrawable(
                                ContextCompat.getDrawable(getActivity(), R.drawable.ic_stop_white_24dp));
                        setRecordingBooleanInSharedPreferences(true);
                        setSessionIdInSharedPreferences(session.getId());
                    } catch (SQLException e) {
                        Toast.makeText(getActivity(), "Could not start timer due to database errors!",
                                Toast.LENGTH_LONG).show();
                    }
                }

                private void stopCurrentSession(FloatingActionButton button) {
                    try {
                        session.setStopTime(new Date());

                        SessionsDAO sessionsDAO = DataAccessObjectFactory.getInstance()
                                .createSessionsDAO(getActivity());
                        sessionsDAO.update(session);

                        timer.stop();

                        button.setImageDrawable(
                                ContextCompat.getDrawable(getActivity(), R.drawable.ic_play_arrow_white_24dp));

                        addSessionsToAdapter();
                        setRecordingBooleanInSharedPreferences(false);
                    } catch (SQLException e) {
                        Toast.makeText(getActivity(), "Could not stop timer due to database errors!",
                                Toast.LENGTH_LONG).show();
                    }
                }
            });
        }
        setAdapterToSessionListView();
        setClickListenerToListView();
        addSessionsToAdapter();
        setClickListenerToFAB();
    }

    /**
     * Returns true if Final Date is after current date.
     *
     * methodtype boolean query method
     */
    public boolean isProjectRecordingExpired() {
        return new Date().after(finalDate);
    }

    /**
     * Shows a toast with a message that it isn't possible to record times after final project date.
     *
     * methodtype command method
     */
    private void showToastFinalDateExpiredMessage() {
        final String message = getResources().getString(R.string.finalDateExpired);
        Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
    }

    /**
     * Sets a boolean if the activity records a session.
     *
     * methodtype command method
     */
    public void setRecordingBooleanInSharedPreferences(boolean isRecording) {
        SharedPreferences sharedPref = getActivity().getSharedPreferences("selectedProject", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putBoolean("isRecording", isRecording);
        editor.apply();
    }

    /**
     * Sets the session id in the Shared Preferences
     *
     * methodtype command method
     */
    public void setSessionIdInSharedPreferences(long sessionId) {
        SharedPreferences sharedPref = getActivity().getSharedPreferences("selectedProject", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putLong("sessionId", sessionId);
        editor.apply();
    }

    /**
     * This method is used to set an adapter to a session list view.
     *
     * methodtype set method
     */
    private void setAdapterToSessionListView() {
        sessionListView = (ListView) getActivity().findViewById(R.id.sessionList);
        adapter = new SessionArrayAdapter(getActivity(), getFragmentManager());
        sessionListView.setAdapter(adapter);
    }

    /**
     * This method is used to set a click listener to the list view.
     *
     * methodtype set method
     */
    private void setClickListenerToListView() {
        sessionListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                if (firstTimeStartup) {
                    selectedView = view;
                    firstTimeStartup = false;
                }
                adapter.setSelectedItemPosition(i);
                setPreviousBtnInvisible();
                SessionArrayAdapter.ViewHolder viewHolder = (SessionArrayAdapter.ViewHolder) view.getTag();
                viewHolder.deleteSessionBtn.setVisibility(View.VISIBLE);
                selectedView = view;
                selectedPosition = i;
            }
        });
    }

    /**
     * This method is used to set the sessionDeleteBtn invisible
     *
     * methodtype set method
     */
    private void setPreviousBtnInvisible() {
        if (selectedView != null) {
            View view = getViewByPosition(selectedPosition, sessionListView);
            if (view != null) {
                (((LinearLayout) view).getChildAt(4)).setVisibility(View.INVISIBLE);
            }
        }
    }

    /**
     * This method is used to get a view of the selected Item
     *
     * @param pos specify the position of the session_row which is to be returned
     * @param listView consist several sessions_rows
     * @return the session_row on the given position
     * methodtype get method
     */
    public View getViewByPosition(int pos, ListView listView) {
        final int firstListItemPosition = listView.getFirstVisiblePosition();
        final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1;

        if (pos < firstListItemPosition || pos > lastListItemPosition) {
            return null;
        } else {
            final int childIndex = pos - firstListItemPosition;
            return listView.getChildAt(childIndex);
        }
    }

    /**
     * This method is used to add sessions to the adapter attribute.
     *
     * methodtype command method
     */
    private void addSessionsToAdapter() {
        if (!attributesAreNull()) {
            adapter.clear();
            adapter.addAll(getSessionsFromDB());
            adapter.notifyDataSetChanged();
        } else {
            setTextViewToNoProjectSelected();
        }
    }

    /**
     * This method is used to load sessions belonging to the selected project from database.
     *
     * @return a list containing all sessions belonging to the selected project
     * methodtype get method
     */
    private List<Session> getSessionsFromDB() {
        List<Session> sessions = null;
        try {
            SessionsDAO sessionsDAO = DataAccessObjectFactory.getInstance().createSessionsDAO(getActivity());
            sessions = sessionsDAO.listAllForProject(projectId);
        } catch (SQLException e) {
            Toast.makeText(getActivity(), "Could not load project list due to database errors!", Toast.LENGTH_LONG)
                    .show();
        }
        return sessions;
    }

    /**
     * This method sets the attributes based on the arguments saved in shared preferences.
     *
     * methodtype set method
     */
    private void setArgumentsFromSharedPreferences() {
        SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
        projectId = sharedPref.getString("project_id", null);
        projectName = sharedPref.getString("project_name", null);
        finalDate = new Date(sharedPref.getLong("final_date", Long.MAX_VALUE));
    }

    /**
     * This method initializes the widget attributes
     *
     * methodtype initialization method
     */
    private void setWidgets() {
        projectNameTextView = (TextView) getActivity().findViewById(R.id.name_of_selected_project);
        timer = (ProjectTimer) getActivity().findViewById(R.id.timer);
        startStopBtn = (FloatingActionButton) getActivity().findViewById(R.id.startStopBtn);
    }

    /**
     * This method checks whether the attributes are null or not.
     *
     * @return true if the attributes are null, false if not
     * methodtype boolean query method
     */
    private boolean attributesAreNull() {
        boolean attributesAreNull = false;
        if (projectId == null && projectName == null)
            attributesAreNull = true;
        return attributesAreNull;
    }

    /**
     * This method displays in the text view that no project is selected if there was no project selected.
     *
     * methodtype set method
     */
    private void setTextViewToNoProjectSelected() {
        projectNameTextView.setText("No project selected. Please select one in the projects tab.");
    }

    /**
     * This method sets an onClickListener to the Floating Action Button to create a new session
     *
     * methodtype initialization method
     */
    private void setClickListenerToFAB() {
        FloatingActionButton addSessionFAB = (FloatingActionButton) getActivity().findViewById(R.id.addSessionFAB);
        addSessionFAB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isProjectRecordingExpired()) {
                    showToastFinalDateExpiredMessage();
                } else {
                    createAddSessionActivity();
                }
            }
        });
    }

    /**
     * This method is used to create the activity to add new sessions.
     *
     * methodtype initialization method
     */
    private void createAddSessionActivity() {
        Intent intent = new Intent(getActivity(), AddSessionActivity.class);
        intent.putExtra("project_id", projectId);
        getActivity().startActivity(intent);
        getActivity().overridePendingTransition(R.animator.fade_in_right, R.animator.empty_animator);
    }

    /**
     * This method is called in the android lifecycle when a menu is created.
     *
     * @param menu the menu item which has to be created
     * @param inflater contains the information for the layout of the menu
     * methodtype initialization method
     */
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        getActivity().getMenuInflater().inflate(R.menu.menu_selected_project, menu);
    }

    /**
     * This method is called in the android lifecycle when a menu item is clicked on.
     *
     * @param item the item which was targeted
     * @return true if there was an item clicked
     * methodtype boolean query method
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_edit_project:
            startEditProjectActivity();
            return true;
        case R.id.action_delete_project:
            initConfirmationDialog();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    /**
     * This method is used in the android lifecycle when the option menu is prepared.
     *
     * @param menu the menu that is prepared
     * methodtype initialization method
     */
    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        if (projectId == null && projectName == null || isSpecialProject()) {
            menu.getItem(0).setEnabled(false);
            menu.getItem(1).setEnabled(false);
        }
    }

    /**
     * This method checks if the selected project is a special project
     *
     * methodtype boolean query method
     */
    private boolean isSpecialProject() {
        boolean isSpecialProject = false;
        List<String> specialProjects = PersistenceHelper.getDefaultProjectsAsList();
        for (String specialProjectId : specialProjects) {
            if (specialProjectId.equals(projectId)) {
                isSpecialProject = true;
            }
        }
        return isSpecialProject;
    }

    private void startEditProjectActivity() {
        Intent intent = new Intent(getActivity(), EditProjectActivity.class);
        intent.putExtra("project_id", projectId);
        startActivity(intent);
        getActivity().overridePendingTransition(R.animator.fade_in_right, R.animator.empty_animator);
    }

    /**
     * This method initializes a dialog to confirm the deletion of the selected project
     *
     * methodtype initialization method
     */
    private void initConfirmationDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
                .setMessage(getResources().getString(R.string.confirmDeletionDialog) + " " + projectName + "?")
                .setPositiveButton("Delete", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        deleteProject();
                    }
                }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        final AlertDialog dialog = builder.create();
        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface arg0) {
                dialog.getButton(AlertDialog.BUTTON_POSITIVE)
                        .setTextColor(getResources().getColor(R.color.bluePrimaryColor));
                dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
                        .setTextColor(getResources().getColor(R.color.bluePrimaryColor));
            }
        });
        dialog.show();
    }

    /**
     * This method is used to delete projects from database.
     *
     * methodtype command method
     */
    private void deleteProject() {
        try {
            ProjectsDAO projectsDAO = DataAccessObjectFactory.getInstance().createProjectsDAO(getActivity());
            projectsDAO.delete(projectId);
        } catch (SQLException e) {
            Toast.makeText(getActivity(), "Could not get ProjectsDAO due to database errors!", Toast.LENGTH_SHORT)
                    .show();
        }
        setAttributesNull();
        showProjectsListFragment();
    }

    /**
     * This method is used to set the attributes to null in case of deletion of the selected project.
     *
     * methodtype command method
     */
    private void setAttributesNull() {
        projectId = null;
        projectName = null;
        finalDate = new Date(Long.MAX_VALUE);
        saveArgumentsIntoSharedPreferences();
    }

    /**
     * This method is used to show the project list fragment.
     *
     * methodtype command method
     */
    private void showProjectsListFragment() {
        getFragmentManager().beginTransaction().replace(R.id.frameLayout, new ProjectsListFragment()).commit();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    }
}