Refactor and convert to Kotlin base classes. Fix FAB behavior

This commit is contained in:
len 2016-04-28 21:51:50 +02:00
parent 97ee7b81af
commit e881488bcc
25 changed files with 342 additions and 521 deletions

View File

@ -92,6 +92,7 @@ dependencies {
final DAGGER_VERSION = '2.2' final DAGGER_VERSION = '2.2'
final OKHTTP_VERSION = '3.2.0' final OKHTTP_VERSION = '3.2.0'
final RETROFIT_VERSION = '2.0.1' final RETROFIT_VERSION = '2.0.1'
final NUCLEUS_VERSION = '3.0.0-beta'
final STORIO_VERSION = '1.8.0' final STORIO_VERSION = '1.8.0'
final MOCKITO_VERSION = '1.10.19' final MOCKITO_VERSION = '1.10.19'
@ -142,7 +143,9 @@ dependencies {
kapt "com.pushtorefresh.storio:sqlite-annotations-processor:$STORIO_VERSION" kapt "com.pushtorefresh.storio:sqlite-annotations-processor:$STORIO_VERSION"
// Model View Presenter // Model View Presenter
compile 'info.android15.nucleus:nucleus:3.0.0-beta' compile "info.android15.nucleus:nucleus:$NUCLEUS_VERSION"
compile "info.android15.nucleus:nucleus-support-v4:$NUCLEUS_VERSION"
compile "info.android15.nucleus:nucleus-support-v7:$NUCLEUS_VERSION"
// Dependency injection // Dependency injection
compile "com.google.dagger:dagger:$DAGGER_VERSION" compile "com.google.dagger:dagger:$DAGGER_VERSION"

View File

@ -0,0 +1,75 @@
package eu.kanade.tachiyomi.ui.base.activity
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.ActionBar
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.R
interface ActivityMixin {
fun setupToolbar(toolbar: Toolbar, backNavigation: Boolean = true) {
setSupportActionBar(toolbar)
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true)
if (backNavigation) {
toolbar.setNavigationOnClickListener { onBackPressed() }
}
}
fun setAppTheme() {
setTheme(when (App.get(getActivity()).appTheme) {
2 -> R.style.Theme_Tachiyomi_Dark
else -> R.style.Theme_Tachiyomi
})
}
fun setToolbarTitle(title: String) {
getSupportActionBar()?.title = title
}
fun setToolbarTitle(titleResource: Int) {
getSupportActionBar()?.title = getString(titleResource)
}
fun setToolbarSubtitle(title: String) {
getSupportActionBar()?.subtitle = title
}
fun setToolbarSubtitle(titleResource: Int) {
getSupportActionBar()?.subtitle = getString(titleResource)
}
/**
* Requests read and write permissions on Android M and higher.
*/
fun requestPermissionsOnMarshmallow() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(),
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE),
1)
}
}
}
fun getActivity(): AppCompatActivity
fun onBackPressed()
fun getSupportActionBar(): ActionBar?
fun setSupportActionBar(toolbar: Toolbar?)
fun setTheme(resource: Int)
fun getString(resource: Int): String
}

View File

@ -1,76 +1,9 @@
package eu.kanade.tachiyomi.ui.base.activity package eu.kanade.tachiyomi.ui.base.activity
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.support.design.widget.Snackbar
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.View
import android.widget.TextView
import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.R
open class BaseActivity : AppCompatActivity() { abstract class BaseActivity : AppCompatActivity(), ActivityMixin {
protected fun setupToolbar(toolbar: Toolbar, backNavigation: Boolean = true) { override fun getActivity() = this
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (backNavigation) {
toolbar.setNavigationOnClickListener { onBackPressed() }
}
}
fun setAppTheme() {
when (app.appTheme) {
2 -> setTheme(R.style.Theme_Tachiyomi_Dark)
else -> setTheme(R.style.Theme_Tachiyomi)
}
}
fun setToolbarTitle(title: String) {
supportActionBar?.title = title
}
fun setToolbarTitle(titleResource: Int) {
supportActionBar?.title = getString(titleResource)
}
fun setToolbarSubtitle(title: String) {
supportActionBar?.subtitle = title
}
fun setToolbarSubtitle(titleResource: Int) {
supportActionBar?.subtitle = getString(titleResource)
}
/**
* Requests read and write permissions on Android M and higher.
*/
fun requestPermissionsOnMarshmallow() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE),
1)
} }
}
}
protected val app: App
get() = App.get(this)
inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) {
val snack = Snackbar.make(this, message, length)
val textView = snack.view.findViewById(android.support.design.R.id.snackbar_text) as TextView
textView.setTextColor(Color.WHITE)
snack.f()
snack.show()
}
}

