/* * 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.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.GridView; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.getbase.floatingactionbutton.FloatingActionButton; import com.google.gson.Gson; import com.mikepenz.community_material_typeface_library.CommunityMaterial; import com.mikepenz.iconics.IconicsDrawable; import com.nispok.snackbar.Snackbar; import java.util.ArrayList; import java.util.List; import es.usc.citius.servando.calendula.CalendulaActivity; import es.usc.citius.servando.calendula.DefaultDataGenerator; import es.usc.citius.servando.calendula.R; import es.usc.citius.servando.calendula.database.DB; import es.usc.citius.servando.calendula.persistence.Patient; import es.usc.citius.servando.calendula.util.AvatarMgr; import es.usc.citius.servando.calendula.util.ScreenUtils; import es.usc.citius.servando.calendula.util.Snack; public class PatientDetailActivity extends CalendulaActivity implements GridView.OnItemClickListener { GridView avatarGrid; BaseAdapter adapter; Patient patient; ImageView patientAvatar; View patientAvatarBg; RelativeLayout gridContainer; // TextView selectAvatarMsg; View top; View bg; EditText patientName; List<String> avatars = new ArrayList<>(AvatarMgr.avatars.keySet()); private Menu menu; private int avatarBackgroundColor; FloatingActionButton fab; int color1; int color2; Drawable iconClose; Drawable iconSwich; CheckBox addRoutinesCheckBox; LinearLayout colorList; HorizontalScrollView colorScroll; Button linkButton; boolean linked = false; String token = null; long patientId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_patient_detail); top = findViewById(R.id.top); bg = findViewById(R.id.bg); patientAvatar = (ImageView) findViewById(R.id.patient_avatar); patientAvatarBg = findViewById(R.id.patient_avatar_bg); gridContainer = (RelativeLayout) findViewById(R.id.grid_container); patientName = (EditText) findViewById(R.id.patient_name); fab = (FloatingActionButton) findViewById(R.id.avatar_change); avatarGrid = (GridView) findViewById(R.id.grid); addRoutinesCheckBox = (CheckBox) findViewById(R.id.checkBox); colorScroll = (HorizontalScrollView) findViewById(R.id.colorScroll); linkButton = (Button) findViewById(R.id.linkButton); avatarGrid.setVisibility(View.VISIBLE); gridContainer.setVisibility(View.GONE); patientId = getIntent().getLongExtra("patient_id", -1); lookForQrData(getIntent()); if(patientId!=-1){ patient = DB.patients().findById(patientId); addRoutinesCheckBox.setVisibility(View.GONE); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); token = prefs.getString("remote_token" + patientId, null); if(token != null){ linkButton.setVisibility(View.VISIBLE); linkButton.setText("Desvincular"); linkButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { showUnlinkPatientDialog(); } }); }else{ linkButton.setVisibility(View.GONE); } }else{ linkButton.setVisibility(View.GONE); patient = new Patient(); } iconClose = new IconicsDrawable(this, CommunityMaterial.Icon.cmd_close) .sizeDp(24) .paddingDp(5) .colorRes(R.color.dark_grey_home); iconSwich = new IconicsDrawable(this, CommunityMaterial.Icon.cmd_account_switch) .sizeDp(24) .paddingDp(2) .colorRes(R.color.fab_light_normal); setSwichFab(); setupToolbar(patient.name(), Color.TRANSPARENT); setupStatusBar(Color.TRANSPARENT); setupAvatarList(); setupColorChooser(); loadPatient(); } void lookForQrData(Intent i){ String qrData = i.getStringExtra("qr_data"); if(qrData!=null){ PatientLinkWrapper p = new Gson().fromJson(qrData, PatientLinkWrapper.class); Snack.show("Usuario vinculado correctamente!", this, Snackbar.SnackbarDuration.LENGTH_LONG); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(PatientDetailActivity.this); prefs.edit().putString("remote_token" + patientId, p.token).commit(); Log.d("PatDetail", p.toString()); } } private void showUnlinkPatientDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Si desvinculas este usuario se interrumpirá el seguimiento. Estás seguro de que deseas continuar?") .setCancelable(true) .setTitle("Ten cuidado") .setPositiveButton("Si, desvincular", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { token = null; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(PatientDetailActivity.this); prefs.edit().remove("remote_token" + patientId).commit(); linkButton.setText("Vincular"); } }) .setNegativeButton(getString(R.string.dialog_no_option), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.show(); } private void startScanActivity(){ Intent i = new Intent(this, ScanActivity.class); i.putExtra("after_scan_pkg", getPackageName()); i.putExtra("after_scan_cls", PatientDetailActivity.class.getName()); i.putExtra("patient_id", patientId); this.startActivity(i); this.overridePendingTransition(0, 0); finish(); } private void setupColorChooser() { colorList = (LinearLayout) findViewById(R.id.color_chooser); colorList.removeAllViews(); for(final String hex : COLORS){ ImageView colorView = (ImageView) getLayoutInflater().inflate(R.layout.color_chooser_item, null); final int color = Color.parseColor(hex); colorView.setBackgroundColor(color); colorView.setPadding(2, 2, 2, 2); if(color == patient.color()) { colorView.setImageDrawable(new IconicsDrawable(this) .icon(CommunityMaterial.Icon.cmd_checkbox_marked_circle) .paddingDp(30) .color(Color.WHITE) .sizeDp(80)); }else { colorView.setImageDrawable(new IconicsDrawable(this) .icon(CommunityMaterial.Icon.cmd_checkbox_marked_circle) .paddingDp(30) .color(Color.TRANSPARENT) .sizeDp(80)); } colorView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { patient.setColor(color); setupColorChooser(); int x = (int) view.getX() + view.getWidth()/2 - colorScroll.getScrollX(); updateAvatar(patient.avatar(), 1, 400, x); colorList.postDelayed(new Runnable() { @Override public void run() { scrollToColor(color); } },300); //Toast.makeText(getBaseContext(), "Color: " + hex, Toast.LENGTH_SHORT).show(); } }); colorList.addView(colorView); } } private void scrollToColor(int color){ int index = 0; for(int i = 0; i < COLORS.length; i++){ if(color == Color.parseColor(COLORS[i])){ index = i; break; } } int width = colorList.getChildAt(0).getWidth(); colorScroll.smoothScrollTo(width*index + width/2 - colorScroll.getWidth()/2 ,0); } void setSwichFab(){ fab.setColorNormalResId(R.color.fab_dark_normal); fab.setColorPressedResId(R.color.fab_dark_pressed); fab.setIconDrawable(iconSwich); } void setCloseFab(){ fab.setColorNormalResId(R.color.fab_light_normal); fab.setColorPressedResId(R.color.fab_light_pressed); fab.setIconDrawable(iconClose); } @Override public void onBackPressed() { //ScreenUtils.setStatusBarColor(this, color2); patientAvatarBg.setVisibility(View.INVISIBLE); super.onBackPressed(); } private void animateAvatarSelectorShow(int duration) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { gridContainer.setVisibility(View.INVISIBLE); // get the center for the clipping circle int cx = (int) fab.getX() + fab.getWidth()/2; int cy = 0; // get the final radius for the clipping circle int finalRadius = (int) Math.hypot(patientAvatarBg.getWidth(), bg.getHeight() - patientAvatarBg.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(gridContainer, cx, cy, 0, finalRadius); anim.setInterpolator(new DecelerateInterpolator()); // make the view visible and start the animation gridContainer.setVisibility(View.VISIBLE); anim.setDuration(duration).start(); gridContainer.postDelayed(new Runnable() { @Override public void run() { scrollToColor(patient.color()); } },duration); } } private void animateAvatarSelectorHide(int duration) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // get the center for the clipping circle int cx = (int) fab.getX() + fab.getWidth()/2; int cy = 0; // get the final radius for the clipping circle int finalRadius = (int) Math.hypot(patientAvatarBg.getWidth(), bg.getHeight() - patientAvatarBg.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(gridContainer, cx, cy, finalRadius, 0); // make the view visible and start the animation anim.setInterpolator(new AccelerateInterpolator()); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { gridContainer.setVisibility(View.GONE); setSwichFab(); super.onAnimationEnd(animation); } }); anim.setDuration(duration).start(); } } private void animateAvatarBg(int duration, int x, Animator.AnimatorListener cb) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { patientAvatarBg.setVisibility(View.INVISIBLE); // get the center for the clipping circle int cx = (patientAvatarBg.getLeft() + patientAvatarBg.getRight()) / 2; int cy = patientAvatarBg.getBottom(); // get the final radius for the clipping circle int finalRadius = (int)Math.hypot(patientAvatarBg.getWidth(), patientAvatarBg.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(patientAvatarBg, x, cy, ScreenUtils.dpToPx(getResources(), 100f), finalRadius); // make the view visible and start the animation patientAvatarBg.setVisibility(View.VISIBLE); anim.setInterpolator(new DecelerateInterpolator()); anim.setDuration(duration); if(cb!=null){ anim.addListener(cb); } anim.start(); } } void hideAvatarSelector(){ animateAvatarSelectorHide(200); } void showAvatarSelector(){ setCloseFab(); animateAvatarSelectorShow(300); } private void setupAvatarList() { adapter = new PatientAvatarsAdapter(this); avatarGrid.setAdapter(adapter); avatarGrid.setOnItemClickListener(this); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(gridContainer.getVisibility() == View.VISIBLE) hideAvatarSelector(); else showAvatarSelector(); } }); } private void loadPatient() { patientName.setText(patient.name()); top.setBackgroundColor(patient.color()); updateAvatar(patient.avatar(), 400, 400, patientAvatar.getWidth()/2); } private void updateAvatar(String avatar, int delay, final int duration, final int x){ patientAvatar.setImageResource(AvatarMgr.res(avatar)); color1 = patient.color(); color2 = ScreenUtils.equivalentNoAlpha(color1, 0.7f); avatarBackgroundColor = color1; gridContainer.setBackgroundColor(getResources().getColor(R.color.dark_grey_home)); //ScreenUtils.setStatusBarColor(this, avatarBackgroundColor); if(delay > 0) { patientAvatarBg.postDelayed(new Runnable() { @Override public void run() { patientAvatarBg.setBackgroundColor(avatarBackgroundColor); animateAvatarBg(duration, x, new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { top.setBackgroundColor(avatarBackgroundColor); } }); } }, delay); }else{ patientAvatarBg.setBackgroundColor(avatarBackgroundColor); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_patient_detail, menu); this.menu = menu; //if(token != null){ this.menu.getItem(0).setVisible(false); //} return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // Respond to the action bar's Up/Home button case android.R.id.home: //ScreenUtils.setStatusBarColor(this, color2); patientAvatarBg.setVisibility(View.INVISIBLE); supportFinishAfterTransition(); return true; case R.id.action_done: String text = patientName.getText().toString().trim(); if(!TextUtils.isEmpty(text) && !text.equals(patient.name())){ patient.setName(text); } if(!TextUtils.isEmpty(patient.name())){ DB.patients().saveAndFireEvent(patient); if(addRoutinesCheckBox.isChecked()){ DefaultDataGenerator.generateDefaultRoutines(patient, this); } supportFinishAfterTransition(); }else{ Snack.show("Indique un nombre, por favor.", this); } return true; case R.id.action_link_qr: if(token == null) { startScanActivity(); }else{ showUnlinkPatientDialog(); } return true; } return super.onOptionsItemSelected(item); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String avatar = avatars.get(position); patient.setAvatar(avatar); updateAvatar(avatar, 0, 0, patientAvatar.getWidth()/2); adapter.notifyDataSetChanged(); } private class PatientAvatarsAdapter extends BaseAdapter { private Context context; public PatientAvatarsAdapter(Context context) { this.context = context; } @Override public int getCount() { return avatars.size(); } @Override public Object getItem(int position) { return avatars.get(position); } @Override public long getItemId(int position) { return avatars.get(position).hashCode(); } @Override public View getView(int position, View view, ViewGroup viewGroup) { ImageView v; String avatar = avatars.get(position); int resource = AvatarMgr.res(avatar); if (view == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.avatar_list_item, viewGroup, false); } v = (ImageView) view.findViewById(R.id.imageView); v.setImageResource(resource); if(avatar.equals(patient.avatar())){ v.setBackgroundResource(R.drawable.avatar_list_item_bg); }else{ v.setBackgroundResource(R.color.transparent); } return view; } } public class PatientLinkWrapper{ public String name; public String id; public String token; @Override public String toString() { return "PatientLinkWrapper{" + "name='" + name + '\'' + ", id='" + id + '\'' + ", token='" + token + '\'' + '}'; } } public static final String[] COLORS = new String[]{ "#1abc9c", "#16a085", "#f1c40f", "#f39c12", "#2ecc71", "#27ae60", "#e67e22", "#d35400", "#c0392b", "#e74c3c", "#2980b9", "#3498db", "#9b59b6", "#8e44ad", "#2c3e50", "#34495e" // "#f44336", // "#e91e63", // "#9c27b0", // "#673ab7", // "#3f51b5", // "#1976d2", // "#2196f3", // "#03a9f4", // "#00bcd4", // "#009688", // "#4caf50", // "#8bc34a", // "#cddc39", // "#ffeb3b", // "#ffc107", // "#ff9800", // "#ff5722", // "#795548", // "#9e9e9e", // "#607d8b" }; }