/* * Copyright (C) 2016 Ferid Cafer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.ferid.app.classroom.statistics; import android.content.Context; import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v4.content.ContextCompat; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import com.ferid.app.classroom.R; import com.ferid.app.classroom.adapters.StatisticalAdapter; import com.ferid.app.classroom.database.DatabaseManager; import com.ferid.app.classroom.listeners.AdapterClickListener; import com.ferid.app.classroom.model.Attendance; import com.ferid.app.classroom.model.AttendanceStatistics; import com.ferid.app.classroom.model.Classroom; import com.jjoe64.graphview.DefaultLabelFormatter; import com.jjoe64.graphview.GraphView; import com.jjoe64.graphview.GridLabelRenderer; import com.jjoe64.graphview.series.DataPoint; import com.jjoe64.graphview.series.LineGraphSeries; import java.util.ArrayList; /** * Created by ferid.cafer on 4/20/2015.<br /> * Shows the student attendance rate and graph. */ public class StatisticalListActivity extends AppCompatActivity { private Context context; private RecyclerView list; //attendance list which can be changed during search private ArrayList<AttendanceStatistics> attendanceList = new ArrayList<>(); //holds attendance list which is used for searching mechanism private ArrayList<AttendanceStatistics> wholeAttendanceList = new ArrayList<>(); private StatisticalAdapter adapter; private TextView emptyText; //empty list view text private Classroom classroom; //graphics private GraphView graph; private LinearLayout graphLayout; private AttendanceStatistics attendance; private ArrayList<Attendance> graphList = new ArrayList<>(); //close graph icon private ImageButton closeGraphIcon; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.statistics); Bundle args = getIntent().getExtras(); if (args != null) { classroom = args.getParcelable("classroom"); } context = this; //toolbar setToolbar(); //graph graphLayout = (LinearLayout) findViewById(R.id.graphLayout); graph = (GraphView) findViewById(R.id.graph); closeGraphIcon = (ImageButton) findViewById(R.id.closeGraphIcon); TextView className = (TextView) findViewById(R.id.className); if (className != null && classroom != null) { className.setText(classroom.getName()); } //list list = (RecyclerView) findViewById(R.id.list); adapter = new StatisticalAdapter(attendanceList); list.setAdapter(adapter); list.setLayoutManager(new LinearLayoutManager(context)); list.setHasFixedSize(true); emptyText = (TextView) findViewById(R.id.emptyText); setCloseGraphIconListener(); addAdapterClickListener(); new SelectAllAttendancesOfClass().execute(); } /** * Create toolbar and set its attributes */ private void setToolbar() { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); } if (classroom != null) { setTitle(classroom.getName()); } } /** * Set empty list text */ private void setEmptyText() { if (emptyText != null) { if (attendanceList.isEmpty()) { emptyText.setVisibility(View.VISIBLE); } else { emptyText.setVisibility(View.GONE); } } } /** * List item click event */ private void addAdapterClickListener() { adapter.setAdapterClickListener(new AdapterClickListener() { @Override public void OnItemClick(int position) { if (attendanceList != null && attendanceList.size() > position) { hideKeyboard(); attendance = attendanceList.get(position); graphList.clear(); new SelectAllAttendancesOfStudent().execute(); } } }); } /** * setOnClickListener */ private void setCloseGraphIconListener() { closeGraphIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { hideGraph(); } }); } /** * Select all students' attendances in percentage from DB */ private class SelectAllAttendancesOfClass extends AsyncTask<Void, Void, ArrayList<AttendanceStatistics>> { @Override protected ArrayList<AttendanceStatistics> doInBackground(Void... params) { ArrayList<AttendanceStatistics> tmpList = null; if (classroom != null) { DatabaseManager databaseManager = new DatabaseManager(context); tmpList = databaseManager.selectAllAttendancesOfClass(classroom.getId()); } return tmpList; } @Override protected void onPostExecute(ArrayList<AttendanceStatistics> tmpList) { wholeAttendanceList.clear(); attendanceList.clear(); if (tmpList != null) { wholeAttendanceList.addAll(tmpList); attendanceList.addAll(tmpList); adapter.notifyDataSetChanged(); setEmptyText(); } } } /** * Select a student's all attendances from DB */ private class SelectAllAttendancesOfStudent extends AsyncTask<Void, Void, ArrayList<Attendance>> { @Override protected ArrayList<Attendance> doInBackground(Void... params) { ArrayList<Attendance> tmpList = null; if (attendance != null) { DatabaseManager databaseManager = new DatabaseManager(context); tmpList = databaseManager.selectAllAttendancesOfStudent(attendance.getClassroomId(), attendance.getStudentId()); } return tmpList; } @Override protected void onPostExecute(ArrayList<Attendance> tmpList) { graphList.clear(); if (tmpList != null) { graphList.addAll(tmpList); calculateAttendanceByWeek(); } } } /** * Calculate presence percentage by week */ private void calculateAttendanceByWeek() { ArrayList<Integer> presenceList = new ArrayList<>(); int numberOfWeeks = graphList.size(); int numberOfPresence = 0; for (int i = 0; i < numberOfWeeks; i++) { Attendance tmpAttendance = graphList.get(i); if (tmpAttendance.getPresent() == 1) { numberOfPresence++; } int percentage = (int) ((double)numberOfPresence * 100 / (i+1)); presenceList.add(percentage); } prepareGraphics(presenceList); } /** * Set graph style attributes * @param maxX */ private void setGraphAttributes(int maxX) { graph.setTitle(attendance.getStudentName()); graph.setTitleColor(ContextCompat.getColor(this, R.color.primary_text)); graph.getViewport().setMaxY(100); graph.getViewport().setYAxisBoundsManual(true); graph.getViewport().setMaxX(maxX); graph.getViewport().setXAxisBoundsManual(true); graph.getGridLabelRenderer().setGridStyle(GridLabelRenderer.GridStyle.BOTH); graph.getGridLabelRenderer().setGridColor(ContextCompat.getColor(this, R.color.grey)); graph.getGridLabelRenderer().setHorizontalLabelsColor(ContextCompat.getColor(this, R.color.blackish)); graph.getGridLabelRenderer().setVerticalLabelsColor(ContextCompat.getColor(this, R.color.blackish)); //number of x-axis label items int numHorizontalLabels; if (maxX <= 8) { numHorizontalLabels = maxX + 1; } else if (maxX <= 16) { numHorizontalLabels = maxX / 2 + 1; } else { numHorizontalLabels = maxX / 4 + 1; } graph.getGridLabelRenderer().setNumHorizontalLabels(numHorizontalLabels); graph.getGridLabelRenderer().reloadStyles(); } /** * Draw graph of weekly attendance * @param presenceList */ private void prepareGraphics(ArrayList<Integer> presenceList) { DataPoint[] dataPoints = new DataPoint[presenceList.size() + 1]; dataPoints[0] = new DataPoint(0, 0); for (int i = 0; i < presenceList.size(); i++) { dataPoints[i + 1] = new DataPoint((i+1), presenceList.get(i)); } LineGraphSeries<DataPoint> series = new LineGraphSeries<>(dataPoints); series.setColor(ContextCompat.getColor(this, R.color.colourAccent)); series.setThickness(getResources().getInteger(R.integer.statistics_series_thickness)); series.setAnimated(true); graph.removeAllSeries(); graph.addSeries(series); setGraphAttributes(presenceList.size()); graph.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter() { @Override public String formatLabel(double value, boolean isValueX) { int valueInt = ((int) value); if (isValueX && valueInt == 0) { return ""; } else { return super.formatLabel(valueInt, isValueX); } } }); showGraph(); } /** * Show graph layout with its full content */ private void showGraph() { if (graphLayout.getVisibility() != View.VISIBLE) { Animation animShow = AnimationUtils.loadAnimation(context, R.anim.push_from_bottom); graphLayout.startAnimation(animShow); graphLayout.setVisibility(View.VISIBLE); setStatusBarColour(); } } /** * Hide graph layout */ private void hideGraph() { if (graphLayout.getVisibility() == View.VISIBLE) { Animation animHide = AnimationUtils.loadAnimation(context, R.anim.push_to_bottom); graphLayout.setAnimation(animHide); graphLayout.setVisibility(View.GONE); setStatusBarColour(); } } /** * Set status bar colour on graph visibility change */ private void setStatusBarColour() { if (Build.VERSION.SDK_INT >= 21) { Window window = getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); if (graphLayout.getVisibility() == View.VISIBLE) { Configuration configuration = getResources().getConfiguration(); if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) { window.setStatusBarColor(ContextCompat.getColor(this, R.color.materialLightGreen)); } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { window.setStatusBarColor(ContextCompat.getColor(this, R.color.colourPrimaryDark)); } } else { window.setStatusBarColor(ContextCompat.getColor(this, R.color.colourPrimaryDark)); } } } /** * Run time searching * @param searchText */ private void searchEngine(final String searchText) { Handler handler = new Handler(); handler.post(new Runnable() { @Override public void run() { ArrayList<AttendanceStatistics> tmpList = new ArrayList<>(); for (AttendanceStatistics as : wholeAttendanceList) { if (as.getStudentName().toLowerCase().startsWith(searchText.toLowerCase())) { tmpList.add(as); } } attendanceList.clear(); attendanceList.addAll(tmpList); adapter.notifyDataSetChanged(); } }); } /** * Hide keyboard */ private void hideKeyboard() { View view = this.getCurrentFocus(); if (view != null) { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } } @Override protected void onSaveInstanceState(Bundle outState) { boolean isGraphVisible; if (graphLayout.getVisibility() == View.VISIBLE) { isGraphVisible = true; } else { isGraphVisible = false; } outState.putBoolean("isGraphVisible", isGraphVisible); outState.putParcelable("attendance", attendance); super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); boolean isGraphVisible = savedInstanceState.getBoolean("isGraphVisible"); attendance = savedInstanceState.getParcelable("attendance"); if (isGraphVisible) { graphList.clear(); new SelectAllAttendancesOfStudent().execute(); } } private void closeWindow() { finish(); overridePendingTransition(R.anim.stand_still, R.anim.move_out_to_bottom); } @Override public void onBackPressed() { //if the graph is open, close it if (graphLayout.getVisibility() == View.VISIBLE) { hideGraph(); } else { //otherwise leave the screen closeWindow(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar actions click switch (item.getItemId()) { case android.R.id.home: closeWindow(); return true; default: return super.onOptionsItemSelected(item); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_statistics, menu); MenuItem searchItem = menu.findItem(R.id.app_bar_search); SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { if (newText.length() >= 1) { searchEngine(newText); } else { attendanceList.clear(); attendanceList.addAll(wholeAttendanceList); adapter.notifyDataSetChanged(); } return true; } }); return true; } }