View File

@ -1,94 +0,0 @@
package eu.kanade.tachiyomi.ui.base.activity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import eu.kanade.tachiyomi.App;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import nucleus.factory.PresenterFactory;
import nucleus.factory.ReflectionPresenterFactory;
import nucleus.presenter.Presenter;
import nucleus.view.PresenterLifecycleDelegate;
import nucleus.view.ViewWithPresenter;
/**
* This class is an example of how an activity could controls it's presenter.
* You can inherit from this class or copy/paste this class's code to
* create your own view implementation.
*
* @param <P> a type of presenter to return with {@link #getPresenter}.
*/
public abstract class BaseRxActivity<P extends Presenter> extends BaseActivity implements ViewWithPresenter<P> {
private static final String PRESENTER_STATE_KEY = "presenter_state";
private final PresenterLifecycleDelegate<P> presenterDelegate =
new PresenterLifecycleDelegate<>(ReflectionPresenterFactory.<P>fromViewClass(getClass()));
/**
* Returns a current presenter factory.
*/
public PresenterFactory<P> getPresenterFactory() {
return presenterDelegate.getPresenterFactory();
}
/**
* Sets a presenter factory.
* Call this method before onCreate/onFinishInflate to override default {@link ReflectionPresenterFactory} presenter factory.
* Use this method for presenter dependency injection.
*/
@Override
public void setPresenterFactory(PresenterFactory<P> presenterFactory) {
presenterDelegate.setPresenterFactory(presenterFactory);
}
/**
* Returns a current attached presenter.
* This method is guaranteed to return a non-null value between
* onResume/onPause and onAttachedToWindow/onDetachedFromWindow calls
* if the presenter factory returns a non-null value.
*
* @return a currently attached presenter or null.
*/
public P getPresenter() {
return presenterDelegate.getPresenter();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
final PresenterFactory<P> superFactory = getPresenterFactory();
setPresenterFactory(new PresenterFactory<P>() {
@Override
public P createPresenter() {
P presenter = superFactory.createPresenter();
App app = (App) getApplication();
app.getComponentReflection().inject(presenter);
((BasePresenter) presenter).setContext(app.getApplicationContext());
return presenter;
}
});
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
presenterDelegate.onRestoreInstanceState(savedInstanceState.getBundle(PRESENTER_STATE_KEY));
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBundle(PRESENTER_STATE_KEY, presenterDelegate.onSaveInstanceState());
}
@Override
protected void onResume() {
super.onResume();
presenterDelegate.onResume(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
presenterDelegate.onDropView();
presenterDelegate.onDestroy(!isChangingConfigurations());
}
}

View File

@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.ui.base.activity
import android.os.Bundle
import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import nucleus.view.NucleusAppCompatActivity
abstract class BaseRxActivity<P : BasePresenter<*>> : NucleusAppCompatActivity<P>(), ActivityMixin {
override fun onCreate(savedState: Bundle?) {
val superFactory = presenterFactory
setPresenterFactory {
superFactory.createPresenter().apply {
val app = application as App
app.componentReflection.inject(this)
context = app.applicationContext
}
}
super.onCreate(savedState)
}
override fun getActivity() = this
}

View File

@ -1,48 +0,0 @@
package eu.kanade.tachiyomi.ui.base.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import eu.davidea.flexibleadapter.FlexibleAdapter;
public abstract class FlexibleViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener {
private final FlexibleAdapter adapter;
private final OnListItemClickListener onListItemClickListener;
public FlexibleViewHolder(View itemView,FlexibleAdapter adapter,
OnListItemClickListener onListItemClickListener) {
super(itemView);
this.adapter = adapter;
this.onListItemClickListener = onListItemClickListener;
this.itemView.setOnClickListener(this);
this.itemView.setOnLongClickListener(this);
}
@Override
public void onClick(View view) {
if (onListItemClickListener.onListItemClick(getAdapterPosition())) {
toggleActivation();
}
}
@Override
public boolean onLongClick(View view) {
onListItemClickListener.onListItemLongClick(getAdapterPosition());
toggleActivation();
return true;
}
protected void toggleActivation() {
itemView.setActivated(adapter.isSelected(getAdapterPosition()));
}
public interface OnListItemClickListener {
boolean onListItemClick(int position);
void onListItemLongClick(int position);
}
}

View File

@ -0,0 +1,39 @@
package eu.kanade.tachiyomi.ui.base.adapter
import android.support.v7.widget.RecyclerView
import android.view.View
import eu.davidea.flexibleadapter.FlexibleAdapter
abstract class FlexibleViewHolder(view: View,
private val adapter: FlexibleAdapter<*, *>,
private val itemClickListener: FlexibleViewHolder.OnListItemClickListener) :
RecyclerView.ViewHolder(view), View.OnClickListener, View.OnLongClickListener {
init {
view.setOnClickListener(this)
view.setOnLongClickListener(this)
}
override fun onClick(view: View) {
if (itemClickListener.onListItemClick(adapterPosition)) {
toggleActivation()
}
}
override fun onLongClick(view: View): Boolean {
itemClickListener.onListItemLongClick(adapterPosition)
toggleActivation()
return true
}
protected fun toggleActivation() {
itemView.isActivated = adapter.isSelected(adapterPosition)
}
interface OnListItemClickListener {
fun onListItemClick(position: Int): Boolean
fun onListItemLongClick(position: Int)
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright (C) 2015 Paul Burke
*
* 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.
*/
package eu.kanade.tachiyomi.ui.base.adapter;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
/**
* Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
*
* @author Paul Burke (ipaulpro)
*/
public interface ItemTouchHelperAdapter {
/**
* Called when an item has been dragged far enough to trigger a move. This is called every time
* an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
* <br/>
* Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
* adjusting the underlying data to reflect this move.
*
* @param fromPosition The start position of the moved item.
* @param toPosition Then resolved position of the moved item.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
void onItemMove(int fromPosition, int toPosition);
/**
* Called when an item has been dismissed by a swipe.<br/>
* <br/>
* Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
* adjusting the underlying data to reflect this removal.
*
* @param position The position of the item dismissed.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
void onItemDismiss(int position);
}

View File

@ -0,0 +1,36 @@
package eu.kanade.tachiyomi.ui.base.adapter
/**
* Interface to listen for a move or dismissal event from a [ItemTouchHelper.Callback].
*
* @author Paul Burke (ipaulpro)
*/
interface ItemTouchHelperAdapter {
/**
* Called when an item has been dragged far enough to trigger a move. This is called every time
* an item is shifted, and **not** at the end of a "drop" event.
*
* Implementations should call [RecyclerView.Adapter.notifyItemMoved] after
* adjusting the underlying data to reflect this move.
*
* @param fromPosition The start position of the moved item.
* @param toPosition Then resolved position of the moved item.
* @see [RecyclerView.getAdapterPositionFor]
* @see [RecyclerView.ViewHolder.getAdapterPosition]
*/
fun onItemMove(fromPosition: Int, toPosition: Int)
/**
* Called when an item has been dismissed by a swipe.
*
* Implementations should call [RecyclerView.Adapter.notifyItemRemoved] after
* adjusting the underlying data to reflect this removal.
*
* @param position The position of the item dismissed.
* @see RecyclerView.getAdapterPositionFor
* @see RecyclerView.ViewHolder.getAdapterPosition
*/
fun onItemDismiss(position: Int)
}

View File

@ -1,13 +0,0 @@
package eu.kanade.tachiyomi.ui.base.adapter;
import android.support.v7.widget.RecyclerView;
public interface OnStartDragListener {
/**
* Called when a view is requesting a start of a drag.
*
* @param viewHolder The holder of the view to drag.
*/
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}

View File

@ -0,0 +1,13 @@
package eu.kanade.tachiyomi.ui.base.adapter
import android.support.v7.widget.RecyclerView
interface OnStartDragListener {
/**
* Called when a view is requesting a start of a drag.
*
* @param viewHolder The holder of the view to drag.
*/
fun onStartDrag(viewHolder: RecyclerView.ViewHolder)
}

View File

@ -1,44 +0,0 @@
package eu.kanade.tachiyomi.ui.base.adapter;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter adapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
this.adapter = adapter;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
adapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}

View File

@ -0,0 +1,28 @@
package eu.kanade.tachiyomi.ui.base.adapter
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
open class SimpleItemTouchHelperCallback(private val adapter: ItemTouchHelperAdapter) : ItemTouchHelper.Callback() {
override fun isLongPressDragEnabled() = true
override fun isItemViewSwipeEnabled() = true
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
return ItemTouchHelper.Callback.makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
adapter.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
adapter.onItemDismiss(viewHolder.adapterPosition)
}
}

View File

@ -1,48 +0,0 @@
package eu.kanade.tachiyomi.ui.base.adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.util.SparseArray;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
// Sparse array to keep track of registered fragments in memory
private final SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Register the fragment when the item is instantiated
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
// Unregister when the item is inactive
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
// Returns the fragment for the position (if instantiated)
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
public List<Fragment> getRegisteredFragments() {
ArrayList<Fragment> fragments = new ArrayList<>();
for (int i = 0; i < registeredFragments.size(); i++) {
fragments.add(registeredFragments.valueAt(i));
}
return fragments;
}
}

View File

@ -0,0 +1,41 @@
package eu.kanade.tachiyomi.ui.base.adapter
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter
import android.util.SparseArray
import android.view.ViewGroup
import java.util.*
abstract class SmartFragmentStatePagerAdapter(fragmentManager: FragmentManager) :
FragmentStatePagerAdapter(fragmentManager) {
// Sparse array to keep track of registered fragments in memory
private val registeredFragments = SparseArray<Fragment>()
// Register the fragment when the item is instantiated
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val fragment = super.instantiateItem(container, position) as Fragment
registeredFragments.put(position, fragment)
return fragment
}
// Unregister when the item is inactive
override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any) {
registeredFragments.remove(position)
super.destroyItem(container, position, `object`)
}
// Returns the fragment for the position (if instantiated)
fun getRegisteredFragment(position: Int): Fragment {
return registeredFragments.get(position)
}
fun getRegisteredFragments(): List<Fragment> {
val fragments = ArrayList<Fragment>()
for (i in 0..registeredFragments.size() - 1) {
fragments.add(registeredFragments.valueAt(i))
}
return fragments
}
}

