Java tutorial
/* * Calendula - An assistant for personal medication management. * Copyright (C) 2016 CITIUS - USC * * Calendula is free software; you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software. If not, see <http://www.gnu.org/licenses/>. */ package es.usc.citius.servando.calendula.activities; import android.app.ProgressDialog; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; import com.getbase.floatingactionbutton.FloatingActionButton; import com.google.gson.Gson; import com.j256.ormlite.misc.TransactionManager; import org.joda.time.DateTime; import org.joda.time.LocalTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import es.usc.citius.servando.calendula.CalendulaActivity; import es.usc.citius.servando.calendula.CalendulaApp; import es.usc.citius.servando.calendula.R; import es.usc.citius.servando.calendula.activities.qrWrappers.PickupWrapper; import es.usc.citius.servando.calendula.activities.qrWrappers.PrescriptionListWrapper; import es.usc.citius.servando.calendula.activities.qrWrappers.PrescriptionWrapper; import es.usc.citius.servando.calendula.database.DB; import es.usc.citius.servando.calendula.events.PersistenceEvents; import es.usc.citius.servando.calendula.fragments.ScheduleConfirmationEndFragment; import es.usc.citius.servando.calendula.fragments.ScheduleConfirmationStartFragment; import es.usc.citius.servando.calendula.fragments.ScheduleImportFragment; import es.usc.citius.servando.calendula.persistence.DailyScheduleItem; import es.usc.citius.servando.calendula.persistence.HomogeneousGroup; import es.usc.citius.servando.calendula.persistence.Medicine; import es.usc.citius.servando.calendula.persistence.Patient; import es.usc.citius.servando.calendula.persistence.PickupInfo; import es.usc.citius.servando.calendula.persistence.Prescription; import es.usc.citius.servando.calendula.persistence.Presentation; import es.usc.citius.servando.calendula.persistence.Schedule; import es.usc.citius.servando.calendula.persistence.ScheduleItem; import es.usc.citius.servando.calendula.scheduling.AlarmScheduler; import es.usc.citius.servando.calendula.scheduling.DailyAgenda; import es.usc.citius.servando.calendula.util.FragmentUtils; import es.usc.citius.servando.calendula.util.ScreenUtils; import es.usc.citius.servando.calendula.util.Snack; import es.usc.citius.servando.calendula.util.Strings; public class ConfirmSchedulesActivity extends CalendulaActivity implements ViewPager.OnPageChangeListener { private static final String TAG = "ConfirmSchedules.class"; /** * The {@link android.support.v4.view.PagerAdapter} that will provide * fragments for each of the sections. We use a * {@link FragmentPagerAdapter} derivative, which will keep every * loaded fragment in memory. If this becomes too memory intensive, it * may be best to switch to a * {@link android.support.v4.app.FragmentStatePagerAdapter}. */ SectionsPagerAdapter mSectionsPagerAdapter; /** * The {@link ViewPager} that will host the section contents. */ ViewPager mViewPager; List<PrescriptionWrapper> prescriptionList; int scheduleCount; FloatingActionButton fab; TextView medName; TextView title; ImageButton routinesItem; ImageButton hourlyItem; ImageButton cycleItem; View scheduleTypeSelector; View readingQrBox; DateTimeFormatter df = DateTimeFormat.forPattern("yyMMdd"); private String qrData; private Patient patient; int color; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_confirm_schedules); patient = DB.patients().getActive(this); color = patient.color(); int dark = ScreenUtils.equivalentNoAlpha(color, Color.BLACK, 0.85f); findViewById(R.id.activity_layout).setBackgroundColor(dark); setupToolbar(null, color); setupStatusBar(color); title = (TextView) findViewById(R.id.textView); medName = (TextView) findViewById(R.id.textView2); fab = (FloatingActionButton) findViewById(R.id.add_button); scheduleTypeSelector = findViewById(R.id.schedule_type_selector); readingQrBox = findViewById(R.id.reading_qr_box); medName.setBackgroundColor(color); scheduleTypeSelector.setBackgroundColor(dark); routinesItem = (ImageButton) findViewById(R.id.schedule_type_routines); hourlyItem = (ImageButton) findViewById(R.id.schedule_type_hourly); cycleItem = (ImageButton) findViewById(R.id.schedule_type_period); View.OnClickListener l = new View.OnClickListener() { @Override public void onClick(View v) { onClickScheduleTypeButton(v.getId()); } }; routinesItem.setOnClickListener(l); hourlyItem.setOnClickListener(l); cycleItem.setOnClickListener(l); qrData = getIntent().getStringExtra("qr_data"); try { new ProcessQRTask().execute(qrData); } catch (Exception e) { Log.e(TAG, "Error processing QR", e); Toast.makeText(this, "Error inesperado actualizando!", Toast.LENGTH_LONG).show(); finish(); } } private List<PrescriptionWrapper> filterValidPrescriptions(PrescriptionListWrapper prescriptionListWrapper) { List<PrescriptionWrapper> p = new ArrayList<>(); for (PrescriptionWrapper pw : prescriptionListWrapper.p) { if (pw.cn != null) { Prescription pr = Prescription.findByCn(pw.cn); boolean prescriptionExists = pr != null; boolean medExists = DB.medicines().findOneBy(Medicine.COLUMN_CN, pw.cn) != null; if (prescriptionExists) { pw.exists = medExists; pw.prescription = pr; p.add(pw); } } else if (pw.g != null) { HomogeneousGroup group = findGroup(pw.g); if (group != null) { Log.d("ConfirmSchedulesAct", "Found group: " + group.name); pw.exists = true; pw.isGroup = true; pw.group = group; p.add(pw); } } if (pw.pk != null) { for (PickupWrapper pkw : pw.pk) { Log.d("ConfirmSchedulesAct", "Pickup : " + df.parseDateTime(pkw.f).toString("dd/MM/yyyy")); Log.d("ConfirmSchedulesAct", "Pickup : " + df.parseDateTime(pkw.t).toString("dd/MM/yyyy")); Log.d("ConfirmSchedulesAct", "Pickup : " + pkw.tk); } } } return p; } private HomogeneousGroup findGroup(String g) { return DB.groups().findOneBy(HomogeneousGroup.COLUMN_GROUP, g); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.confirm_schedules, menu); return true; } private void hideScheduleTypeSelector() { scheduleTypeSelector.setVisibility(View.INVISIBLE); } private void showScheduleTypeSelector() { if (scheduleTypeSelector.getVisibility() != View.VISIBLE) { scheduleTypeSelector.setVisibility(View.VISIBLE); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { default: finish(); return true; } } public void onClickScheduleTypeButton(int id) { Fragment f = getViewPagerFragment(mViewPager.getCurrentItem()); routinesItem.setAlpha(0.3f); hourlyItem.setAlpha(0.3f); cycleItem.setAlpha(0.3f); if (f instanceof ScheduleImportFragment) { if (id == R.id.schedule_type_routines) { routinesItem.setAlpha(1f); ((ScheduleImportFragment) f).changeScheduleType(Schedule.SCHEDULE_TYPE_EVERYDAY); } else if (id == R.id.schedule_type_hourly) { hourlyItem.setAlpha(1f); ((ScheduleImportFragment) f).changeScheduleType(Schedule.SCHEDULE_TYPE_HOURLY); } else if (id == R.id.schedule_type_period) { cycleItem.setAlpha(1f); ((ScheduleImportFragment) f).changeScheduleType(Schedule.SCHEDULE_TYPE_CYCLE); } } } public Map<Schedule, PrescriptionWrapper> getScheduleInfo() { Map<Schedule, PrescriptionWrapper> schedules = new HashMap<>(); for (int i = 0; i < scheduleCount; i++) { Fragment f = getViewPagerFragment(i + 1); if (f instanceof ScheduleImportFragment) { ScheduleImportFragment importFragment = (ScheduleImportFragment) f; schedules.put(importFragment.getSchedule(), importFragment.getPrescriptionWrapper()); } } return schedules; } public List<Schedule> getSchedules() { List<Schedule> schedules = new ArrayList<>(); for (int i = 0; i < scheduleCount; i++) { Fragment f = getViewPagerFragment(i + 1); if (f instanceof ScheduleImportFragment) { schedules.add(((ScheduleImportFragment) f).getSchedule()); } } return schedules; } private void saveSchedules() { final ProgressDialog progress = ProgressDialog.show(this, "Calendula", "Actualizando pautas...", true); AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... arg0) { try { TransactionManager.callInTransaction(DB.helper().getConnectionSource(), new Callable<Object>() { @Override public Object call() throws Exception { for (int i = 0; i < scheduleCount; i++) { Log.d("PRESCRIPTION", "Item " + i); Fragment f = getViewPagerFragment(i + 1); if (f instanceof ScheduleImportFragment) { Log.d("PRESCRIPTION", "Fragment " + i); ScheduleImportFragment c = (ScheduleImportFragment) f; if (c.validate()) { PrescriptionWrapper w = prescriptionList.get(i); Log.d("PRESCRIPTION", "Validate!"); String cn = w.cn; Medicine m = null; if (cn != null) { m = DB.medicines().findByCnAndPatient(cn, patient); if (m == null) { Log.d("PRESCRIPTION", "Saving medicine!"); m = Medicine.fromPrescription(Prescription.findByCn(cn)); m.setPatient(patient); m.save(); } } else if (w.isGroup) { m = DB.medicines().findByGroupAndPatient(w.group.getId(), patient); if (m == null) { m = new Medicine(Strings.firstPart(w.group.name)); m.setHomogeneousGroup(w.group.getId()); Presentation pres = Presentation.expected(w.group.name, w.group.name); m.setPresentation(pres != null ? pres : Presentation.PILLS); m.setPatient(patient); m.save(); } } else { throw new RuntimeException( " Prescription must have a cn or group reference"); } Schedule s = c.getSchedule(); Schedule prev = DB.schedules().findByMedicineAndPatient(m, patient); // TODO: find by med and patient if (prev != null) { Log.d("PRESCRIPTION", "Found previous schedule for med " + m.getId()); updateSchedule(prev, s, c.getScheduleItems()); } else { Log.d("PRESCRIPTION", "Not found previous schedule for med " + m.getId()); createSchedule(s, c.getScheduleItems(), m); } if (m != null) { // remove old pickups before inserting the new ones DB.pickups().removeByMed(m); } if (m != null && w.pk != null && w.pk.size() > 0) { for (PickupWrapper pkw : w.pk) { PickupInfo pickupInfo = new PickupInfo(); pickupInfo.setTo(df.parseLocalDate(pkw.t).plusMonths(19)); pickupInfo.setFrom(df.parseLocalDate(pkw.f).plusMonths(19)); pickupInfo.taken(pkw.tk == 1 ? true : false); pickupInfo.setMedicine(m); DB.pickups().save(pickupInfo); } } } else { mViewPager.setCurrentItem(i + 1); Snack.show("Hmmmmmm....", ConfirmSchedulesActivity.this); } } } CalendulaApp.eventBus().post(PersistenceEvents.SCHEDULE_EVENT); AlarmScheduler.instance().updateAllAlarms(ConfirmSchedulesActivity.this); return null; } }); return true; } catch (Exception e) { Log.e("ConfirmSchedulesAct", "Error saving prescriptions", e); return false; } } @Override protected void onPostExecute(Boolean result) { if (progress != null) { progress.dismiss(); } if (result) { finish(); } } }; task.execute((Void[]) null); } public void createSchedule(final Schedule s, List<ScheduleItem> items, Medicine m) { // save schedule s.setMedicine(m); s.setPatient(patient); s.setScanned(true); s.save(); Log.d(TAG, "Saving schedule..." + s.toString()); if (!s.repeatsHourly()) { for (ScheduleItem item : items) { item.setSchedule(s); item.save(); Log.d(TAG, "Saving item..." + item.getId()); // add to daily schedule DailyAgenda.instance().addItem(patient, item, false); } } else { for (DateTime time : s.hourlyItemsToday()) { LocalTime timeToday = time.toLocalTime(); DailyAgenda.instance().addItem(patient, s, timeToday); } } // save and fire event DB.schedules().saveAndFireEvent(s); AlarmScheduler.instance().onCreateOrUpdateSchedule(s, ConfirmSchedulesActivity.this); } public void updateSchedule(final Schedule s, final Schedule current, List<ScheduleItem> items) { s.setType(current.type()); s.setDays(current.days()); s.setDose(current.dose()); s.setStart(current.start()); s.setRepetition(current.rule()); s.setCycle(current.getCycleDays(), current.getCycleRest()); s.setStartTime(current.startTime()); List<Long> routinesTaken = new ArrayList<Long>(); if (!s.repeatsHourly()) { for (ScheduleItem item : s.items()) { DailyScheduleItem d = DailyScheduleItem.findByScheduleItem(item); // if taken today, add to the list if (d != null && d.takenToday()) { routinesTaken.add(item.routine().getId()); } item.deleteCascade(); } // save new items for (ScheduleItem i : items) { ScheduleItem item = new ScheduleItem(); item.setDose(i.dose()); item.setRoutine(i.routine()); item.setSchedule(s); item.save(); // add to daily schedule DailyScheduleItem dsi = new DailyScheduleItem(item); dsi.setPatient(patient); if (routinesTaken.contains(item.routine().getId())) { dsi.setTakenToday(true); } dsi.save(); } } else { DB.dailyScheduleItems().removeAllFrom(s); for (DateTime time : s.hourlyItemsToday()) { LocalTime timeToday = time.toLocalTime(); DailyScheduleItem dsi = new DailyScheduleItem(s, timeToday); dsi.setPatient(patient); dsi.save(); Log.d(TAG, "Saving daily schedule item..." + dsi.getId() + " timeToday: " + timeToday.toString("kk:mm")); } } // save and fire event DB.schedules().saveAndFireEvent(s); AlarmScheduler.instance().onCreateOrUpdateSchedule(s, ConfirmSchedulesActivity.this); } private void updatePageTitle(int i) { if (i == 0) { title.setText(scheduleCount + " " + getString(R.string.scan_prescriptions)); medName.setText(getString(R.string.scan_review_title)); } else if (i == scheduleCount + 1) { title.setText(scheduleCount + " " + getString(R.string.scan_prescriptions)); medName.setText(getString(R.string.confirm)); } else { PrescriptionWrapper pw = prescriptionList.get(i - 1); if (pw.cn != null) { if (pw.prescription == null) { pw.prescription = Prescription.findByCn(pw.cn); } medName.setText(Strings.toProperCase(pw.prescription.name)); } else if (pw.isGroup) { medName.setText(pw.group.name); } title.setText(getResources().getString(R.string.confirm_prescription_x_of_y, i, scheduleCount)); } } @Override public void onPageScrolled(int i, float v, int i2) { } @Override public void onPageSelected(int i) { updatePageTitle(i); Log.d("ConfirmSchedulesAct", " Page Selected: " + i); if (i == 0) { hideScheduleTypeSelector(); fab.setVisibility(View.INVISIBLE); } else if (i == scheduleCount + 1) { hideScheduleTypeSelector(); fab.setVisibility(View.VISIBLE); } else { showScheduleTypeSelector(); fab.setVisibility(View.INVISIBLE); updateScheduleTypeSelector(i); } } public void updateScheduleTypeSelector(int page) { Fragment f = getViewPagerFragment(page); routinesItem.setAlpha(0.3f); hourlyItem.setAlpha(0.3f); cycleItem.setAlpha(0.3f); int type = ((ScheduleImportFragment) f).getSchedule().type(); Log.d("Confirm", "Type: " + type); if (f instanceof ScheduleImportFragment) { if (type == Schedule.SCHEDULE_TYPE_HOURLY) { hourlyItem.setAlpha(1f); } else if (type == Schedule.SCHEDULE_TYPE_CYCLE) { cycleItem.setAlpha(1f); } else { routinesItem.setAlpha(1f); } } } @Override public void onPageScrollStateChanged(int i) { } public List<PrescriptionWrapper> getPrescriptions() { return prescriptionList; } /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to * one of the sections/tabs/pages. */ public class SectionsPagerAdapter extends FragmentPagerAdapter { int scheduleCount; public SectionsPagerAdapter(FragmentManager fm, int scheduleCount) { super(fm); this.scheduleCount = scheduleCount; } @Override public Fragment getItem(int position) { Log.d("ScanQR", "Position: " + position); if (position == 0) { return ScheduleConfirmationStartFragment.newInstance(); } else if (position == scheduleCount + 1) { return ScheduleConfirmationEndFragment.newInstance(); } else { // getItem is called to instantiate the fragment for the given page. // Return a PlaceholderFragment (defined as a static inner class below). PrescriptionWrapper pw = prescriptionList.get(position - 1); return ScheduleImportFragment.newInstance(pw); } } @Override public int getCount() { return scheduleCount + 2; } @Override public CharSequence getPageTitle(int position) { return ""; } } public PrescriptionListWrapper parseQRData(String data) { Log.d(TAG, "QRDATA: " + data); return new Gson().fromJson(data, PrescriptionListWrapper.class); } public void next() { int next = mViewPager.getCurrentItem() + 1; int size = mSectionsPagerAdapter.getCount(); if (next < size) { mViewPager.setCurrentItem(next); } } Fragment getViewPagerFragment(int position) { return getSupportFragmentManager() .findFragmentByTag(FragmentUtils.makeViewPagerFragmentName(R.id.pager, position)); } private class ProcessQRTask extends AsyncTask<String, Integer, Long> { ProgressDialog dialog; @Override protected void onPreExecute() { super.onPreExecute(); dialog = new ProgressDialog(ConfirmSchedulesActivity.this); dialog.setMessage("Processing QR info ..."); } protected Long doInBackground(String... data) { String qrData = data[0]; if (qrData != null) { try { prescriptionList = filterValidPrescriptions(parseQRData(qrData)); Long sCount = (long) prescriptionList.size(); if (sCount > 0) { return sCount; } else { return 0l; } } catch (Exception e) { Log.e(TAG, "Error processing QR", e); return -1l; } } else { return -1l; } } protected void onPostExecute(Long schedules) { scheduleCount = schedules.intValue(); if (schedules == -1) { Toast.makeText(ConfirmSchedulesActivity.this, "Error inesperado actualizando!", Toast.LENGTH_LONG) .show(); finish(); } else if (schedules == 0) { Toast.makeText(ConfirmSchedulesActivity.this, "No se encontraron prescripciones vlidas!", Toast.LENGTH_SHORT).show(); } else { updatePageTitle(0); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { saveSchedules(); } }); // Create the adapter that will return a fragment for each of the three // primary sections of the activity. mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(), scheduleCount); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setOnPageChangeListener(ConfirmSchedulesActivity.this); mViewPager.setAdapter(mSectionsPagerAdapter); mViewPager.setOffscreenPageLimit(20); hideScheduleTypeSelector(); readingQrBox.setVisibility(View.GONE); } if (dialog.isShowing()) { dialog.dismiss(); } } } }