Refactor and convert to Kotlin base classes. Fix FAB behavior
This commit is contained in:
parent
97ee7b81af
commit
e881488bcc
25 changed files with 342 additions and 521 deletions
|
@ -92,6 +92,7 @@ dependencies {
|
|||
final DAGGER_VERSION = '2.2'
|
||||
final OKHTTP_VERSION = '3.2.0'
|
||||
final RETROFIT_VERSION = '2.0.1'
|
||||
final NUCLEUS_VERSION = '3.0.0-beta'
|
||||
final STORIO_VERSION = '1.8.0'
|
||||
final MOCKITO_VERSION = '1.10.19'
|
||||
|
||||
|
@ -142,7 +143,9 @@ dependencies {
|
|||
kapt "com.pushtorefresh.storio:sqlite-annotations-processor:$STORIO_VERSION"
|
||||
|
||||
// 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
|
||||
compile "com.google.dagger:dagger:$DAGGER_VERSION"
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
|
@ -1,76 +1,9 @@
|
|||
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.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) {
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
if (backNavigation) {
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
}
|
||||
}
|
||||
override fun getActivity() = this
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -5,27 +5,29 @@ import android.support.design.widget.FloatingActionButton
|
|||
import android.support.v4.view.ViewCompat
|
||||
import android.view.View
|
||||
|
||||
open class FABAnimationBase() : FloatingActionButton.Behavior()
|
||||
{
|
||||
open val mIsAnimatingOut = false;
|
||||
abstract class FABAnimationBase() : FloatingActionButton.Behavior() {
|
||||
|
||||
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
|
||||
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
|
||||
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)
|
||||
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
|
||||
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
|
||||
animateIn(child)
|
||||
}
|
||||
}
|
||||
|
||||
open fun animateOut(button : FloatingActionButton) {}
|
||||
open fun animateIn(button : FloatingActionButton) {}
|
||||
abstract fun animateOut(button: FloatingActionButton)
|
||||
abstract fun animateIn(button: FloatingActionButton)
|
||||
}
|
|
@ -9,46 +9,42 @@ import android.view.animation.Animation
|
|||
import android.view.animation.AnimationUtils
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
class FABAnimationUpDown() : FABAnimationBase()
|
||||
{
|
||||
override var mIsAnimatingOut: Boolean = false
|
||||
get() = super.mIsAnimatingOut
|
||||
class FABAnimationUpDown @JvmOverloads constructor(ctx: Context, attrs: AttributeSet? = null) : FABAnimationBase() {
|
||||
|
||||
private val INTERPOLATOR = FastOutSlowInInterpolator()
|
||||
|
||||
/**
|
||||
* Needed to prevent NoSuchMethodException
|
||||
*/
|
||||
constructor(ctx: Context, attrs: AttributeSet) : this() { }
|
||||
private val outAnimation by lazy {
|
||||
AnimationUtils.loadAnimation(ctx, R.anim.fab_hide_to_bottom).apply {
|
||||
duration = 200
|
||||
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) {
|
||||
super.animateIn(button)
|
||||
val anim = AnimationUtils.loadAnimation(button.context, R.anim.fab_hide_to_bottom)
|
||||
anim.interpolator = INTERPOLATOR
|
||||
anim.duration = 200L
|
||||
anim.setAnimationListener(object : Animation.AnimationListener {
|
||||
outAnimation.setAnimationListener(object : Animation.AnimationListener {
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
mIsAnimatingOut = true
|
||||
isAnimatingOut = true
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
mIsAnimatingOut = false
|
||||
isAnimatingOut = false
|
||||
button.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animation) {
|
||||
}
|
||||
})
|
||||
button.startAnimation(anim)
|
||||
|
||||
button.startAnimation(outAnimation)
|
||||
}
|
||||
|
||||
override fun animateIn(button: FloatingActionButton) {
|
||||
super.animateOut(button)
|
||||
button.visibility = View.VISIBLE
|
||||
val anim = AnimationUtils.loadAnimation(button.context, R.anim.fab_show_from_bottom)
|
||||
anim.duration = 200L
|
||||
anim.interpolator = INTERPOLATOR
|
||||
button.startAnimation(anim)
|
||||
button.startAnimation(inAnimation)
|
||||
}
|
||||
}
|
|
@ -1,19 +1,7 @@
|
|||
package eu.kanade.tachiyomi.ui.base.fragment
|
||||
|
||||
import android.support.v4.app.Fragment
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||
|
||||
open class BaseFragment : Fragment() {
|
||||
|
||||
fun setToolbarTitle(title: String) {
|
||||
baseActivity.setToolbarTitle(title)
|
||||
}
|
||||
|
||||
fun setToolbarTitle(resourceId: Int) {
|
||||
baseActivity.setToolbarTitle(getString(resourceId))
|
||||
}
|
||||
|
||||
val baseActivity: BaseActivity
|
||||
get() = activity as BaseActivity
|
||||
abstract class BaseFragment : Fragment(), FragmentMixin {
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -260,7 +260,7 @@ class CategoryActivity : BaseRxActivity<CategoryPresenter>(), ActionMode.Callbac
|
|||
*
|
||||
* @param viewHolder view that contains dragged item
|
||||
*/
|
||||
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder?) {
|
||||
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
|
||||
// Notify touchHelper
|
||||
touchHelper.startDrag(viewHolder)
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ class LibraryAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) {
|
|||
* @param mode the mode to set.
|
||||
*/
|
||||
fun setSelectionMode(mode: Int) {
|
||||
for (fragment in registeredFragments) {
|
||||
for (fragment in getRegisteredFragments()) {
|
||||
(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.
|
||||
*/
|
||||
fun refreshRegisteredAdapters() {
|
||||
for (fragment in registeredFragments) {
|
||||
for (fragment in getRegisteredFragments()) {
|
||||
(fragment as LibraryCategoryFragment).adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.setting
|
|||
|
||||
import android.os.Bundle
|
||||
import android.support.v14.preference.PreferenceFragment
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
|
@ -24,7 +25,7 @@ class SettingsActivity : BaseActivity() {
|
|||
setAppTheme()
|
||||
super.onCreate(savedState)
|
||||
setContentView(R.layout.activity_preferences)
|
||||
app.component.inject(this)
|
||||
App.get(this).component.inject(this)
|
||||
|
||||
setupToolbar(toolbar)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
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'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
Reference in a new issue