View File

@ -5,27 +5,29 @@ import android.support.design.widget.FloatingActionButton
import android.support.v4.view.ViewCompat import android.support.v4.view.ViewCompat
import android.view.View import android.view.View
open class FABAnimationBase() : FloatingActionButton.Behavior() abstract class FABAnimationBase() : FloatingActionButton.Behavior() {
{
open val mIsAnimatingOut = false;
override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout?, child: FloatingActionButton?, directTargetChild: View?, target: View?, nestedScrollAxes: Int): Boolean { var isAnimatingOut = false
override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton,
directTargetChild: View, target: View, nestedScrollAxes: Int): Boolean {
// Ensure we react to vertical scrolling // Ensure we react to vertical scrolling
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes) super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes)
} }
override fun onNestedScroll(coordinatorLayout: CoordinatorLayout?, child: FloatingActionButton?, target: View?, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int) { override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton, target: View,
dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed) super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
if (dyConsumed > 0 && !this.mIsAnimatingOut && child!!.visibility == View.VISIBLE) { if (dyConsumed > 0 && !isAnimatingOut && child.visibility == View.VISIBLE) {
// User scrolled down and the FAB is currently visible -> hide the FAB // User scrolled down and the FAB is currently visible -> hide the FAB
animateOut(child) animateOut(child)
} else if (dyConsumed < 0 && child!!.visibility != View.VISIBLE) { } else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {
// User scrolled up and the FAB is currently not visible -> show the FAB // User scrolled up and the FAB is currently not visible -> show the FAB
animateIn(child) animateIn(child)
} }
} }
open fun animateOut(button : FloatingActionButton) {} abstract fun animateOut(button: FloatingActionButton)
open fun animateIn(button : FloatingActionButton) {} abstract fun animateIn(button: FloatingActionButton)
} }

