/* * Copyright 2014 Bevbot LLC <info@bevbot.com> * * This file is part of the Kegtab package from the Kegbot project. For * more information on Kegtab or Kegbot, see <http://kegbot.org/>. * * Kegtab 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, version 2. * * Kegtab 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 Kegtab. If not, see <http://www.gnu.org/licenses/>. */ package org.kegbot.app; import android.app.Activity; import android.app.ListFragment; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.squareup.otto.Subscribe; import org.kegbot.app.event.FlowUpdateEvent; import org.kegbot.app.util.ImageDownloader; import org.kegbot.app.util.Units; import org.kegbot.app.view.BadgeView; import org.kegbot.core.AuthenticationManager; import org.kegbot.core.Flow; import org.kegbot.core.KegbotCore; import org.kegbot.proto.Models.Keg; import org.kegbot.proto.Models.KegTap; import java.util.concurrent.TimeUnit; public class PourStatusFragment extends ListFragment { private static final String TAG = PourStatusFragment.class.getSimpleName(); private static final double VOLUME_COUNTER_INCREMENT_ML = 10; private static final long VOLUME_COUNTER_INCREMENT_DELAY_MILLIS = 20; private static final String ARG_TAP_ID = "tap_id"; private static final int AUTH_DRINKER_REQUEST = 1; /** * After this much inactivity, the "pour automatically ends" dialog is shown. */ private static final long IDLE_TOOLTIP_MILLIS = TimeUnit.SECONDS.toMillis(5); private final Handler mHandler = new Handler(Looper.getMainLooper()); private double mTargetVolumeMl = 0.0; private double mCurrentVolumeMl = 0.0; private KegbotCore mCore; private ImageDownloader mImageDownloader; private View mView; private BadgeView mPourVolumeBadge; private TextView mTapTitle; private TextView mTapSubtitle; private TextView mStatusLine; private ImageView mBeerImage; private final Runnable mCounterIncrementRunnable = new Runnable() { @Override public void run() { final double remain = mTargetVolumeMl - mCurrentVolumeMl; if (remain <= 0) { return; } mCurrentVolumeMl += Math.min(remain, VOLUME_COUNTER_INCREMENT_ML); setVolumeDisplay(mCurrentVolumeMl); if (mCurrentVolumeMl < mTargetVolumeMl) { mHandler.postDelayed(mCounterIncrementRunnable, VOLUME_COUNTER_INCREMENT_DELAY_MILLIS); } } }; private Flow mFlow = null; private final Runnable mCountdownRunnable = new Runnable() { @Override public void run() { final Flow flow = mFlow; if (flow != null) { if (flow.isFinished()) { mStatusLine.setVisibility(View.VISIBLE); mStatusLine.setText(getString(R.string.pour_status_complete)); } else { if (mFlow.getIdleTimeMs() >= IDLE_TOOLTIP_MILLIS) { final long seconds = mFlow.getMsUntilIdle() / 1000; mStatusLine.setText("Pour automatically ends in " + seconds + " second" + ((seconds != 1) ? "s" : "") + "."); mStatusLine.setVisibility(View.VISIBLE); } else { mStatusLine.setVisibility(View.INVISIBLE); } } } mHandler.postDelayed(mCountdownRunnable, 1000); } }; public static PourStatusFragment forTap(KegTap tap) { final PourStatusFragment frag = new PourStatusFragment(); final Bundle args = new Bundle(); args.putInt(ARG_TAP_ID, tap.getId()); frag.setArguments(args); return frag; } private KegTap getTap() { return mCore.getTapManager().getTap(getArguments().getInt(ARG_TAP_ID)); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCore = KegbotCore.getInstance(getActivity()); mImageDownloader = mCore.getImageDownloader(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.pour_status_item_layout, container, false); mPourVolumeBadge = (BadgeView) mView.findViewById(R.id.tapStatsBadge1); mPourVolumeBadge.setBadgeValue("0.0"); mPourVolumeBadge.setBadgeCaption("Ounces Poured"); mTapTitle = (TextView) mView.findViewById(R.id.tapTitle); mTapSubtitle = (TextView) mView.findViewById(R.id.tapSubtitle); mStatusLine = (TextView) mView.findViewById(R.id.tapNotes); mBeerImage = (ImageView) mView.findViewById(R.id.tapImage); setVolumeDisplay(0); return mView; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case AUTH_DRINKER_REQUEST: if (resultCode == Activity.RESULT_OK) { final String username = data.getStringExtra(KegtabCommon.ACTIVITY_AUTH_DRINKER_RESULT_EXTRA_USERNAME); if (!Strings.isNullOrEmpty(username)) { Log.d(TAG, "Authenticating async."); AuthenticationManager am = mCore.getAuthenticationManager(); am.authenticateUsernameAsync(username); } } break; default: super.onActivityResult(requestCode, resultCode, data); } } @Override public void onAttach(Activity activity) { super.onAttach(activity); } @Override public void onResume() { super.onResume(); applyTapDetail(); KegbotCore.getInstance(getActivity()).getBus().register(this); startCountdown(); if (mFlow != null) { updateWithFlow(mFlow); } } @Override public void onPause() { KegbotCore.getInstance(getActivity()).getBus().unregister(this); cancelCountdown(); super.onPause(); } @Subscribe public void onFlowUpdate(FlowUpdateEvent event) { final Flow flow = event.getFlow(); final KegTap tap = getTap(); if (tap != null && tap.getId() == flow.getTap().getId()) { if (!flow.isFinished()) { updateWithFlow(flow); } } } private void setVolumeDisplay(double volumeMl) { final Pair<String, String> qty = Units.localizeWithoutScaling( mCore.getConfiguration(), volumeMl); mPourVolumeBadge.setBadgeValue(qty.first); mPourVolumeBadge.setBadgeCaption(Units.capitalizeUnits(qty.second) + " Poured"); } private void applyTapDetail() { final KegTap tap = getTap(); mBeerImage.setImageResource(R.drawable.kegbot_unknown_square_2); final Keg keg = tap.getCurrentKeg(); if (keg != null) { final String beerName = keg.getBeverage().getName(); // Set beer name. if (!Strings.isNullOrEmpty(beerName) && mTapTitle != null) { mTapTitle.setText(beerName); } // Set beer image. if (keg.getBeverage().hasPicture()) { mImageDownloader.download(keg.getBeverage().getPicture().getUrl(), mBeerImage); } mTapSubtitle.setText(tap.getName()); } else { mTapTitle.setText(tap.getName()); } } public void updateWithFlow(final Flow flow) { Preconditions.checkNotNull(flow, "null flow given to updateWithFlow()"); mFlow = flow; if (mFlow.isFinished()) { return; } if (mView == null) { return; } // Set volume portion. mTargetVolumeMl = flow.getVolumeMl(); if (mCurrentVolumeMl < mTargetVolumeMl) { mHandler.removeCallbacks(mCounterIncrementRunnable); mHandler.post(mCounterIncrementRunnable); } } private void cancelCountdown() { mHandler.removeCallbacks(mCountdownRunnable); } private void startCountdown() { cancelCountdown(); mHandler.post(mCountdownRunnable); } }