/* * The CroudTrip! application aims at revolutionizing the car-ride-sharing market with its easy, * user-friendly and highly automated way of organizing shared Trips. Copyright (C) 2015 Nazeeh Ammari, * Philipp Eichhorn, Ricarda Hohn, Vanessa Lange, Alexander Popp, Frederik Simon, Michael Weber * This program is free software: you can redistribute it and/or modify it under the terms of the GNU * Affero 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 Affero General Public License for more details. * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package org.croudtrip.fragments; import android.app.Dialog; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.NumberPicker; import android.widget.Toast; import com.larswerkman.holocolorpicker.ColorPicker; import com.larswerkman.holocolorpicker.SVBar; import com.pnikosis.materialishprogress.ProgressWheel; import org.croudtrip.R; import org.croudtrip.account.AccountManager; import org.croudtrip.account.VehicleManager; import org.croudtrip.api.TripsResource; import org.croudtrip.api.VehicleResource; import org.croudtrip.api.account.User; import org.croudtrip.api.account.Vehicle; import org.croudtrip.api.account.VehicleDescription; import org.croudtrip.api.trips.TripOffer; import org.croudtrip.utils.CrashCallback; import org.croudtrip.utils.DataHolder; import org.croudtrip.utils.DefaultTransformer; import java.util.List; import javax.inject.Inject; import retrofit.client.Response; import rx.Observable; import rx.Subscription; import rx.functions.Action1; import rx.functions.Func1; import timber.log.Timber; /** * This fragment allows the user to enter the vehicle information and uploads this information to the server * * @author nazeehammari */ public class VehicleInfoFragment extends SubscriptionFragment { @Inject private TripsResource tripsResource; @Inject private VehicleResource vehicleResource; private ProgressWheel progressBar; private String newCarType, newCarPlate, newColor; private Integer newCarCapacity; private EditText carTypeEdit, carPlateEdit; private Button colorPickerButton, capacityPickerButton, updateInfo, deleteVehicle; private int vehicleId = DataHolder.getInstance().getVehicle_id(); private User user; private long userId = -1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); View view = inflater.inflate(R.layout.fragment_vehicle_info, container, false); progressBar = (ProgressWheel) view.findViewById(R.id.pb_add_vehicle); if (vehicleId != -1 && vehicleId !=-2) getVehicle(vehicleId); //Fetches vehicle info from the server and updates the corresponding local variables carTypeEdit = (EditText) view.findViewById(R.id.car_type); carPlateEdit = (EditText) view.findViewById(R.id.car_plate); capacityPickerButton = (Button) view.findViewById(R.id.capacity_picker_button); colorPickerButton = (Button) view.findViewById(R.id.color_picker_button); updateInfo = (Button) view.findViewById(R.id.update_info); deleteVehicle = (Button) view.findViewById(R.id.delete_vehicle); if (vehicleId == -1 || vehicleId == -2) updateInfo.setText(getString(R.string.add_vehicle)); else updateInfo.setText(getString(R.string.save_changes)); if (vehicleId == -2) carPlateEdit.requestFocus(); if (vehicleId != -1 && vehicleId != -2) deleteVehicle.setVisibility(View.VISIBLE); Timber.i(vehicleId+""); this.user = AccountManager.getLoggedInUser(this.getActivity().getApplicationContext()); if (user != null) userId = user.getId(); setFields(); updateInfo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { saveCarChanges(vehicleId); } }); deleteVehicle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { progressBar.setVisibility(View.VISIBLE); vehicleId = DataHolder.getInstance().getVehicle_id(); //Get a list of offers and iterate over them to check if the vehicle is being used before attempting to remove it subscriptions.add(tripsResource.getOffers(false) .compose(new DefaultTransformer<List<TripOffer>>()) .flatMap(new Func1<List<TripOffer>, Observable<TripOffer>>() { @Override public Observable<TripOffer> call(List<TripOffer> tripOffers) { //Remove the vehicle if there are no offers if (tripOffers.isEmpty()) { Timber.d("tripOffers is empty"); removeVehicle(vehicleId); deleteVehicle.setVisibility(View.INVISIBLE); vehicleId = -1; updateInfo.setText(getString(R.string.add_vehicle)); } else { //Iterate over the offers to check if the vehicle is being used for (int i = 0; i < tripOffers.size(); i++) { Timber.d("tripOffers has size: " + tripOffers.size()); //Notify the user if the vehicle is being used in any trip offers if (tripOffers.get(i).getVehicle().getId() == vehicleId && userId == tripOffers.get(i).getDriver().getId()) { Toast.makeText(getActivity(), getResources().getString(R.string.vehicle_in_use), Toast.LENGTH_SHORT).show(); Timber.d("The targeted car is in use with id: " + tripOffers.get(i).getVehicle().getId()); progressBar.setVisibility(View.GONE); } else { //Remove the vehicle if it's not being used in any of the trip offers Timber.d("Vehicle is not being used"); removeVehicle(vehicleId); deleteVehicle.setVisibility(View.INVISIBLE); vehicleId = -1; updateInfo.setText(getString(R.string.add_vehicle)); } } } return null; } }).subscribe(new Action1<TripOffer>() { @Override public void call(TripOffer offer) { } }, new CrashCallback(getActivity(), "failed to remove car", new Action1<Throwable>() { @Override public void call(Throwable throwable) { progressBar.setVisibility(View.GONE); } }))); } }); capacityPickerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showCapacityPicker(); } }); colorPickerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showColorPicker(); } }); carTypeEdit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { newCarType = carTypeEdit.getText().toString(); } }); carPlateEdit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { newCarPlate = carPlateEdit.getText().toString(); } }); return view; } public void showColorPicker() { final Dialog colorDialog = new Dialog(getActivity()); colorDialog.setTitle(Html.fromHtml("<font color='#388e3c'>Select car color</font>")); colorDialog.setContentView(R.layout.color_picker_dialog); Button set = (Button) colorDialog.findViewById(R.id.set); Button cancel = (Button) colorDialog.findViewById(R.id.cancel); final ColorPicker colorPicker = (ColorPicker) colorDialog.findViewById(R.id.color_picker); SVBar saturationBar = (SVBar) colorDialog.findViewById(R.id.saturation_bar); colorPicker.addSVBar(saturationBar); colorDialog.show(); //Change divider line color int titleDividerId = getResources().getIdentifier("titleDivider", "id", "android"); View titleDivider = colorDialog.findViewById(titleDividerId); if (titleDivider != null) titleDivider.setBackgroundColor(getResources().getColor(R.color.primary)); set.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { colorPickerButton.setBackgroundColor(colorPicker.getColor()); newColor = String.valueOf(colorPicker.getColor()); colorDialog.hide(); } }); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { colorDialog.hide(); } }); } public void showCapacityPicker() { final Dialog capacityDialog = new Dialog(getActivity()); capacityDialog.setTitle(Html.fromHtml("<font color='#388e3c'>Car Capacity</font>")); capacityDialog.setContentView(R.layout.capacity_picker_dialog); Button set = (Button) capacityDialog.findViewById(R.id.set); Button cancel = (Button) capacityDialog.findViewById(R.id.cancel); final NumberPicker capacityPicker = (NumberPicker) capacityDialog.findViewById(R.id.capacity_picker); capacityPicker.setMaxValue(4); capacityPicker.setMinValue(1); capacityPicker.setWrapSelectorWheel(false); capacityPicker.setValue(Integer.parseInt(capacityPickerButton.getText().toString())); setDividerColor(capacityPicker, getResources().getColor(R.color.primary)); capacityDialog.show(); //Change divider line color int titleDividerId = getResources().getIdentifier("titleDivider", "id", "android"); View titleDivider = capacityDialog.findViewById(titleDividerId); if (titleDivider != null) titleDivider.setBackgroundColor(getResources().getColor(R.color.primary)); set.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { newCarCapacity = capacityPicker.getValue(); capacityPickerButton.setText(newCarCapacity.toString()); capacityDialog.hide(); } }); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { capacityDialog.hide(); } }); } private void setDividerColor(NumberPicker picker, int color) { java.lang.reflect.Field[] pickerFields = NumberPicker.class.getDeclaredFields(); for (java.lang.reflect.Field pf : pickerFields) { if (pf.getName().equals("mSelectionDivider")) { pf.setAccessible(true); try { ColorDrawable colorDrawable = new ColorDrawable(color); pf.set(picker, colorDrawable); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Resources.NotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } break; } } } public void getVehicle(int id) { progressBar.setVisibility(View.VISIBLE); Subscription subscription = vehicleResource.getVehicle(id) .compose(new DefaultTransformer<Vehicle>()) .subscribe(new Action1<Vehicle>() { @Override public void call(Vehicle vehicle) { newCarPlate = vehicle.getLicensePlate(); newColor = vehicle.getColor(); newCarCapacity = vehicle.getCapacity(); newCarType = vehicle.getType(); //Set fields to values fetched from the server setFields(); progressBar.setVisibility(View.GONE); } }, new CrashCallback(getActivity(), "failed to get car", new Action1<Throwable>() { @Override public void call(Throwable throwable) { progressBar.setVisibility(View.GONE); } })); subscriptions.add(subscription); } public void addVehicle(final VehicleDescription vehicleDescription) { progressBar.setVisibility(View.VISIBLE); Subscription subscription = vehicleResource.addVehicle(vehicleDescription) .compose(new DefaultTransformer<Vehicle>()) .subscribe(new Action1<Vehicle>() { @Override public void call(Vehicle vehicle) { Toast.makeText(getActivity(), "New car added!", Toast.LENGTH_SHORT).show(); Timber.v("New car added!"); VehicleInfoFragment.this.getActivity().onBackPressed(); if (VehicleManager.getDefaultVehicleId(getActivity()) == -3) VehicleManager.saveDefaultVehicle(getActivity(), vehicle.getId()); progressBar.setVisibility(View.GONE); } }, new CrashCallback(getActivity(), "failed to add car", new Action1<Throwable>() { @Override public void call(Throwable throwable) { progressBar.setVisibility(View.GONE); } })); subscriptions.add(subscription); } public void removeVehicle(int id) { Subscription subscription = vehicleResource.removeVehicle(id) .compose(new DefaultTransformer<Response>()) .subscribe(new Action1<Response>() { @Override public void call(Response response) { VehicleInfoFragment.this.getActivity().onBackPressed(); Toast.makeText(getActivity(), "Car removed!", Toast.LENGTH_SHORT).show(); //Set default to -3 if the user deletes the last available car if (DataHolder.getInstance().getIsLast() == true) VehicleManager.saveDefaultVehicle(getActivity(), -3); progressBar.setVisibility(View.GONE); } }, new CrashCallback(getActivity(), "failed to remove car", new Action1<Throwable>() { @Override public void call(Throwable throwable) { progressBar.setVisibility(View.GONE); } })); subscriptions.add(subscription); } public void updateVehicle(int id, VehicleDescription vehicleDescription) { progressBar.setVisibility(View.VISIBLE); Subscription subscription = vehicleResource.updateVehicle(id, vehicleDescription) .compose(new DefaultTransformer<Vehicle>()) .subscribe(new Action1<Vehicle>() { @Override public void call(Vehicle vehicle) { VehicleInfoFragment.this.getActivity().onBackPressed(); Toast.makeText(getActivity(), "Updated car info", Toast.LENGTH_SHORT).show(); Timber.v("Updated car info"); progressBar.setVisibility(View.GONE); } }, new CrashCallback(getActivity(), "failed to update car", new Action1<Throwable>() { @Override public void call(Throwable throwable) { progressBar.setVisibility(View.GONE); } })); subscriptions.add(subscription); } public void saveCarChanges(int vehicleId) { VehicleDescription vehicleDescription = new VehicleDescription(newCarPlate, newColor, newCarType, newCarCapacity); //check if car type and plate were entered before updating vehicle info (mandatory fields) if ((carPlateEdit.getText() != null && carPlateEdit.length() > 0) && carTypeEdit.getText() != null && carTypeEdit.length() > 0) { if (vehicleId == -1 || vehicleId == -2) { addVehicle(vehicleDescription); } else if (vehicleId != 0) { updateVehicle(vehicleId, vehicleDescription); } } else { //detect which edit text is empty if (carTypeEdit.getText() == null || carTypeEdit.length() == 0) { Toast.makeText(getActivity(), "Car Type field is mandatory", Toast.LENGTH_SHORT).show(); } else if (carPlateEdit.getText() == null || carPlateEdit.length() == 0) { Toast.makeText(getActivity(), "Car Plate field is mandatory", Toast.LENGTH_SHORT).show(); } } } public void setFields() { if (newCarPlate != null) { carPlateEdit.setText(newCarPlate); } else { carPlateEdit.setHint(R.string.car_plate_hint); } if (newCarType != null) { carTypeEdit.setText(newCarType); } else { carTypeEdit.setHint(R.string.car_type_hint); } if (newColor != null) { colorPickerButton.setBackgroundColor(Integer.parseInt(newColor)); } else { colorPickerButton.setBackgroundColor(Color.WHITE); newColor = String.valueOf(Color.WHITE); } if (newCarCapacity != null) { capacityPickerButton.setText(String.valueOf(newCarCapacity)); } else { capacityPickerButton.setText("1"); newCarCapacity = 1; } } }