View File

@ -9,46 +9,42 @@ import android.view.animation.Animation
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
class FABAnimationUpDown() : FABAnimationBase() class FABAnimationUpDown @JvmOverloads constructor(ctx: Context, attrs: AttributeSet? = null) : FABAnimationBase() {
{
override var mIsAnimatingOut: Boolean = false
get() = super.mIsAnimatingOut
private val INTERPOLATOR = FastOutSlowInInterpolator() private val INTERPOLATOR = FastOutSlowInInterpolator()
/** private val outAnimation by lazy {
* Needed to prevent NoSuchMethodException AnimationUtils.loadAnimation(ctx, R.anim.fab_hide_to_bottom).apply {
*/ duration = 200
constructor(ctx: Context, attrs: AttributeSet) : this() { } interpolator = INTERPOLATOR
}
}
private val inAnimation by lazy {
AnimationUtils.loadAnimation(ctx, R.anim.fab_show_from_bottom).apply {
duration = 200
interpolator = INTERPOLATOR
}
}
override fun animateOut(button: FloatingActionButton) { override fun animateOut(button: FloatingActionButton) {
super.animateIn(button) outAnimation.setAnimationListener(object : Animation.AnimationListener {
val anim = AnimationUtils.loadAnimation(button.context, R.anim.fab_hide_to_bottom)
anim.interpolator = INTERPOLATOR
anim.duration = 200L
anim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) { override fun onAnimationStart(animation: Animation) {
mIsAnimatingOut = true isAnimatingOut = true
} }
override fun onAnimationEnd(animation: Animation) { override fun onAnimationEnd(animation: Animation) {
mIsAnimatingOut = false isAnimatingOut = false
button.visibility = View.GONE button.visibility = View.GONE
} }
override fun onAnimationRepeat(animation: Animation) { override fun onAnimationRepeat(animation: Animation) {
} }
}) })
button.startAnimation(anim) button.startAnimation(outAnimation)
} }
override fun animateIn(button: FloatingActionButton) { override fun animateIn(button: FloatingActionButton) {
super.animateOut(button)
button.visibility = View.VISIBLE button.visibility = View.VISIBLE
val anim = AnimationUtils.loadAnimation(button.context, R.anim.fab_show_from_bottom) button.startAnimation(inAnimation)
anim.duration = 200L
anim.interpolator = INTERPOLATOR
button.startAnimation(anim)
} }
} }

