/**
* Copyright (C) 2013 - 2015 the enviroCar community
*
* This file is part of the enviroCar app.
*
* The enviroCar app 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.
*
* The enviroCar app 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 the enviroCar app. If not, see http://www.gnu.org/licenses/.
*/
package org.envirocar.app.view.tracklist;
import android.app.Activity;
import android.os.AsyncTask;
import android.view.View;
import com.squareup.otto.Subscribe;
import org.envirocar.app.R;
import org.envirocar.app.view.trackdetails.TrackDetailsActivity;
import org.envirocar.app.view.utils.ECAnimationUtils;
import org.envirocar.core.entity.Track;
import org.envirocar.core.events.NewUserSettingsEvent;
import org.envirocar.core.exception.NotConnectedException;
import org.envirocar.core.exception.UnauthorizedException;
import org.envirocar.core.injection.Injector;
import org.envirocar.core.logging.Logger;
import java.util.Collections;
import java.util.List;
import rx.Observer;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
/**
* @author dewall
*/
public class TrackListRemoteCardFragment extends AbstractTrackListCardFragment<
TrackListRemoteCardAdapter> implements TrackListLocalCardFragment.OnTrackUploadedListener {
private static final Logger LOG = Logger.getLogger(TrackListRemoteCardFragment.class);
private CompositeSubscription subscriptions = new CompositeSubscription();
private boolean hasLoadedRemote = false;
private boolean hasLoadedStored = false;
private boolean isSorted = false;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((Injector) activity).injectObjects(this);
}
@Override
public void onResume() {
super.onResume();
if (mUserManager.isLoggedIn()) {
mRecyclerView.setVisibility(View.VISIBLE);
infoView.setVisibility(View.GONE);
} else {
showText(R.drawable.img_logged_out,
R.string.track_list_bg_not_logged_in,
R.string.track_list_bg_not_logged_in_sub);
mProgressView.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.GONE);
mRecyclerViewAdapter.mTrackDataset.clear();
mRecyclerViewAdapter.notifyDataSetChanged();
}
}
@Override
public void onDestroyView() {
LOG.info("onDestroyView()");
super.onDestroyView();
if (!subscriptions.isUnsubscribed()) {
subscriptions.unsubscribe();
}
}
@Override
public TrackListRemoteCardAdapter getRecyclerViewAdapter() {
return new TrackListRemoteCardAdapter(getContext(), mTrackList,
new OnTrackInteractionCallback() {
/**
* Inits the view transition to a {@link TrackDetailsActivity} showing the
* details for the given track.
*
* @param track the track to show the details for.
* @param transitionView the transitionView used for scene transition.
*/
@Override
public void onTrackDetailsClicked(Track track, View transitionView) {
LOG.info(String.format("onTrackDetailsClicked(%s)", track.getTrackID()
.toString()));
int trackID = (int) track.getTrackID().getId();
TrackDetailsActivity.navigate(getActivity(), transitionView, trackID);
}
@Override
public void onDeleteTrackClicked(Track track) {
LOG.info(String.format("onDeleteTrackClicked(%s)", track.getTrackID()));
// create a dialog
createDeleteTrackDialog(track);
}
@Override
public void onUploadTrackClicked(Track track) {
LOG.info(String.format("onUploadTrackClicked(%s)", track.getTrackID()));
// Upload the track
LOG.warn("onUploadTrackClicked() on remote tracks has no effect.");
}
@Override
public void onExportTrackClicked(Track track) {
LOG.info(String.format("onExportTrackClicked(%s)", track.getTrackID()));
exportTrack(track);
}
@Override
public void onDownloadTrackClicked(Track track, AbstractTrackListCardAdapter
.TrackCardViewHolder viewHolder) {
onDownloadTrackClickedInner(track, viewHolder);
}
});
}
@Override
protected void loadDataset() {
// Do not load the dataset twice.
if (mUserManager.isLoggedIn() && !tracksLoaded) {
tracksLoaded = true;
new LoadRemoteTracksTask().execute();
}
}
@Subscribe
public void onReceiveNewUserSettingsEvent(NewUserSettingsEvent event) {
if (!event.mIsLoggedIn) {
mMainThreadWorker.schedule(() -> {
mRecyclerViewAdapter.mTrackDataset.clear();
mRecyclerViewAdapter.notifyDataSetChanged();
tracksLoaded = false;
});
}
}
private void onDownloadTrackClickedInner(final Track track, AbstractTrackListCardAdapter
.TrackCardViewHolder viewHolder) {
AbstractTrackListCardAdapter.RemoteTrackCardViewHolder holder =
(AbstractTrackListCardAdapter.RemoteTrackCardViewHolder) viewHolder;
// Show the downloading text notification.
ECAnimationUtils.animateShowView(getContext(), holder.mDownloadNotification,
R.anim.fade_in);
holder.mProgressCircle.show();
track.setDownloadState(Track.DownloadState.DOWNLOADING);
mTrackDAOHandler.fetchRemoteTrackObservable(track)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Track>() {
@Override
public void onCompleted() {
holder.mProgressCircle.beginFinalAnimation();
holder.mProgressCircle.attachListener(() -> {
// When the visualization is finished, then Init the
// content view including its mapview and track details.
mRecyclerViewAdapter.bindLocalTrackViewHolder(holder, track);
// and hide the download button
ECAnimationUtils.animateHideView(getContext(), R.anim.fade_out,
holder.mProgressCircle, holder.mDownloadButton, holder
.mDownloadNotification);
ECAnimationUtils.animateShowView(getContext(), holder.mContentView, R
.anim.fade_in);
});
}
@Override
public void onError(Throwable e) {
LOG.error("Not connected exception", e);
showSnackbar(R.string.track_list_communication_error);
holder.mProgressCircle.hide();
track.setDownloadState(Track.DownloadState.DOWNLOADING);
holder.mDownloadNotification.setText(
R.string.track_list_error_while_downloading);
}
@Override
public void onNext(Track remoteTrack) {
LOG.info("Successfully fetched remote track:");
}
});
}
private final class LoadRemoteTracksTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
// Wait until the activity has been attached.
synchronized (attachingActivityLock) {
while (!isAttached) {
try {
attachingActivityLock.wait();
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
}
}
subscriptions.add(mEnvirocarDB.getAllRemoteTracks()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Track>>() {
@Override
public void onStart() {
LOG.info("onStart() tracks in db");
mMainThreadWorker.schedule(() -> {
mProgressView.setVisibility(View.VISIBLE);
mProgressText.setText(R.string.track_list_loading_tracks);
});
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
LOG.error(e.getMessage(), e);
showSnackbar(R.string.track_list_loading_lremote_tracks_error);
}
@Override
public void onNext(List<Track> tracks) {
LOG.info("onNext(" + tracks.size() + ") locally stored tracks");
for (Track track : tracks) {
if (track.getMeasurements() != null &&
!track.getMeasurements().isEmpty()) {
if (mTrackList.contains(track)) {
mTrackList.set(mTrackList.indexOf(track), track);
} else {
mTrackList.add(track);
}
}
}
hasLoadedStored = true;
updateView();
}
}));
subscriptions.add(mDAOProvider.getTrackDAO().getTrackIdsObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Track>>() {
@Override
public void onStart() {
LOG.info("onStart() tracks in db");
mMainThreadWorker.schedule(() -> {
mProgressView.setVisibility(View.VISIBLE);
mProgressText.setText(R.string.track_list_loading_tracks);
});
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
LOG.error(e.getMessage(), e);
if (e instanceof NotConnectedException) {
showSnackbar(R.string.track_list_loading_remote_tracks_error);
if (mTrackList.isEmpty()) {
showText(R.drawable.img_disconnected,
R.string.track_list_bg_no_connection,
R.string.track_list_bg_no_connection_sub);
}
} else if (e instanceof UnauthorizedException) {
showSnackbar(R.string.track_list_bg_unauthorized);
if (mTrackList.isEmpty()) {
showText(R.drawable.img_logged_out,
R.string.track_list_bg_unauthorized,
R.string.track_list_bg_unauthorized_sub);
}
}
ECAnimationUtils.animateHideView(getContext(), mProgressView,
R.anim.fade_out);
}
@Override
public void onNext(List<Track> tracks) {
LOG.info("onNext(" + tracks.size() + ") remotely stored tracks");
// Add all tracks to the track list that are not in the
// list so far
for (Track track : tracks) {
if (!mTrackList.contains(track)) {
mTrackList.add(track);
}
}
hasLoadedRemote = true;
// Sort the list and update the list
updateView();
}
}));
return null;
}
}
@Override
public void onTrackUploaded(Track track) {
mEnvirocarDB.getTrack(track.getTrackID())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(track1 -> {
mTrackList.add(track1);
mRecyclerViewAdapter.notifyDataSetChanged();
});
}
private void updateView() {
if (hasLoadedStored && hasLoadedRemote) {
if (!isSorted) {
isSorted = true;
Collections.sort(mTrackList);
}
ECAnimationUtils.animateHideView(getContext(), mProgressView, R.anim.fade_out);
if (mTrackList.isEmpty()) {
showText(R.drawable.img_tracks,
R.string.track_list_bg_no_remote_tracks,
R.string.track_list_bg_no_remote_tracks_sub);
}
}
if (!mTrackList.isEmpty()) {
mRecyclerView.setVisibility(View.VISIBLE);
infoView.setVisibility(View.GONE);
mRecyclerViewAdapter.notifyDataSetChanged();
}
}
}