package org.kidinov.just_weather.weather.view; import android.Manifest; import android.content.Intent; import android.graphics.Canvas; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.design.widget.BaseTransientBottomBar; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v4.content.ContextCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; import android.widget.ViewFlipper; import com.google.android.gms.location.LocationRequest; import com.patloew.rxlocation.RxLocation; import com.tbruyelle.rxpermissions2.RxPermissions; import org.kidinov.just_weather.App; import org.kidinov.just_weather.R; import org.kidinov.just_weather.util.RxUtil; import org.kidinov.just_weather.weather.DaggerWeatherComponent; import org.kidinov.just_weather.weather.WeatherContract; import org.kidinov.just_weather.weather.model.local.City; import org.kidinov.just_weather.weather.presentation.WeatherPresenter; import org.kidinov.just_weather.weather.presentation.WeatherPresenterModule; import java.util.List; import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import io.reactivex.Observable; import io.reactivex.disposables.CompositeDisposable; import timber.log.Timber; public class WeatherActivity extends AppCompatActivity implements WeatherContract.View { private CompositeDisposable compositeDisposable = new CompositeDisposable(); @Inject WeatherPresenter presenter; @Inject WeatherAdapter adapter; @Inject RxPermissions rxPermissions; @Inject RxLocation rxLocation; @BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout; @BindView(R.id.swipe_refresh_empty_layout) SwipeRefreshLayout swipeRefreshEmptyLayout; @BindView(R.id.recycler_view) RecyclerView recyclerView; @BindView(R.id.view_flipper) ViewFlipper viewFlipper; @BindView(R.id.add_city_button) FloatingActionButton addCityButton; public static Intent startActivityForTesting() { Intent intent = new Intent(); intent.putExtra("test", true); return intent; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DaggerWeatherComponent.builder() .repositoryComponent(((App) getApplication()).getComponent()) .weatherPresenterModule(new WeatherPresenterModule(this)) .weatherActivityModule(new WeatherActivityModule(this)) .build() .inject(this); setContentView(R.layout.weather_activity); ButterKnife.bind(this); initViews(); presenter.subscribe(); presenter.updateData(true); if (!getIntent().getBooleanExtra("test", false)) { getLocation(); } } private void initViews() { recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setHasFixedSize(true); swipeRefreshLayout.setOnRefreshListener(this::fetchAllData); swipeRefreshEmptyLayout.setOnRefreshListener(this::fetchAllData); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (dy > 0) { if (addCityButton.isShown()) { addCityButton.hide(); } } else if (dy < 0 && !addCityButton.isShown()) { addCityButton.show(); } } }); ItemTouchHelper.SimpleCallback itemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { boolean inited; Drawable background; Drawable xMark; int xMarkMargin; private void init() { background = new ColorDrawable(ContextCompat.getColor(WeatherActivity.this, R.color.accent)); xMark = ContextCompat.getDrawable(WeatherActivity.this, R.drawable.ic_delete_white_24dp); xMarkMargin = (int) WeatherActivity.this.getResources().getDimension(R.dimen.default_margin); inited = true; } @Override public boolean onMove(RecyclerView rv, RecyclerView.ViewHolder vh, RecyclerView.ViewHolder target) { return false; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { int swipedPosition = viewHolder.getAdapterPosition(); presenter.itemRemovedAtPosition(swipedPosition); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (!inited) { init(); } View itemView = viewHolder.itemView; background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom()); background.draw(c); // draw x mark int itemHeight = itemView.getBottom() - itemView.getTop(); int intrinsicWidth = xMark.getIntrinsicWidth(); int intrinsicHeight = xMark.getIntrinsicWidth(); int xMarkLeft = itemView.getRight() - xMarkMargin - intrinsicWidth; int xMarkRight = itemView.getRight() - xMarkMargin; int xMarkTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2; int xMarkBottom = xMarkTop + intrinsicHeight; xMark.setBounds(xMarkLeft, xMarkTop, xMarkRight, xMarkBottom); xMark.draw(c); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }; ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallback); itemTouchHelper.attachToRecyclerView(recyclerView); } private void fetchAllData() { getLocation(); presenter.updateData(true); } private void getLocation() { compositeDisposable.add(rxPermissions .request(Manifest.permission.ACCESS_COARSE_LOCATION) .flatMap(granted -> { LocationRequest locationRequest = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); if (granted) { //noinspection MissingPermission return rxLocation .location() .updates(locationRequest) .firstElement() .toObservable(); } else { return Observable.empty(); } }) .doFinally(() -> swipeRefreshEmptyLayout.setRefreshing(false)) .subscribe(location -> { Timber.d("location - %s", location); presenter.addCityByCoordinates(location.getLatitude(), location.getLongitude()); }, Timber::e)); } private void changeScreenState(int state) { viewFlipper.setDisplayedChild(viewFlipper.indexOfChild(viewFlipper.findViewById(state))); } @Override protected void onDestroy() { super.onDestroy(); RxUtil.unsubscribe(compositeDisposable); presenter.unsubscribe(); } @OnClick(R.id.retry_button) void clickOnRetryButton() { presenter.updateData(false); } @OnClick(R.id.add_city_button) void clickOnAddCityButton() { WeatherAddCityDialog.newInstance().show(getSupportFragmentManager(), "WeatherAddCityDialog"); } public void addCityByName(String name) { presenter.addCityByName(name); } @Override public void showProgress() { changeScreenState(R.id.progress_view); } @Override public void showData(List<City> cities) { Timber.d("showData - %d", cities.size()); swipeRefreshLayout.setRefreshing(false); changeScreenState(R.id.swipe_refresh_layout); adapter.setWeatherInCities(cities); } @Override public void showError() { swipeRefreshLayout.setRefreshing(false); changeScreenState(R.id.error_view); } @Override public void showEmptyState() { swipeRefreshLayout.setRefreshing(false); changeScreenState(R.id.swipe_refresh_empty_layout); } @Override public void showNetworkErrorNotification() { Snackbar.make(viewFlipper, R.string.network_error_text, BaseTransientBottomBar.LENGTH_LONG).show(); } @Override public void hideItemAtPosition(int position) { adapter.notifyItemRemoved(position); } @Override public void showCurrentCityDeletionErrorNotification() { Snackbar.make(viewFlipper, R.string.removal_current_error_text, BaseTransientBottomBar.LENGTH_LONG).show(); } }