View File

@ -1,19 +1,7 @@
package eu.kanade.tachiyomi.ui.base.fragment package eu.kanade.tachiyomi.ui.base.fragment
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
open class BaseFragment : Fragment() { abstract class BaseFragment : Fragment(), FragmentMixin {
fun setToolbarTitle(title: String) {
baseActivity.setToolbarTitle(title)
}
fun setToolbarTitle(resourceId: Int) {
baseActivity.setToolbarTitle(getString(resourceId))
}
val baseActivity: BaseActivity
get() = activity as BaseActivity
} }

View File

@ -1,97 +0,0 @@
package eu.kanade.tachiyomi.ui.base.fragment;
import android.os.Bundle;
import eu.kanade.tachiyomi.App;
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
import nucleus.factory.PresenterFactory;
import nucleus.factory.ReflectionPresenterFactory;
import nucleus.presenter.Presenter;
import nucleus.view.PresenterLifecycleDelegate;
import nucleus.view.ViewWithPresenter;
/**
* This view is an example of how a view should control it's presenter.
* You can inherit from this class or copy/paste this class's code to
* create your own view implementation.
*
* @param <P> a type of presenter to return with {@link #getPresenter}.
*/
public abstract class BaseRxFragment<P extends Presenter> extends BaseFragment implements ViewWithPresenter<P> {
private static final String PRESENTER_STATE_KEY = "presenter_state";
private final PresenterLifecycleDelegate<P> presenterDelegate =
new PresenterLifecycleDelegate<>(ReflectionPresenterFactory.<P>fromViewClass(getClass()));
/**
* Returns a current presenter factory.
*/
public PresenterFactory<P> getPresenterFactory() {
return presenterDelegate.getPresenterFactory();
}
/**
* Sets a presenter factory.
* Call this method before onCreate/onFinishInflate to override default {@link ReflectionPresenterFactory} presenter factory.
* Use this method for presenter dependency injection.
*/
@Override
public void setPresenterFactory(PresenterFactory<P> presenterFactory) {
presenterDelegate.setPresenterFactory(presenterFactory);
}
/**
* Returns a current attached presenter.
* This method is guaranteed to return a non-null value between
* onResume/onPause and onAttachedToWindow/onDetachedFromWindow calls
* if the presenter factory returns a non-null value.
*
* @return a currently attached presenter or null.
*/
public P getPresenter() {
return presenterDelegate.getPresenter();
}
@Override
public void onCreate(Bundle bundle) {
final PresenterFactory<P> superFactory = getPresenterFactory();
setPresenterFactory(new PresenterFactory<P>() {
@Override
public P createPresenter() {
P presenter = superFactory.createPresenter();
App app = (App) getActivity().getApplication();
app.getComponentReflection().inject(presenter);
((BasePresenter) presenter).setContext(app.getApplicationContext());
return presenter;
}
});
super.onCreate(bundle);
if (bundle != null)
presenterDelegate.onRestoreInstanceState(bundle.getBundle(PRESENTER_STATE_KEY));
}
@Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putBundle(PRESENTER_STATE_KEY, presenterDelegate.onSaveInstanceState());
}
@Override
public void onResume() {
super.onResume();
presenterDelegate.onResume(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
presenterDelegate.onDropView();
}
@Override
public void onDestroy() {
super.onDestroy();
presenterDelegate.onDestroy(!getActivity().isChangingConfigurations());
}
}

