/*
* 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.AlertDialog;
import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.ViewFlipper;
import com.google.common.collect.Lists;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.kegbot.app.event.TapsChangedEvent;
import org.kegbot.backend.Backend;
import org.kegbot.backend.BackendException;
import org.kegbot.core.KegbotCore;
import org.kegbot.core.SyncManager;
import org.kegbot.core.TapManager;
import org.kegbot.proto.Models;
import org.kegbot.proto.Models.FlowMeter;
import org.kegbot.proto.Models.Keg;
import org.kegbot.proto.Models.KegTap;
import java.util.List;
import butterknife.ButterKnife;
/**
* A fragment representing a single Tap detail screen. This fragment is either contained in a {@link
* TapListActivity} in two-pane mode (on tablets) or a {@link TapDetailActivity} on handsets.
*/
public class TapDetailFragment extends Fragment {
private static final String TAG = TapDetailFragment.class.getSimpleName();
/**
* The fragment argument representing the item ID that this fragment represents.
*/
public static final String ARG_ITEM_ID = "item_id";
private View mView;
private Bus mBus;
private TapManager mTapManager;
private ViewFlipper mFlipper;
private Spinner mMeterSelect;
private Spinner mToggleSelect;
private final List<FlowMeter> mMeters = Lists.newArrayList();
private final List<Models.FlowToggle> mToggles = Lists.newArrayList();
private FlowMeterAdapter mAdapter;
private FlowToggleAdapter mToggleAdapter;
private Switch mTapEnabledSwitch;
private KegTap mTap;
private int mTapId;
Button mDeleteTapButton;
public TapDetailFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final KegbotCore core = KegbotCore.getInstance(getActivity());
mTapManager = core.getTapManager();
mBus = core.getBus();
mBus.register(this);
mMeters.add(null); // "not connected"
final SyncManager syncManager = KegbotCore.getInstance(getActivity()).getSyncManager();
mMeters.addAll(syncManager.getCurrentFlowMeters());
mToggles.add(null); // "none"
mToggles.addAll(syncManager.getCurrentFlowToggles());
mTapId = getArguments().getInt(ARG_ITEM_ID, 0);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
mView = inflater.inflate(R.layout.fragment_tap_detail, container, false);
ButterKnife.inject(this, mView);
mFlipper = ButterKnife.findById(mView, R.id.tapControlsFlipper);
mTapEnabledSwitch = ButterKnife.findById(mView, R.id.tapEnabledSwitch);
mTapEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (mTap == null) {
Log.wtf(TAG, "Tap is null!");
return;
}
mTapManager.setTapVisibility(mTap, b);
updateTapDetails(mTap);
}
});
mAdapter = new FlowMeterAdapter(getActivity());
mMeterSelect = ButterKnife.findById(mView, R.id.meterSelect);
mMeterSelect.setAdapter(mAdapter);
mToggleAdapter = new FlowToggleAdapter(getActivity());
mToggleSelect = ButterKnife.findById(mView, R.id.toggleSelect);
mToggleSelect.setAdapter(mToggleAdapter);
mAdapter.addAll(mMeters);
mToggleAdapter.addAll(mToggles);
mDeleteTapButton = ButterKnife.findById(mView, R.id.deleteTapButton);
mMeterSelect.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.d(TAG, "onItemSelected: position=" + position + " id=" + id);
final FlowMeter meter = mMeters.get(position);
if (meter == mTap.getMeter() ||
(meter != null && mTap.hasMeter() && meter.getId() == mTap.getMeter().getId())) {
Log.d(TAG, "Not changed.");
return;
}
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
final KegbotCore core = KegbotCore.getInstance(getActivity());
final Backend backend = core.getBackend();
final SyncManager sync = core.getSyncManager();
try {
if (meter == null) {
Log.d(TAG, "Disconnecting meter on tap.");
backend.disconnectMeter(mTap);
} else {
Log.d(TAG, "Connecting meter on tap.");
backend.connectMeter(mTap, meter);
}
} catch (BackendException e) {
Log.w(TAG, "Error: " + e, e);
}
sync.requestSync();
return null;
}
}.execute((Void) null);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Log.d(TAG, "onNothingSelected");
}
});
mToggleSelect.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Log.d(TAG, "toggle selected: position=" + position + " id=" + id);
final Models.FlowToggle toggle = mToggles.get(position);
if (toggle == mTap.getToggle() ||
(toggle != null && mTap.hasToggle() && toggle.getId() == mTap.getToggle().getId())) {
Log.d(TAG, "Not changed.");
return;
}
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
final KegbotCore core = KegbotCore.getInstance(getActivity());
final Backend backend = core.getBackend();
final SyncManager sync = core.getSyncManager();
try {
if (toggle == null) {
Log.d(TAG, "Disconnecting toggle on tap.");
backend.disconnectToggle(mTap);
} else {
Log.d(TAG, "Connecting toggle on tap.");
backend.connectToggle(mTap, toggle);
}
} catch (BackendException e) {
Log.w(TAG, "Error: " + e, e);
}
sync.requestSync();
return null;
}
}.execute((Void) null);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
Log.d(TAG, "onNothingSelected");
}
});
mDeleteTapButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
confirmDeleteTap();
}
});
if (mTapId != 0) {
mTap = KegbotCore.getInstance(getActivity()).getTapManager().getTap(mTapId);
updateTapDetails(mTap);
}
return mView;
}
@Override
public void onDestroy() {
mBus.unregister(this);
super.onDestroy();
}
@Subscribe
public void onTapUpdatedEvent(TapsChangedEvent event) {
Log.d(TAG, "onTapUpdatedEvent");
if (mTap == null) {
return;
}
for (final KegTap tap : event.getTaps()) {
if (tap.getId() == mTap.getId()) {
updateTapDetails(tap);
return;
}
}
// We must have been deleted.
getFragmentManager().popBackStackImmediate();
}
private void updateTapDetails(final KegTap tap) {
Log.d(TAG, "updateTapDetails");
mTap = tap;
if (mView == null) {
Log.w(TAG, "updateTapDetails: No rootview!");
return;
}
Log.d(TAG, "Updating tap! + " + mTap);
final boolean isVisible = mTapManager.getTapVisibility(mTap);
mTapEnabledSwitch.setChecked(isVisible);
if (isVisible) {
mFlipper.setDisplayedChild(0);
} else {
mFlipper.setDisplayedChild(1);
}
final TextView title = (TextView) mView.findViewById(R.id.tapDetailTitle);
title.setText(mTap.getName());
int position = 0;
final FlowMeter currentMeter = mTap.getMeter();
for (final FlowMeter meter : mMeters) {
if ((meter == null && currentMeter == null) ||
(meter != null && meter.getId() == currentMeter.getId())) {
mMeterSelect.setSelection(position);
break;
}
position += 1;
}
position = 0;
final Models.FlowToggle currentToggle = mTap.getToggle();
for (final Models.FlowToggle toggle : mToggles) {
if ((toggle == null && currentToggle == null) ||
(toggle != null && toggle.getId() == currentToggle.getId())) {
mToggleSelect.setSelection(position);
break;
}
position += 1;
}
final TextView onTapTitle = ButterKnife.findById(mView, R.id.onTapTitle);
final Button onTapButton = ButterKnife.findById(mView, R.id.tapKegButton);
if (mTap.hasCurrentKeg()) {
final Keg currentKeg = mTap.getCurrentKeg();
if (currentKeg.hasBeverage()) {
onTapTitle.setText(currentKeg.getBeverage().getName());
} else {
onTapTitle.setText(String.format("Keg %s", Integer.valueOf(currentKeg.getId())));
}
onTapButton.setText(R.string.end_keg_button);
onTapButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
confirmEndKeg();
}
});
} else {
onTapTitle.setText(R.string.tap_detail_tap_empty);
onTapButton.setText(R.string.tap_keg_button);
onTapButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onStartKeg();
}
});
}
final Button calibrateButton = ButterKnife.findById(mView, R.id.calibrateButton);
if (tap.hasMeter()) {
calibrateButton.setEnabled(true);
calibrateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
final Intent intent = CalibrationActivity.getStartIntent(getActivity(), tap);
startActivity(intent);
}
});
} else {
calibrateButton.setEnabled(false);
}
}
private void onStartKeg() {
if (!mTap.hasMeter()) {
Log.w(TAG, "Can't start keg, no meter.");
}
startActivity(NewKegActivity.getStartIntent(getActivity(), mTap));
}
/** Called when the "end keg" button is pressed. */
private void confirmEndKeg() {
if (mTap == null || !mTap.hasCurrentKeg()) {
Log.w(TAG, "No tap/keg, hmm.");
return;
}
final Keg keg = mTap.getCurrentKeg();
final Spanned message = Html.fromHtml(
String.format(
"Are you sure you want end <b>Keg %s</b> (<i>%s</i>) on tap <b>%s</b>?",
Integer.valueOf(keg.getId()),
keg.getBeverage().getName(),
mTap.getName())
);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton("End Keg", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
doEndKeg();
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
final AlertDialog alert = builder.create();
alert.show();
}
private void doEndKeg() {
final ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setTitle("Ending Keg");
dialog.setMessage("Please wait ...");
dialog.show();
final Keg keg = mTap.getCurrentKeg();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Backend api = KegbotCore.getInstance(getActivity()).getBackend();
try {
api.endKeg(keg);
} catch (BackendException e) {
Log.w(TAG, "Error ending keg: " + e, e);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
dialog.dismiss();
KegbotCore.getInstance(getActivity()).getSyncManager().requestSync();
}
}.execute();
}
private void confirmDeleteTap() {
if (mTap == null) {
Log.wtf(TAG, "No tap, hmm.");
return;
}
final Spanned message = Html.fromHtml(
String.format("Are you sure you want delete tap <b>%s</b>?", mTap.getName()));
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton("Delete Tap", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
doDeleteTap();
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
final AlertDialog alert = builder.create();
alert.show();
}
private void doDeleteTap() {
final ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setTitle("Deleting Tap");
dialog.setMessage("Please wait ...");
dialog.show();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Backend api = KegbotCore.getInstance(getActivity()).getBackend();
try {
api.deleteTap(mTap);
} catch (BackendException e) {
Log.w(TAG, "Error ending tap: " + e, e);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
dialog.dismiss();
KegbotCore.getInstance(getActivity()).getSyncManager().requestSync();
}
}.execute();
}
private class FlowMeterAdapter extends ArrayAdapter<FlowMeter> {
public FlowMeterAdapter(Context context) {
super(context, android.R.layout.simple_spinner_item);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
if (convertView != null) {
view = convertView;
} else {
final LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(android.R.layout.simple_list_item_1, null);
}
final FlowMeter item = getItem(position);
final TextView text = ButterKnife.findById(view, android.R.id.text1);
if (item == null) {
text.setText("Not connected.");
} else {
text.setText(item.getName());
}
return view;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
@Override
public long getItemId(int position) {
if (position == 0) {
return 0;
}
return mMeters.get(position).getId();
}
}
private class FlowToggleAdapter extends ArrayAdapter<Models.FlowToggle> {
public FlowToggleAdapter(Context context) {
super(context, android.R.layout.simple_spinner_item);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
if (convertView != null) {
view = convertView;
} else {
final LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(android.R.layout.simple_list_item_1, null);
}
final Models.FlowToggle item = getItem(position);
final TextView text = ButterKnife.findById(view, android.R.id.text1);
if (item == null) {
text.setText("None.");
} else {
text.setText(item.getName());
}
return view;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
@Override
public long getItemId(int position) {
if (position == 0) {
return 0;
}
return mToggles.get(position).getId();
}
}
}