diff --git a/app/build.gradle b/app/build.gradle index 96859a497e0884c5a52612e9c42081ff7ffdec22..9f47ba17aba93a22e024e6d3e3a524a748a557d4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,6 +11,7 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "@string/auth0_scheme"] } buildTypes { release { @@ -35,4 +36,6 @@ dependencies { api 'com.theartofdev.edmodo:android-image-cropper:2.8.0' implementation 'com.jjoe64:graphview:4.2.2' implementation 'com.github.sundeepk:compact-calendar-view:3.0.0' + implementation 'com.auth0.android:auth0:1.22.1' + implementation 'com.auth0.android:lock:2.7.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5a267e8271d865adfbdb91eb763c76c2b483f75d..99f831b27cad425cd9965acd2e0a2f80b295600e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" @@ -24,6 +25,13 @@ </intent-filter> </activity> + <activity + android:name="com.auth0.android.lock.LockActivity" + android:label="@string/app_name" + android:launchMode="singleTask" + android:screenOrientation="portrait" + android:theme="@style/Lock.Theme"/> + <activity android:name=".AboutActivity" android:label="About" diff --git a/app/src/main/java/com/yearthreeproject/xbframework/BoxesActivity.java b/app/src/main/java/com/yearthreeproject/xbframework/BoxesActivity.java index 6040de4c5c2af6ca2d51dfe2bd8eb186c63dc9cb..4616b0520a2856dfb27efdccc67a352d3f74b1b7 100644 --- a/app/src/main/java/com/yearthreeproject/xbframework/BoxesActivity.java +++ b/app/src/main/java/com/yearthreeproject/xbframework/BoxesActivity.java @@ -151,7 +151,7 @@ public class BoxesActivity extends AppCompatActivity { JSONObject localData = new JSONObject(ProjectMacros.readFile(BoxesActivity.this, "localUserData.json")); - if (!locked && ProjectMacros.checkDateLimit(localData.getString("dateUntil"))) { + if (!locked) { Intent openPage = new Intent(BoxesActivity.this, ExperimentActivity.class); openPage.putExtra("JSON", box.toString()); startActivity(openPage); diff --git a/app/src/main/java/com/yearthreeproject/xbframework/LoginActivity.java b/app/src/main/java/com/yearthreeproject/xbframework/LoginActivity.java index f8b66afd53c3f0a8730a5c79559408cb557b3d01..a456d8e9ba5148a55593a4ef5011fbfea0ff88b9 100644 --- a/app/src/main/java/com/yearthreeproject/xbframework/LoginActivity.java +++ b/app/src/main/java/com/yearthreeproject/xbframework/LoginActivity.java @@ -4,16 +4,31 @@ import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.Button; +import android.widget.EditText; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import com.auth0.android.Auth0; +import com.auth0.android.authentication.AuthenticationAPIClient; +import com.auth0.android.authentication.AuthenticationException; +import com.auth0.android.callback.BaseCallback; +import com.auth0.android.lock.AuthenticationCallback; +import com.auth0.android.lock.Lock; +import com.auth0.android.lock.utils.LockException; +import com.auth0.android.result.Credentials; + import java.util.Objects; +import static android.util.Log.d; + public class LoginActivity extends AppCompatActivity { + private Auth0 auth0; + private Lock lock; + @Override public boolean onSupportNavigateUp() { finish(); @@ -32,11 +47,51 @@ public class LoginActivity extends AppCompatActivity { getSupportActionBar().setLogo(R.mipmap.ic_launcher); getSupportActionBar().setDisplayUseLogoEnabled(true); + auth0 = new Auth0(getString(R.string.com_auth0_client_id), getString(R.string.com_auth0_domain)); + auth0.setOIDCConformant(true); + + lock = Lock.newBuilder(auth0, cb).build(this); + + final EditText email = findViewById(R.id.EmailEditText); + final EditText password = findViewById(R.id.PasswordEditText); + + final AuthenticationAPIClient authentication = new AuthenticationAPIClient(auth0); + Button submitLoginButton = findViewById(R.id.LoginSubmitButton); submitLoginButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - //TODO: implement what happens on submitting login + authentication + .login(email.getText().toString(), password.getText().toString(), "Username-Password-Authentication") + .start(new BaseCallback<Credentials, AuthenticationException>() { + @Override + public void onSuccess(Credentials payload) { + d("dbg_success", payload.getIdToken()); + } + + @Override + public void onFailure(AuthenticationException error) { + d("dbg_failure", error.getMessage()); + } + }); + //startActivity(lock.newIntent(LoginActivity.this)); } }); } + + private AuthenticationCallback cb = new AuthenticationCallback() { + @Override + public void onError(LockException error) { + d("dbg_err", "err"); + } + + @Override + public void onAuthentication(Credentials credentials) { + d("dbg_success", "success"); + } + + @Override + public void onCanceled() { + d("dbg_cancelled", "cancelled"); + } + }; } diff --git a/app/src/main/java/com/yearthreeproject/xbframework/MainActivity.java b/app/src/main/java/com/yearthreeproject/xbframework/MainActivity.java index 836886908d79b6d05667dee0433971666f5f81dc..496b20de4ef45b0abcb2750a3295675e43f299df 100644 --- a/app/src/main/java/com/yearthreeproject/xbframework/MainActivity.java +++ b/app/src/main/java/com/yearthreeproject/xbframework/MainActivity.java @@ -269,7 +269,25 @@ public class MainActivity extends AppCompatActivity { File file = new File(this.getFilesDir(), "localUserData.json"); if (!file.exists()) { // Do stuff to initialise the file - ProjectMacros.saveFile(this, "localUserData.json", "{\"d\":\"01/31/1999\",\"savedUserID\":\"A01\"}"); + InputStream inputStream = getResources().openRawResource(R.raw.local_user_data); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + String localUserData = ""; + int ctr; + try { + ctr = inputStream.read(); + while (ctr != -1) { + byteArrayOutputStream.write(ctr); + ctr = inputStream.read(); + } + inputStream.close(); + + localUserData = byteArrayOutputStream.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + + + ProjectMacros.saveFile(this, "localUserData.json", localUserData); } } @@ -316,7 +334,23 @@ public class MainActivity extends AppCompatActivity { ProjectMacros.saveFile(this, "boxData.json", boxesData); - ProjectMacros.saveFile(this, "localUserData.json", "{\"dateUntil\": \"01/31/1999\",\n\"savedUserID\": \"A01\",\n\"locked\": false}"); + inputStream = getResources().openRawResource(R.raw.local_user_data); + byteArrayOutputStream = new ByteArrayOutputStream(); + String localUserData = ""; + try { + ctr = inputStream.read(); + while (ctr != -1) { + byteArrayOutputStream.write(ctr); + ctr = inputStream.read(); + } + inputStream.close(); + + localUserData = byteArrayOutputStream.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + + ProjectMacros.saveFile(this, "localUserData.json", localUserData); d("dbg_file", ProjectMacros.readFile(this, "boxData.json")); d("dbg_file", ProjectMacros.readFile(this, "localUserData.json")); @@ -351,6 +385,36 @@ public class MainActivity extends AppCompatActivity { // Image permission check @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) private void askForWriteAccess() { + if (ContextCompat.checkSelfPermission(MainActivity.this, + Manifest.permission.INTERNET) + != PackageManager.PERMISSION_GRANTED) { + + if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, + Manifest.permission.INTERNET)) { + + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setTitle("Permission Required") + .setMessage("Permission to access internet for login.") + .setPositiveButton("Ok", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", getPackageName(), null)); + startActivityForResult(intent, 5); + } + }).setNegativeButton("Cancel", null).show(); + + } else { + ActivityCompat.requestPermissions(MainActivity.this, + new String[]{Manifest.permission.INTERNET}, + 1); + } + } else { + d("dbg_Perm", "Already granted"); + } + + if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { diff --git a/app/src/main/java/com/yearthreeproject/xbframework/ProgressActivity.java b/app/src/main/java/com/yearthreeproject/xbframework/ProgressActivity.java index e82dabdaf097b21c44903ba7a42cc468e3a2466c..2d9c263542a3b6989727be61d0197a995d2b16b3 100644 --- a/app/src/main/java/com/yearthreeproject/xbframework/ProgressActivity.java +++ b/app/src/main/java/com/yearthreeproject/xbframework/ProgressActivity.java @@ -1,28 +1,43 @@ package com.yearthreeproject.xbframework; +import android.content.DialogInterface; +import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; import android.os.Build; import android.os.Bundle; import android.text.Html; import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import com.github.sundeepk.compactcalendarview.CompactCalendarView; import com.github.sundeepk.compactcalendarview.domain.Event; +import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.tabs.TabLayout; import com.jjoe64.graphview.GraphView; import com.jjoe64.graphview.helper.DateAsXAxisLabelFormatter; import com.jjoe64.graphview.series.DataPoint; +import com.jjoe64.graphview.series.DataPointInterface; import com.jjoe64.graphview.series.LineGraphSeries; import com.jjoe64.graphview.series.PointsGraphSeries; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -33,6 +48,39 @@ import static android.util.Log.d; public class ProgressActivity extends AppCompatActivity { + Toast progressToast; + + CompactCalendarView calendarViewForGraphs; + TextView monthTextViewGraph; + Date oldDateGraph; + + CompactCalendarView calendarViewForJournal; + TextView monthTextViewJournal; + Date oldDateJournal; + + TextView overallGraphTitle; + + TextView currentExperimentTitle; + + TextView selectedGraphTitle; + GraphView selectedGraph; + + LinearLayout currentJournalLayout; + TextView todaysEntryText; + + LinearLayout selectedJournalLayout; + TextView selectedEntryText; + TextView selectedEntryTitle; + + LinearLayout experimentJournalLayout; + + JSONObject localUserData; + JSONArray currentExperimentData; + JSONArray archivedExperimentData; + + JSONArray journalArray; + + @Override public boolean onSupportNavigateUp() { finish(); @@ -50,7 +98,6 @@ public class ProgressActivity extends AppCompatActivity { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { toolbar.setNestedScrollingEnabled(false); } - //toolbar.setExpanded(false); toolbar.setActivated(false); setSupportActionBar(toolbar); Objects.requireNonNull(getSupportActionBar()).setDisplayShowHomeEnabled(true); @@ -72,25 +119,235 @@ public class ProgressActivity extends AppCompatActivity { final LinearLayout calendarView = findViewById(R.id.calendarLinLay); - generateCalendar(); - generateGraphs(); + try { + localUserData = new JSONObject(ProjectMacros.readFile(this, "localUserData.json")); + currentExperimentData = localUserData.getJSONObject("lockedExperiment").getJSONArray("UserData"); + archivedExperimentData = localUserData.getJSONArray("archivedExperimentData"); + journalArray = localUserData.getJSONArray("journal"); + } catch (JSONException e) { + e.printStackTrace(); + } + + // Setup calendarView + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + generateGraphCalendar(calendarView); + } + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MILLISECOND, 0); + + long lowest = cal.getTime().getTime(); + + try{ + if(localUserData.getBoolean("locked")) generateCurrentExperimentGraph(calendarView); + + String experimentName; + + if(currentExperimentData.length() != 0 || archivedExperimentData.length() != 0){ + List<DataPoint> dataSeries; + + if(localUserData.getBoolean("locked") && currentExperimentData.length() > 1){ + experimentName = localUserData.getJSONObject("lockedExperiment").getString("Title"); + dataSeries = loopJSONArrayForPoints(currentExperimentData, new ArrayList<DataPoint>()); + lowest = loopJSONArrayForLowest(currentExperimentData, lowest); + } else { + long highest = cal.getTime().getTime(); + int highestIndex = 0; + + for(int i = 0; i < archivedExperimentData.length(); i++){ + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(archivedExperimentData.getJSONObject(i).getString("Date").substring(0, 2))); + cal.set(Calendar.MONTH, Integer.parseInt(archivedExperimentData.getJSONObject(i).getString("Date").substring(3, 5)) - 1); + cal.set(Calendar.YEAR, Integer.parseInt(archivedExperimentData.getJSONObject(i).getString("Date").substring(6, 10))); + long calNow = cal.getTime().getTime(); + if (i == 0 || calNow >= highest) { + highest = calNow; + highestIndex = i; + } + } + experimentName = archivedExperimentData.getJSONObject(highestIndex).getString("Experiment"); + + dataSeries = arrayLoopForSelectedDateForData(archivedExperimentData, new ArrayList<DataPoint>(), experimentName); + lowest = arrayLoopForSelectedDateForLowest(archivedExperimentData, lowest, experimentName); + + oldDateGraph = new Date(highest); + final SimpleDateFormat dateFormatForMonth = new SimpleDateFormat("MMM - yyyy", Locale.getDefault()); + calendarViewForGraphs.setCurrentDate(oldDateGraph); + monthTextViewGraph.setText(dateFormatForMonth.format(calendarViewForGraphs.getFirstDayOfCurrentMonth())); + } + DataPoint[] series = new DataPoint[0]; + if (dataSeries != null) { + series = new DataPoint[dataSeries.size()]; + } + + if (dataSeries != null) { + for (int i = 0; i < dataSeries.size(); i++) series[i] = dataSeries.get(i); + } + + generateSelectedGraph(calendarView, series, lowest); + String selectedGraphString = "Experiment: " + experimentName; + selectedGraphTitle.setText(selectedGraphString); + + generateOverallGraph(calendarView); + } else { + TextView noDataMessage = new TextView(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + noDataMessage.setTextColor(getColor(R.color.colorPrimary)); + } + noDataMessage.setTextSize(30); + noDataMessage.setText(Html.fromHtml("There has been no experiment data to show yet!")); + calendarView.addView(noDataMessage); + } + } catch (JSONException e){ + e.printStackTrace(); + } + + // Setup Journal View + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + generateJournalCalendar(journalView); + journalView.addView(ProjectMacros.newHR(this, 10,"#587B7F")); + generateJournalTodaysEntry(journalView); + journalView.addView(ProjectMacros.newHR(this, 10,"#587B7F")); + generateJournalSelectedEntry(journalView); + journalView.addView(ProjectMacros.newHR(this, 10,"#587B7F")); + generateJournalExperimentEntries(journalView, ""); + } + + final FloatingActionButton journalFAB = findViewById(R.id.editCurrentJournal); + final ViewGroup coordinateLayout = findViewById(R.id.mainScreen); + + coordinateLayout.removeView(journalFAB); mainBody.removeView(journalView); + journalFAB.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + AlertDialog.Builder alert = new AlertDialog.Builder(ProgressActivity.this, R.style.AlertDialogStyle); + + alert.setTitle("Today's Journal Entry"); + alert.setMessage("Edit below"); + + // Set an EditText view to get user input + final EditText input = new EditText(ProgressActivity.this); + alert.setView(input); + final String match = "Click the pen in the bottom right to add an entry for today!"; + if(!todaysEntryText.getText().toString().equals(match)) { + input.setText(todaysEntryText.getText()); + } + + alert.setPositiveButton("Save", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + if(input.getText().toString().equals("")) { + todaysEntryText.setText(match); + try{ + JSONArray journalEntriesOut = new JSONArray(); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR, 0); + Date today = cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/YYYY", Locale.getDefault()); + + for(int i = 0; i < journalArray.length(); i++){ + if(!sdf.format(today).equals(journalArray.getJSONObject(i).getString("Date"))){ + journalEntriesOut.put(journalArray.getJSONObject(i)); + } + } + if(sdf.format(oldDateJournal).equals(sdf.format(today))){ + selectedEntryTitle.setText(Html.fromHtml(localUserData.getJSONObject("lockedExperiment").getString("Title") + " (" + sdf.format(today) + "):")); + selectedEntryText.setText(todaysEntryText.getText().toString()); + } + + localUserData.put("journal", journalEntriesOut); + ProjectMacros.saveFile(ProgressActivity.this, "localUserData.json", localUserData.toString()); + } catch (JSONException e){ + e.printStackTrace(); + } + } else{ + todaysEntryText.setText(input.getText().toString()); + try{ + JSONArray journalEntriesOut = new JSONArray(); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR, 0); + Date today = cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/YYYY", Locale.getDefault()); + + boolean todayExists = false; + + for(int i = 0; i < journalArray.length(); i++){ + if(sdf.format(today).equals(journalArray.getJSONObject(i).getString("Date"))){ + todayExists = true; + JSONObject tempObject = new JSONObject(); + tempObject.put("Date", sdf.format(today)); + tempObject.put("Experiment", localUserData.getJSONObject("lockedExperiment").getString("Title")); + tempObject.put("Entry", input.getText()); + journalEntriesOut.put(tempObject); + } else { + journalEntriesOut.put(journalArray.getJSONObject(i)); + } + } + + if(!todayExists) { + JSONObject tempObject = new JSONObject(); + tempObject.put("Date", sdf.format(today)); + tempObject.put("Experiment", localUserData.getJSONObject("lockedExperiment").getString("Title")); + tempObject.put("Entry", input.getText()); + journalEntriesOut.put(tempObject); + } + + if(sdf.format(oldDateJournal).equals(sdf.format(today))){ + selectedEntryTitle.setText(Html.fromHtml(localUserData.getJSONObject("lockedExperiment").getString("Title") + " (" + sdf.format(today) + "):")); + selectedEntryText.setText(todaysEntryText.getText().toString()); + } + + localUserData.put("journal", journalEntriesOut); + ProjectMacros.saveFile(ProgressActivity.this, "localUserData.json", localUserData.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + }}); + + alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // Canceled. + } + }); + + alert.show(); + } + }); + + // Tab layout setup, with calendarView being set as default TabLayout tabLay = findViewById(R.id.tabs); tabLay.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { switch(tab.getPosition()){ case 0: - if(mainBody.getChildAt(0) == journalView) mainBody.removeView(journalView); + if(mainBody.getChildAt(0) == journalView) { + mainBody.removeView(journalView); + coordinateLayout.removeView(journalFAB); + } if(mainBody.getChildAt(0) != calendarView) mainBody.addView(calendarView); findViewById(R.id.progressScrollObject).scrollTo(0,0); break; case 1: if(mainBody.getChildAt(0) == calendarView) mainBody.removeView(calendarView); - if(mainBody.getChildAt(0) != journalView) mainBody.addView(journalView); + if(mainBody.getChildAt(0) != journalView) { + mainBody.addView(journalView); + coordinateLayout.addView(journalFAB); + } findViewById(R.id.progressScrollObject).scrollTo(0,0); break; default: @@ -110,104 +367,680 @@ public class ProgressActivity extends AppCompatActivity { }); } - private void generateCalendar(){ + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void generateJournalExperimentEntries(LinearLayout parent, String experiment) { + if(experimentJournalLayout == null){ + experimentJournalLayout = new LinearLayout(this); + experimentJournalLayout.setOrientation(LinearLayout.VERTICAL); + + try { + + if (localUserData.getBoolean("locked")) { + for (int i = 0; i < journalArray.length(); i++) { + if (journalArray.getJSONObject(i).getString("Experiment").equals(localUserData.getJSONObject("lockedExperiment").getString("Title"))){ + LinearLayout tempLayout = new LinearLayout(this); + tempLayout.setOrientation(LinearLayout.VERTICAL); + TextView tempTitle = new TextView(this); + TextView tempEntry = new TextView(this); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(6,10))); + Date dateValue = cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY", Locale.getDefault()); + + tempTitle.setText(Html.fromHtml(journalArray.getJSONObject(i).getString("Experiment") + " (" + sdf.format(dateValue) + "):")); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + tempTitle.setTextColor(getColor(R.color.colorPrimary)); + } + tempTitle.setTextSize(20); + + tempEntry.setText(Html.fromHtml(journalArray.getJSONObject(i).getString("Entry"))); + + tempLayout.addView(tempTitle); + tempLayout.addView(tempEntry); + tempLayout.addView(ProjectMacros.newHR(this, 4, "#587B7F")); + + experimentJournalLayout.addView(tempLayout); + } + } + } + } catch(JSONException e){ + e.printStackTrace(); + } + parent.addView(experimentJournalLayout); + } else { + experimentJournalLayout.removeAllViews(); + try { + for (int i = 0; i < journalArray.length(); i++) { + if (journalArray.getJSONObject(i).getString("Experiment").equals(experiment)) { + LinearLayout tempLayout = new LinearLayout(this); + tempLayout.setOrientation(LinearLayout.VERTICAL); + TextView tempTitle = new TextView(this); + TextView tempEntry = new TextView(this); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(6,10))); + Date dateValue = cal.getTime(); + + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY", Locale.getDefault()); + + tempTitle.setText(Html.fromHtml(experiment + " (" + sdf.format(dateValue) + "):")); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + tempTitle.setTextColor(getColor(R.color.colorPrimary)); + } + tempTitle.setTextSize(20); + tempEntry.setText(Html.fromHtml(journalArray.getJSONObject(i).getString("Entry"))); + + tempLayout.addView(tempTitle); + tempLayout.addView(tempEntry); + tempLayout.addView(ProjectMacros.newHR(this, 4, "#587B7F")); + + experimentJournalLayout.addView(tempLayout); + } + } + + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void generateJournalSelectedEntry(LinearLayout parent) { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR, 0); + + Date today = cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY", Locale.getDefault()); + + if(selectedJournalLayout == null){ + selectedJournalLayout = new LinearLayout(this); + selectedJournalLayout.setOrientation(LinearLayout.VERTICAL); + selectedEntryTitle = new TextView(this); + selectedEntryTitle.setText(Html.fromHtml( "Select an entry!")); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + selectedEntryTitle.setTextColor(getColor(R.color.colorPrimary)); + } + selectedEntryTitle.setTextSize(25); + selectedJournalLayout.addView(selectedEntryTitle); + } + if(selectedEntryText == null){ + selectedEntryText = new TextView(this); + selectedEntryText.setText(Html.fromHtml("Or click the pen in the bottom right to add / edit an entry for today!")); + } + selectedJournalLayout.addView(selectedEntryText); + parent.addView(selectedJournalLayout); + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void generateJournalTodaysEntry(LinearLayout parent) { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR, 0); + + Date today = cal.getTime(); + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY", Locale.getDefault()); + + currentJournalLayout = new LinearLayout(this); + currentJournalLayout.setOrientation(LinearLayout.VERTICAL); + + TextView title = new TextView(this); + title.setText(Html.fromHtml( "Today's Entry (" + sdf.format(today) + "):")); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + title.setTextColor(getColor(R.color.colorPrimary)); + } + title.setTextSize(25); + currentJournalLayout.addView(title); + + if(todaysEntryText == null){ + todaysEntryText = new TextView(this); + + try{ + + boolean entryToday = false; + int entryIndex = 0; + + sdf = new SimpleDateFormat("dd/MM/YYYY", Locale.getDefault()); + + for(int i = 0; i < journalArray.length(); i++){ + if(sdf.format(today).equals(journalArray.getJSONObject(i).getString("Date"))){ + entryToday = true; + entryIndex = i; + } + } + + if(entryToday){ + todaysEntryText.setText(journalArray.getJSONObject(entryIndex).getString("Entry")); + } else { + todaysEntryText.setText(Html.fromHtml("Click the pen in the bottom right to add an entry for today!")); + } + + + } catch (JSONException e) { + e.printStackTrace(); + } + } + currentJournalLayout.addView(todaysEntryText); + parent.addView(currentJournalLayout); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void generateJournalCalendar(final LinearLayout parent) { + calendarViewForJournal = findViewById(R.id.compactCalendarJournal); + calendarViewForJournal.setFirstDayOfWeek(Calendar.MONDAY); + final SimpleDateFormat dateFormatForMonth = new SimpleDateFormat("MMM - yyyy", Locale.getDefault()); + final String[] Month = {dateFormatForMonth.format(calendarViewForJournal.getFirstDayOfCurrentMonth())}; + + monthTextViewJournal = new TextView(this); + monthTextViewJournal.setTextColor(getColor(R.color.colorPrimary)); + monthTextViewJournal.setTextSize(35); + monthTextViewJournal.setText(Month[0]); + parent.addView(monthTextViewJournal, 0); + + try{ + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + final String[] markColor = {"#8FFF0000","#8F0A8F0F","#8F0000FF"}; + int markColorIndex = 0; + String oldExperiment = ""; + + for(int i = 0; i < journalArray.length(); i++){ + if(i == 0) oldExperiment = journalArray.getJSONObject(i).getString("Experiment"); + + if(!journalArray.getJSONObject(i).getString("Experiment").equals(oldExperiment)){ + markColorIndex++; + oldExperiment = journalArray.getJSONObject(i).getString("Experiment"); + } + + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(journalArray.getJSONObject(i).getString("Date").substring(6,10))); + + if(Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == cal.get(Calendar.DAY_OF_MONTH) + && Calendar.getInstance().get(Calendar.MONTH) == cal.get(Calendar.MONTH) + && Calendar.getInstance().get(Calendar.YEAR) == cal.get(Calendar.YEAR)){ + calendarViewForJournal.setCurrentDayBackgroundColor(Color.parseColor(markColor[markColorIndex%3])); + } + calendarViewForJournal.addEvent(new Event(Color.parseColor(markColor[markColorIndex%3]), cal.getTimeInMillis(), journalArray.getJSONObject(i).getString("Experiment"))); + } + } catch (JSONException e){ + e.printStackTrace(); + } + + calendarViewForJournal.setListener(new CompactCalendarView.CompactCalendarViewListener() { + @Override + public void onDayClick(Date dateClicked) { + calendarViewForJournal.setCurrentSelectedDayBackgroundColor(getColor(R.color.colorPrimary)); + + if(calendarViewForJournal.getEvents(dateClicked).size() == 0){ + ProjectMacros.showToast(progressToast, ProgressActivity.this, "Cannot select a date without data!"); + calendarViewForJournal.setCurrentDate(oldDateGraph); + Month[0] = dateFormatForMonth.format(calendarViewForJournal.getFirstDayOfCurrentMonth()); + monthTextViewJournal.setText(Month[0]); + } else { + oldDateJournal = dateClicked; + Month[0] = dateFormatForMonth.format(calendarViewForJournal.getFirstDayOfCurrentMonth()); + monthTextViewJournal.setText(Month[0]); - final CompactCalendarView compactCalendarView = (CompactCalendarView) findViewById(R.id.compactcalendar_view); - // Set first day of week to Monday, defaults to Monday so calling setFirstDayOfWeek is not necessary - // Use constants provided by Java Calendar class - compactCalendarView.setFirstDayOfWeek(Calendar.MONDAY); + try { + + String experimentName = ""; + + for (int i = 0; i < journalArray.length(); i++) { + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/YYYY", Locale.getDefault()); + if (journalArray.getJSONObject(i).getString("Date").equals(sdf.format(dateClicked))) { + selectedEntryText.setText(journalArray.getJSONObject(i).getString("Entry")); + + sdf = new SimpleDateFormat("MM/dd/YYYY", Locale.getDefault()); + String entryTitle = journalArray.getJSONObject(i).getString("Experiment") + " (" + sdf.format(dateClicked) + "):"; + selectedEntryTitle.setText(entryTitle); + experimentName = journalArray.getJSONObject(i).getString("Experiment"); + } + } + generateJournalExperimentEntries(parent, experimentName); + + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onMonthScroll(Date firstDayOfNewMonth) { + Calendar calCheck = Calendar.getInstance(); + calCheck.setTime(firstDayOfNewMonth); + Calendar calCheck2 = Calendar.getInstance(); + calCheck2.setTime(oldDateJournal); + if(calCheck.get(Calendar.MONTH) == calCheck2.get(Calendar.MONTH)){ + calendarViewForJournal.setCurrentDate(oldDateJournal); + calendarViewForJournal.setCurrentSelectedDayBackgroundColor(getColor(R.color.colorPrimary)); + } else{ + calendarViewForJournal.setCurrentSelectedDayBackgroundColor(Color.TRANSPARENT); + } + + Month[0] = dateFormatForMonth.format(calendarViewForJournal.getFirstDayOfCurrentMonth()); + monthTextViewJournal.setText(Month[0]); + } + }); + oldDateJournal = Calendar.getInstance().getTime(); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void generateGraphCalendar(final LinearLayout parent){ + calendarViewForGraphs = findViewById(R.id.compactCalendarGraph); + calendarViewForGraphs.setFirstDayOfWeek(Calendar.MONDAY); final SimpleDateFormat dateFormatForMonth = new SimpleDateFormat("MMM - yyyy", Locale.getDefault()); - final String[] Month = {dateFormatForMonth.format(compactCalendarView.getFirstDayOfCurrentMonth())}; - final TextView monthTextView = new TextView(this); - monthTextView.setTextColor(getColor(R.color.colorPrimary)); - monthTextView.setTextSize(35); - monthTextView.setText(Month[0]); - calendarView.addView(monthTextView, 0); - - // Add event 1 on Sun, 07 Jun 2015 18:20:51 GMT - Event ev1 = new Event(Color.GREEN, 1583754563000L, "Some extra data that I want to store."); - compactCalendarView.addEvent(ev1); - - // Added event 2 GMT: Sun, 07 Jun 2015 19:10:51 GMT - Event ev2 = new Event(Color.RED, 1583581763000L); - compactCalendarView.addEvent(ev2); - - // Query for events on Sun, 07 Jun 2015 GMT. - // Time is not relevant when querying for events, since events are returned by day. - // So you can pass in any arbitary DateTime and you will receive all events for that day. - List<Event> events = compactCalendarView.getEvents(1583754563000L); // can also take a Date object - - // events has size 2 with the 2 events inserted previously - d("dbg", "Events: " + events); - - // define a listener to receive callbacks when certain events happen. - compactCalendarView.setListener(new CompactCalendarView.CompactCalendarViewListener() { + final String[] Month = {dateFormatForMonth.format(calendarViewForGraphs.getFirstDayOfCurrentMonth())}; + + monthTextViewGraph = new TextView(this); + monthTextViewGraph.setTextColor(getColor(R.color.colorPrimary)); + monthTextViewGraph.setTextSize(35); + monthTextViewGraph.setText(Month[0]); + parent.addView(monthTextViewGraph, 0); + parent.addView(ProjectMacros.newHR(this, 10, "#587B7F")); + + try { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + final String[] markColor = {"#8FFF0000","#8F0A8F0F","#8F0000FF"}; + int markColorIndex = 0; + String oldExperiment = ""; + + for(int i = 0; i < archivedExperimentData.length(); i++){ + if(i == 0) oldExperiment = archivedExperimentData.getJSONObject(i).getString("Experiment"); + + if(!archivedExperimentData.getJSONObject(i).getString("Experiment").equals(oldExperiment)){ + markColorIndex++; + oldExperiment = archivedExperimentData.getJSONObject(i).getString("Experiment"); + } + + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(archivedExperimentData.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(archivedExperimentData.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(archivedExperimentData.getJSONObject(i).getString("Date").substring(6,10))); + + if(Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == cal.get(Calendar.DAY_OF_MONTH) + && Calendar.getInstance().get(Calendar.MONTH) == cal.get(Calendar.MONTH) + && Calendar.getInstance().get(Calendar.YEAR) == cal.get(Calendar.YEAR)){ + calendarViewForGraphs.setCurrentDayBackgroundColor(Color.parseColor(markColor[markColorIndex%3])); + } + calendarViewForGraphs.addEvent(new Event(Color.parseColor(markColor[markColorIndex%3]), cal.getTimeInMillis(), archivedExperimentData.getJSONObject(i).getString("Experiment"))); + } + + markColorIndex++; + + for(int i = 0; i < currentExperimentData.length(); i++){ + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(currentExperimentData.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(currentExperimentData.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(currentExperimentData.getJSONObject(i).getString("Date").substring(6,10))); + + if(Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == cal.get(Calendar.DAY_OF_MONTH) + && Calendar.getInstance().get(Calendar.MONTH) == cal.get(Calendar.MONTH) + && Calendar.getInstance().get(Calendar.YEAR) == cal.get(Calendar.YEAR)){ + calendarViewForGraphs.setCurrentDayBackgroundColor(Color.parseColor(markColor[markColorIndex%3])); + } + calendarViewForGraphs.addEvent(new Event(Color.parseColor(markColor[markColorIndex%3]), cal.getTimeInMillis())); + } + + calendarViewForGraphs.setListener(new CompactCalendarView.CompactCalendarViewListener() { @Override public void onDayClick(Date dateClicked) { - List<Event> events = compactCalendarView.getEvents(dateClicked); - d("dbg", "Day was clicked: " + dateClicked + " with events " + events); + calendarViewForGraphs.setCurrentSelectedDayBackgroundColor(getColor(R.color.colorPrimary)); + if(calendarViewForGraphs.getEvents(dateClicked).size() == 0){ + ProjectMacros.showToast(progressToast, ProgressActivity.this, "Cannot select a date without data!"); + + calendarViewForGraphs.setCurrentDate(oldDateGraph); + Month[0] = dateFormatForMonth.format(calendarViewForGraphs.getFirstDayOfCurrentMonth()); + monthTextViewGraph.setText(Month[0]); + } else { + oldDateGraph = dateClicked; + Month[0] = dateFormatForMonth.format(calendarViewForGraphs.getFirstDayOfCurrentMonth()); + monthTextViewGraph.setText(Month[0]); + + long lowest = 0; + + try { + List<DataPoint> dataSeries; + String experimentName; + + if(calendarViewForGraphs.getEvents(dateClicked).get(0).getData() != null){ + experimentName = (String) calendarViewForGraphs.getEvents(dateClicked).get(0).getData(); + dataSeries = arrayLoopForSelectedDateForData(archivedExperimentData, new ArrayList<DataPoint>(), experimentName); + lowest = arrayLoopForSelectedDateForLowest(archivedExperimentData, lowest, experimentName); + } else { + experimentName = localUserData.getJSONObject("lockedExperiment").getString("Title"); + dataSeries = loopJSONArrayForPoints(currentExperimentData, new ArrayList<DataPoint>()); + lowest = loopJSONArrayForLowest(currentExperimentData, lowest); + } + + DataPoint[] series = new DataPoint[0]; + if (dataSeries != null) { + series = new DataPoint[dataSeries.size()]; + } + if (dataSeries != null) { + for (int i = 0; i < dataSeries.size(); i++) { + series[i] = dataSeries.get(i); + } + } + + generateSelectedGraph(parent, series, lowest); + + String graphTitleString = "Experiment: " + experimentName; + selectedGraphTitle.setText(graphTitleString); + } catch(JSONException e){ + e.printStackTrace(); + } + } } @Override public void onMonthScroll(Date firstDayOfNewMonth) { - Month[0] = dateFormatForMonth.format(compactCalendarView.getFirstDayOfCurrentMonth()); - monthTextView.setText(Month[0]); - d("dbg", "Month was scrolled to: " + firstDayOfNewMonth); + Calendar calCheck = Calendar.getInstance(); + calCheck.setTime(firstDayOfNewMonth); + Calendar calCheck2 = Calendar.getInstance(); + calCheck2.setTime(oldDateGraph); + if(calCheck.get(Calendar.MONTH) == calCheck2.get(Calendar.MONTH)){ + calendarViewForGraphs.setCurrentDate(oldDateGraph); + calendarViewForGraphs.setCurrentSelectedDayBackgroundColor(getColor(R.color.colorPrimary)); + } else{ + calendarViewForGraphs.setCurrentSelectedDayBackgroundColor(Color.TRANSPARENT); + } + + Month[0] = dateFormatForMonth.format(calendarViewForGraphs.getFirstDayOfCurrentMonth()); + monthTextViewGraph.setText(Month[0]); } }); + + } catch (JSONException e) { + e.printStackTrace(); + } } - private void generateGraphs(){ - final LinearLayout calendarView = findViewById(R.id.calendarLinLay); - calendarView.addView(ProjectMacros.newHR(this, 10, "#587B7F")); + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void generateSelectedGraph(LinearLayout parent, DataPoint[] series, long lowest){ + if(selectedGraph == null) { + selectedGraphTitle = new TextView(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + selectedGraphTitle.setTextColor(getColor(R.color.colorPrimary)); + } + selectedGraphTitle.setTextSize(30); + selectedGraphTitle.setText(Html.fromHtml("Selected Experiment")); + parent.addView(selectedGraphTitle); - TextView graphTitle = new TextView(this); - graphTitle.setTextColor(getColor(R.color.colorPrimary)); - graphTitle.setTextSize(30); - graphTitle.setText(Html.fromHtml("Current Experiment Progress")); - calendarView.addView(graphTitle); + selectedGraph = new GraphView(this); + selectedGraph.setMinimumHeight(300); + parent.addView(selectedGraph); + parent.addView(ProjectMacros.newHR(this, 4, "#587B7F")); + } else { + selectedGraph.removeAllSeries(); + } + LineGraphSeries<DataPoint> series1 = new LineGraphSeries< >(series); + PointsGraphSeries<DataPoint> series2 = new PointsGraphSeries<>(series); + + series2.setCustomShape(new PointsGraphSeries.CustomShape() { + @Override + public void draw(Canvas canvas, Paint paint, float x, float y, DataPointInterface dataPoint) { + paint.setStrokeWidth(7); + canvas.drawLine(x-15, y-15, x+15, y+15, paint); + canvas.drawLine(x+15, y-15, x-15, y+15, paint); + } + }); - GraphView currentExperiment = new GraphView(this); - currentExperiment.setMinimumHeight(300); - calendarView.addView(currentExperiment); + selectedGraph.addSeries(series1); + selectedGraph.addSeries(series2); - calendarView.addView(ProjectMacros.newHR(this, 4, "#587B7F")); + graphSettings(selectedGraph, lowest, 4); + } - final Calendar calendar = Calendar.getInstance(); - Date d1 = calendar.getTime(); - calendar.add(Calendar.DATE, -1); - Date d2 = calendar.getTime(); - calendar.add(Calendar.DATE, -2); - Date d3 = calendar.getTime(); + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void generateCurrentExperimentGraph(LinearLayout parent){ + currentExperimentTitle = new TextView(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + currentExperimentTitle.setTextColor(getColor(R.color.colorPrimary)); + } + currentExperimentTitle.setTextSize(30); + parent.addView(currentExperimentTitle); - calendar.add(Calendar.DATE, -10); - Date d4 = calendar.getTime(); + GraphView selectedExperimentGraph = new GraphView(this); + selectedExperimentGraph.setMinimumHeight(300); + parent.addView(selectedExperimentGraph); + selectedExperimentGraph.removeAllSeries(); + + parent.addView(ProjectMacros.newHR(this, 4, "#587B7F")); + + long lowest = 0; try { - LineGraphSeries <DataPoint> series1 = new LineGraphSeries< >(new DataPoint[] { - new DataPoint(d3, 1), - new DataPoint(d2, 5), - new DataPoint(d1, 3) - }); - currentExperiment.addSeries(series1); - PointsGraphSeries<DataPoint> series2 = new PointsGraphSeries< >(new DataPoint[] { - new DataPoint(d3, 1), - new DataPoint(d2, 5), - new DataPoint(d1, 3) + currentExperimentTitle.setText(Html.fromHtml("Current Experiment: " + localUserData.getJSONObject("lockedExperiment").getString("Title"))); + + DataPoint[] dataSeries; + + dataSeries = loopJSONArrayForPoints(currentExperimentData, new DataPoint[currentExperimentData.length()], 0); + lowest = loopJSONArrayForLowest(currentExperimentData, lowest); + + LineGraphSeries <DataPoint> series1 = new LineGraphSeries< >(dataSeries); + PointsGraphSeries <DataPoint> series2 = new PointsGraphSeries<>(dataSeries); + series2.setCustomShape(new PointsGraphSeries.CustomShape() { + @Override + public void draw(Canvas canvas, Paint paint, float x, float y, DataPointInterface dataPoint) { + paint.setStrokeWidth(7); + canvas.drawLine(x-15, y-15, x+15, y+15, paint); + canvas.drawLine(x+15, y-15, x-15, y+15, paint); + } }); - currentExperiment.addSeries(series2); - } catch (IllegalArgumentException e) { + + if(dataSeries.length == 0) selectedExperimentGraph.setTitle("No data! Answer a survey to display data!"); + selectedExperimentGraph.addSeries(series1); + selectedExperimentGraph.addSeries(series2); + } catch (JSONException e) { + e.printStackTrace(); + } + graphSettings(selectedExperimentGraph, lowest, 4); + + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void generateOverallGraph(LinearLayout parent){ + overallGraphTitle = new TextView(this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + overallGraphTitle.setTextColor(getColor(R.color.colorPrimary)); + } + overallGraphTitle.setTextSize(30); + overallGraphTitle.setText(Html.fromHtml("Overall Progress")); + parent.addView(overallGraphTitle); + + GraphView overallGraph = new GraphView(this); + overallGraph.setMinimumHeight(300); + parent.addView(overallGraph); + + parent.addView(ProjectMacros.newHR(this, 4, "#587B7F")); + + long lowest = 0; + + DataPoint[] dataSeries; + + dataSeries = loopJSONArrayForPoints(archivedExperimentData, new DataPoint[currentExperimentData.length() + archivedExperimentData.length()], 0); + lowest = loopJSONArrayForLowest(archivedExperimentData, lowest); + + //noinspection ConstantConditions + dataSeries = loopJSONArrayForPoints(currentExperimentData, dataSeries, archivedExperimentData.length()); + lowest = loopJSONArrayForLowest(currentExperimentData, lowest); + + LineGraphSeries <DataPoint> series1 = new LineGraphSeries< >(dataSeries); + PointsGraphSeries <DataPoint> series2 = new PointsGraphSeries<>(dataSeries); + series2.setCustomShape(new PointsGraphSeries.CustomShape() { + @Override + public void draw(Canvas canvas, Paint paint, float x, float y, DataPointInterface dataPoint) { + paint.setStrokeWidth(7); + canvas.drawLine(x-15, y-15, x+15, y+15, paint); + canvas.drawLine(x+15, y-15, x-15, y+15, paint); + } + }); + overallGraph.addSeries(series1); + overallGraph.addSeries(series2); + + graphSettings(overallGraph, lowest, 14); + overallGraph.getViewport().scrollToEnd(); + } + + private DataPoint[] loopJSONArrayForPoints(JSONArray array, DataPoint[] dataSeries, int offset){ + try{ + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + for(int i = 0; i < array.length(); i++){ + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(6,10))); + + Date tempDate = cal.getTime(); + dataSeries[i + offset] = new DataPoint(tempDate, Double.parseDouble(array.getJSONObject(i).getString("AverageResult"))); + } + } catch (JSONException e){ + e.printStackTrace(); + } + return dataSeries; + } + + private List<DataPoint> loopJSONArrayForPoints(JSONArray array, List<DataPoint> dataSeries){ + try{ + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + for(int i = 0; i < array.length(); i++){ + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(6,10))); + + Date tempDate = cal.getTime(); + dataSeries.add(new DataPoint(tempDate, Double.parseDouble(array.getJSONObject(i).getString("AverageResult")))); + } + } catch (JSONException e){ e.printStackTrace(); } + return dataSeries; + } + + private long loopJSONArrayForLowest(JSONArray array, long lowest){ + try{ + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + if(lowest == 0){ + lowest = cal.getTime().getTime(); + } + + for(int i = 0; i < array.length(); i++){ + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(6,10))); + + long calNow = cal.getTime().getTime(); + if (i == 0 || calNow <= lowest) lowest = calNow; + } + return lowest; + } catch (JSONException e){ + e.printStackTrace(); + return 0; + } + } + + private void graphSettings(GraphView graph, long lowest, int dayRange){ + graph.getGridLabelRenderer().setLabelFormatter(new DateAsXAxisLabelFormatter(this)); + graph.getGridLabelRenderer().setNumHorizontalLabels(5); + + graph.getViewport().setMaxY(5); + graph.getViewport().setMinY(0); + graph.getViewport().setYAxisBoundsManual(true); - currentExperiment.getGridLabelRenderer().setLabelFormatter(new DateAsXAxisLabelFormatter(this)); - currentExperiment.getGridLabelRenderer().setNumHorizontalLabels(3); - currentExperiment.getViewport().setMinX(d4.getTime()); - currentExperiment.getViewport().setMaxX(d1.getTime()); - currentExperiment.getViewport().setXAxisBoundsManual(false); - currentExperiment.getGridLabelRenderer().setHumanRounding(false); - currentExperiment.getViewport().setScalableY(true); + graph.getViewport().setMinX(lowest-2500); + graph.getViewport().setScalable(false); + graph.getViewport().setScrollable(true); + graph.getViewport().setMaxX(lowest+dayRange*24*60*60*1000+2500); + graph.getViewport().setXAxisBoundsManual(true); + graph.getGridLabelRenderer().setHumanRounding(false); } + + private List<DataPoint> arrayLoopForSelectedDateForData(JSONArray array, List<DataPoint> dataSeries, String match){ + try{ + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + for (int i = 0; i < array.length(); i++) { + if (match.equals(array.getJSONObject(i).getString("Experiment"))) { + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(6,10))); + + Date tempDate = cal.getTime(); + dataSeries.add(new DataPoint(tempDate, Double.parseDouble(array.getJSONObject(i).getString("AverageResult")))); + } + } + return dataSeries; + } catch (JSONException e){ + e.printStackTrace(); + return null; + } + } + + private long arrayLoopForSelectedDateForLowest(@NonNull JSONArray array, long lowest, String match){ + try{ + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.HOUR, 0); + + int addedIndex = 0; + + for (int i = 0; i < array.length(); i++) { + if (match.equals(array.getJSONObject(i).getString("Experiment"))) { + cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(0,2))); + cal.set(Calendar.MONTH, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(3,5))-1); + cal.set(Calendar.YEAR, Integer.parseInt(array.getJSONObject(i).getString("Date").substring(6,10))); + + long calNow = cal.getTime().getTime(); + if (addedIndex++ == 0 || calNow <= lowest) lowest = calNow; + } + } + return lowest; + } catch (JSONException e){ + e.printStackTrace(); + return 0; + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/yearthreeproject/xbframework/TestingActivity.java b/app/src/main/java/com/yearthreeproject/xbframework/TestingActivity.java index e4bddab4490f910c7960c8ea4dfe70de88d6b49f..7428fa28c179c7571d82735d47b352eb7ffb052c 100644 --- a/app/src/main/java/com/yearthreeproject/xbframework/TestingActivity.java +++ b/app/src/main/java/com/yearthreeproject/xbframework/TestingActivity.java @@ -136,6 +136,16 @@ public class TestingActivity extends AppCompatActivity { ProjectMacros.createNotification("Test Notification", "This is a test notification for the notification system!", R.raw.box_outline, "ALL_CHANNEL", TestingActivity.this, timeNowOffset, repeatTime); } }); + + Button fourthTestButton = new Button(this); + buttonHolder.addView(fourthTestButton); + fourthTestButton.setText(Html.fromHtml("Launch login page")); + fourthTestButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(TestingActivity.this, LoginActivity.class)); + } + }); } @RequiresApi(api = Build.VERSION_CODES.N) diff --git a/app/src/main/res/layout/content_login.xml b/app/src/main/res/layout/content_login.xml index 597dad6b712b57fa00eedeeaace4c12af41f634e..951f69848a9b1dfc0c897ab48c3f9acae7ecf3ce 100644 --- a/app/src/main/res/layout/content_login.xml +++ b/app/src/main/res/layout/content_login.xml @@ -30,6 +30,7 @@ android:text="@string/login_email" /> <EditText + android:id="@+id/EmailEditText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" @@ -52,13 +53,14 @@ android:text="@string/login_password" /> <EditText + android:id="@+id/PasswordEditText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:ems="10" android:hint="@string/login_password_hint" android:inputType="textPassword" - tools:ignore="Autofill"/> + tools:ignore="Autofill" /> </LinearLayout> diff --git a/app/src/main/res/layout/content_progress.xml b/app/src/main/res/layout/content_progress.xml index 1ad3c4217d60ea04706583d8db8ebb3700eac3a2..ca4e616a75ccb46200f1d8ffa1ac8a6caacef559 100644 --- a/app/src/main/res/layout/content_progress.xml +++ b/app/src/main/res/layout/content_progress.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/mainScreen" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ProgressActivity" @@ -27,12 +28,12 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"/> + android:orientation="horizontal" /> <ScrollView android:id="@+id/progressScrollObject" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="0dp" android:layout_weight="1"> <LinearLayout @@ -40,38 +41,65 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> - <LinearLayout - android:id="@+id/calendarLinLay" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - <com.github.sundeepk.compactcalendarview.CompactCalendarView xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/compactcalendar_view" - android:layout_width="fill_parent" - android:paddingRight="10dp" - android:paddingLeft="10dp" - android:layout_height="250dp" - app:compactCalendarTargetHeight="250dp" - app:compactCalendarTextSize="12sp" - app:compactCalendarBackgroundColor="@color/calendarBackground" - app:compactCalendarTextColor="@color/colorPrimaryDark" - app:compactCalendarCurrentSelectedDayBackgroundColor="@color/colorPrimary" - app:compactCalendarCurrentDayBackgroundColor="@color/colorPrimary" - app:compactCalendarMultiEventIndicatorColor="@color/colorAccent" /> - </LinearLayout> + <LinearLayout + android:id="@+id/calendarLinLay" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> - <LinearLayout - android:id="@+id/progressJournal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> + <com.github.sundeepk.compactcalendarview.CompactCalendarView xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/compactCalendarGraph" + android:layout_width="fill_parent" + android:layout_height="250dp" + android:paddingLeft="10dp" + android:paddingRight="10dp" + app:compactCalendarBackgroundColor="@color/calendarBackground" + app:compactCalendarCurrentDayBackgroundColor="#8F587B7F" + app:compactCalendarCurrentSelectedDayBackgroundColor="@color/colorPrimary" + app:compactCalendarMultiEventIndicatorColor="@color/colorAccent" + app:compactCalendarTargetHeight="250dp" + app:compactCalendarTextColor="@color/colorPrimaryDark" + app:compactCalendarTextSize="12sp" /> + </LinearLayout> - </LinearLayout> + <LinearLayout + android:id="@+id/progressJournal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <com.github.sundeepk.compactcalendarview.CompactCalendarView xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/compactCalendarJournal" + android:layout_width="fill_parent" + android:layout_height="250dp" + android:paddingLeft="10dp" + android:paddingRight="10dp" + app:compactCalendarBackgroundColor="@color/calendarBackground" + app:compactCalendarCurrentDayBackgroundColor="#8F587B7F" + app:compactCalendarCurrentSelectedDayBackgroundColor="@color/colorPrimary" + app:compactCalendarMultiEventIndicatorColor="@color/colorAccent" + app:compactCalendarTargetHeight="250dp" + app:compactCalendarTextColor="@color/colorPrimaryDark" + app:compactCalendarTextSize="12sp" /> + + </LinearLayout> </LinearLayout> </ScrollView> </LinearLayout> </androidx.core.widget.NestedScrollView> + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/editCurrentJournal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|right|end" + android:clickable="true" + app:backgroundTint="@color/colorPrimary" + app:fabCustomSize="100dp" + app:fabSize="normal" + app:maxImageSize="75dp" + app:srcCompat="@android:drawable/ic_menu_edit" /> + </androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/app/src/main/res/raw/local_user_data.json b/app/src/main/res/raw/local_user_data.json new file mode 100644 index 0000000000000000000000000000000000000000..67dbdec850df813c3df871a1270a8c4d7a994679 --- /dev/null +++ b/app/src/main/res/raw/local_user_data.json @@ -0,0 +1,142 @@ +{ + "dateUntil":"22\/03\/2020", + "savedUserID":"A01", + "locked":true, + "lockedExperiment":{ + "Title":"Sunlight", + "Instructions":"Get 30 to 45 minutes of sunlight a day. Make sure your room captures sunlight.", + "Description":"This will boost circadian rhythm.", + "VideoProcessing":true, + "AudioProcessing":true, + "ImageProcessing":true, + "SurveyQuestions":[ + "Test question 1", + "Test question 2"], + "Notification":[{ + "Title":"Test notification!", + "Message":"Testing Notification for all the cool abilities that it can run, should I allow another thing upload? No, I don't care enough tbh...", + "Time":"18:10", + "Repeat":"00:01 hours" + }], + "ArtefactImplementation":true, + "UserData": [{ + "Date": "22\/03\/2020", + "AverageResult": "1.5", + "Experiment": "Test", + "Type": "Eat" + }] + }, + "journal": [{ + "Date": "04\/03\/2020", + "Entry": "This is a text entry for this result!1", + "Experiment": "Sleep" + },{ + "Date": "05\/03\/2020", + "Entry": "This is a text entry for this result!2", + "Experiment": "Sleep" + },{ + "Date": "06\/03\/2020", + "Entry": "This is a text entry for this result!3", + "Experiment": "Sleep" + },{ + "Date": "07\/03\/2020", + "Entry": "This is a text entry for this result!4", + "Experiment": "Sleep" + },{ + "Date": "08\/03\/2020", + "Entry": "This is a text entry for this result!5", + "Experiment": "Sleep" + },{ + "Date": "20\/03\/2020", + "Entry": "This is a text entry for this result!6", + "Experiment": "Sunlight" + },{ + "Date": "21\/03\/2020", + "Entry": "This is a text entry for this result!7", + "Experiment": "Sunlight" + },{ + "Date": "22\/03\/2020", + "Entry": "This is a text entry for this result!8", + "Experiment": "Sunlight" + },{ + "Date": "23\/03\/2020", + "Entry": "This is a text entry for this result!9", + "Experiment": "Sunlight" + }], + "archivedExperimentData": [{ + "Date": "05\/01\/2020", + "AverageResult": "2", + "Experiment": "SleepBox", + "Type": "Sleep" + }, { + "Date": "06\/01\/2020", + "AverageResult": "1.5", + "Experiment": "SleepBox", + "Type": "Sleep" + }, { + "Date": "07\/01\/2020", + "AverageResult": "5", + "Experiment": "SleepBox", + "Type": "Sleep" + }, { + "Date": "08\/01\/2020", + "AverageResult": "1.5", + "Experiment": "SleepBox", + "Type": "Sleep" + }, { + "Date": "09\/01\/2020", + "AverageResult": "1.5", + "Experiment": "SleepBox", + "Type": "Sleep" + }, { + "Date": "12\/01\/2020", + "AverageResult": "0.5", + "Experiment": "SleepBoxV2", + "Type": "Sleep" + }, { + "Date": "13\/01\/2020", + "AverageResult": "2.5", + "Experiment": "SleepBoxV2", + "Type": "Sleep" + }, { + "Date": "14\/01\/2020", + "AverageResult": "0", + "Experiment": "SleepBoxV2", + "Type": "Sleep" + }, { + "Date": "15\/01\/2020", + "AverageResult": "4.5", + "Experiment": "SleepBoxV2", + "Type": "Sleep" + }, { + "Date": "16\/01\/2020", + "AverageResult": "5", + "Experiment": "SleepBoxV2", + "Type": "Sleep" + }, { + "Date": "17\/03\/2020", + "AverageResult": "4", + "Experiment": "Sunlight", + "Type": "Sleep" + }, { + "Date": "18\/03\/2020", + "AverageResult": "3.5", + "Experiment": "Sunlight", + "Type": "Sleep" + }, { + "Date": "19\/03\/2020", + "AverageResult": "2.5", + "Experiment": "Sunlight", + "Type": "Sleep" + }, { + "Date": "20\/03\/2020", + "AverageResult": "1", + "Experiment": "Sunlight", + "Type": "Sleep" + }, { + "Date": "21\/03\/2020", + "AverageResult": "5", + "Experiment": "Sunlight", + "Type": "Sleep" + }] +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4bbe6d3a46af5a8c331eaa5507f36a31baec5078..05cec78fa7e486ca7f201a9830e1311907f035d4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,4 +53,9 @@ <string name="NewBoxImageLabel">Image:</string> <string name="NewBoxWarningLabel">Warning:</string> + <!-- Auth0 strings --> + <string name="com_auth0_client_id">srMEu3hqB26sHtiaIdr9uvYQmwOktLnK</string> + <string name="com_auth0_domain">eamonn-backend-oauth.eu.auth0.com</string> + <string name="auth0_scheme">https</string> + </resources> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 073dade0d9e9224407c384008274692397d36835..bfbc53a203d4fb2ddfbaa295aae8d9b133bc1fb4 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<resources> +<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> @@ -7,8 +7,14 @@ <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> - <item name="android:navigationBarColor">@color/colorAccent</item> - <item name="android:windowLightNavigationBar">true</item> + <item name="android:navigationBarColor" tools:targetApi="lollipop">@color/colorAccent</item> + <item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item> + </style> + + <style name="AlertDialogStyle" parent="Theme.AppCompat.Light.Dialog"> + <item name="android:colorAccent" tools:targetApi="lollipop">@color/colorAccent</item> + <item name="android:textColor">@color/colorPrimary</item> + <item name="android:textColorPrimary">@color/colorPrimary</item> </style> <style name="AppTheme.NoActionBar">