View File

@ -0,0 +1,21 @@
package eu.kanade.tachiyomi.ui.base.fragment
import android.os.Bundle
import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import nucleus.view.NucleusSupportFragment
abstract class BaseRxFragment<P : BasePresenter<*>> : NucleusSupportFragment<P>(), FragmentMixin {
override fun onCreate(savedState: Bundle?) {
val superFactory = presenterFactory
setPresenterFactory {
superFactory.createPresenter().apply {
val app = activity.application as App
app.componentReflection.inject(this)
context = app.applicationContext
}
}
super.onCreate(savedState)
}
}

View File

@ -0,0 +1,22 @@
package eu.kanade.tachiyomi.ui.base.fragment
import android.support.v4.app.FragmentActivity
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
interface FragmentMixin {
fun setToolbarTitle(title: String) {
baseActivity.setToolbarTitle(title)
}
fun setToolbarTitle(resourceId: Int) {
baseActivity.setToolbarTitle(getString(resourceId))
}
val baseActivity: BaseActivity
get() = getActivity() as BaseActivity
fun getActivity(): FragmentActivity
fun getString(resource: Int): String
}

View File

@ -260,7 +260,7 @@ class CategoryActivity : BaseRxActivity<CategoryPresenter>(), ActionMode.Callbac
* *
* @param viewHolder view that contains dragged item * @param viewHolder view that contains dragged item
*/ */
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder?) { override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
// Notify touchHelper // Notify touchHelper
touchHelper.startDrag(viewHolder) touchHelper.startDrag(viewHolder)
} }

View File

@ -62,7 +62,7 @@ class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
* @param mode the mode to set. * @param mode the mode to set.
*/ */
fun setSelectionMode(mode: Int) { fun setSelectionMode(mode: Int) {
for (fragment in registeredFragments) { for (fragment in getRegisteredFragments()) {
(fragment as LibraryCategoryFragment).setSelectionMode(mode) (fragment as LibraryCategoryFragment).setSelectionMode(mode)
} }
} }
@ -71,7 +71,7 @@ class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
* Notifies the adapters in all the registered fragments to refresh their content. * Notifies the adapters in all the registered fragments to refresh their content.
*/ */
fun refreshRegisteredAdapters() { fun refreshRegisteredAdapters() {
for (fragment in registeredFragments) { for (fragment in getRegisteredFragments()) {
(fragment as LibraryCategoryFragment).adapter.notifyDataSetChanged() (fragment as LibraryCategoryFragment).adapter.notifyDataSetChanged()
} }
} }

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle import android.os.Bundle
import android.support.v14.preference.PreferenceFragment import android.support.v14.preference.PreferenceFragment
import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
@ -24,7 +25,7 @@ class SettingsActivity : BaseActivity() {
setAppTheme() setAppTheme()
super.onCreate(savedState) super.onCreate(savedState)
setContentView(R.layout.activity_preferences) setContentView(R.layout.activity_preferences)
app.component.inject(this) App.get(this).component.inject(this)
setupToolbar(toolbar) setupToolbar(toolbar)

View File

@ -6,7 +6,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.0.0' classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0' classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files