package com.patloew.countries.ui.base;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.annotation.IntegerRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v7.app.AppCompatActivity;
import com.patloew.countries.BR;
import com.patloew.countries.CountriesApp;
import com.patloew.countries.injection.components.ActivityComponent;
import com.patloew.countries.injection.components.DaggerActivityComponent;
import com.patloew.countries.injection.modules.ActivityModule;
import com.patloew.countries.ui.base.view.MvvmView;
import com.patloew.countries.ui.base.viewmodel.MvvmViewModel;
import com.patloew.countries.ui.base.viewmodel.NoOpViewModel;
import com.squareup.leakcanary.RefWatcher;
import javax.inject.Inject;
import io.realm.Realm;
/* Copyright 2016 Patrick Löwenstein
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -------
*
* FILE MODIFIED 2017 Tailored Media GmbH
* */
/* Base class for Activities when using a view model with data binding.
* This class provides the binding and the view model to the subclass. The
* view model is injected and the binding is created when the content view is set.
* Each subclass therefore has to call the following code in onCreate():
* activityComponent().inject(this);
* setAndBindContentView(R.layout.my_activity_layout, savedInstanceState);
*
* After calling these methods, the binding and the view model is initialized.
* saveInstanceState() and restoreInstanceState() methods of the view model
* are automatically called in the appropriate lifecycle events when above calls
* are made.
*
* Your subclass must implement the MvvmView implementation that you use in your
* view model. */
public abstract class BaseActivity<B extends ViewDataBinding, V extends MvvmViewModel> extends AppCompatActivity {
// Inject a Realm instance into every Activity, since the instance
// is cached and reused for a thread (avoids create/destroy overhead)
@Inject protected Realm realm;
protected B binding;
@Inject protected V viewModel;
@Inject
RefWatcher refWatcher;
private ActivityComponent mActivityComponent;
@Override
@CallSuper
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(viewModel != null) { viewModel.saveInstanceState(outState); }
}
@Override
@CallSuper
protected void onDestroy() {
super.onDestroy();
if(refWatcher != null) {
refWatcher.watch(mActivityComponent);
if(viewModel != null) { refWatcher.watch(viewModel); }
}
if(viewModel != null) { viewModel.detachView(); }
binding = null;
viewModel = null;
mActivityComponent = null;
if(realm != null) { realm.close(); }
}
protected final ActivityComponent activityComponent() {
if (mActivityComponent == null) {
mActivityComponent = DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.appComponent(CountriesApp.getAppComponent())
.build();
}
return mActivityComponent;
}
/* Sets the content view, creates the binding and attaches the view to the view model */
protected final void setAndBindContentView(@Nullable Bundle savedInstanceState, @LayoutRes int layoutResID) {
if(viewModel == null) { throw new IllegalStateException("viewModel must already be set via injection"); }
binding = DataBindingUtil.setContentView(this, layoutResID);
binding.setVariable(BR.vm, viewModel);
try {
//noinspection unchecked
viewModel.attachView((MvvmView) this, savedInstanceState);
} catch(ClassCastException e) {
if (!(viewModel instanceof NoOpViewModel)) {
throw new RuntimeException(getClass().getSimpleName() + " must implement MvvmView subclass as declared in " + viewModel.getClass().getSimpleName());
}
}
}
public int dimen(@DimenRes int resId) {
return (int) getResources().getDimension(resId);
}
public int color(@ColorRes int resId) {
return getResources().getColor(resId);
}
public int integer(@IntegerRes int resId) {
return getResources().getInteger(resId);
}
public String string(@StringRes int resId) {
return getResources().getString(resId);
}
}