package com.cusnews.utils;
import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.List;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.view.View.OnClickListener;
import com.cusnews.R;
import com.cusnews.app.App;
import com.cusnews.bus.BookmarksInitEvent;
import com.cusnews.bus.BookmarksLoadingErrorEvent;
import com.cusnews.ds.Bookmark;
import com.cusnews.ds.Entry;
import com.software.shell.fab.ActionButton;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.listener.DeleteListener;
import cn.bmob.v3.listener.FindListener;
import cn.bmob.v3.listener.SaveListener;
import de.greenrobot.event.EventBus;
/**
* A manager to control adding, removing, loading {@link com.cusnews.ds.Bookmark}s.
*
* @author Xinyue Zhao
*/
public class BookmarksManager {
/**
* Cached list of all {@link Bookmark}s from backend.
*/
private List<Bookmark> mCachedBookmarks = new LinkedList<>();
/**
* Singleton.
*/
private static BookmarksManager sInstance = new BookmarksManager();
/**
* {@code true} if init cache-list.
*/
private volatile boolean mInit;
/**
* @return The instance of singleton pattern.
*/
public static BookmarksManager getInstance() {
return sInstance;
}
/**
* No one can create this class.
*/
private BookmarksManager() {
}
/**
* For initialize the manger.
*/
public synchronized void init() {
//Load from backend.
BmobQuery<Bookmark> queryTabLabels = new BmobQuery<>();
queryTabLabels.addWhereEqualTo( "mUID", Prefs.getInstance().getGoogleId() );
queryTabLabels.findObjects( App.Instance, new FindListener<Bookmark>() {
@Override
public void onSuccess( List<Bookmark> list ) {
for( Bookmark bookmark : list ) {
boolean found = false;
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( bookmark ) ) {
found = true;
break;
}
}
if( !found ) {
mCachedBookmarks.add( bookmark );
}
}
mInit = true;
EventBus.getDefault().post( new BookmarksInitEvent() );
}
@Override
public void onError( int i, String s ) {
mInit = false;
EventBus.getDefault().post( new BookmarksLoadingErrorEvent() );
}
} );
}
/**
* To check whether the {@link Entry} had been bookmarked or not.
*
* @param entry
* {@link Entry}.
*
* @return {@code true} was bookmarked.
*/
public boolean isBookmarked( Entry entry ) {
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( entry ) ) {
return true;
}
}
return false;
}
/**
* To check whether the {@link Entry} had been bookmarked or not.
*
* @param entry
* {@link Entry}.
*
* @return A {@link Bookmark} returned if {@code entry} was bookmarked before, otherwise {@code null} returns.
*/
@Nullable
public Bookmark findBookmarked( Entry entry ) {
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( entry ) ) {
return cached;
}
}
return null;
}
/**
* Add new {@link Bookmark} to remote backend.
*
* @param newBookmark
* A new {@link Bookmark}.
* @param btn
* {@link ActionButton} the button to fire the adding.
* @param viewForSnack
* {@link View} anchor for showing {@link Snackbar} messages.
*/
public void addNewRemoteBookmark( Bookmark newBookmark, ActionButton btn, View viewForSnack ) {
//Same bookmark should not be added again.
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( newBookmark ) ) {
return;
}
}
mCachedBookmarks.add( newBookmark );
btn.setImageResource( R.drawable.ic_bookmarked );
btn.setEnabled( false );
addNewBookmarkInternal( newBookmark, btn, viewForSnack );
}
/**
* Add new {@link Bookmark} to backend.
*
* @param newBookmark
* A new {@link Bookmark}.
* @param btn
* {@link ActionButton} the button to fire the adding.
* @param viewForSnack
* {@link View} anchor for showing {@link Snackbar} messages.
*/
private void addNewBookmarkInternal( final Bookmark newBookmark, final ActionButton btn, View viewForSnack ) {
final WeakReference<View> anchor = new WeakReference<>( viewForSnack );
final WeakReference<ActionButton> actionBtn = new WeakReference<>( btn );
newBookmark.save( App.Instance, new SaveListener() {
@Override
public void onSuccess() {
View anchorV = anchor.get();
View btn = actionBtn.get();
if( anchorV != null ) {
Snackbar.make( anchorV, R.string.lbl_sync_success, Snackbar.LENGTH_SHORT ).show();
}
if( btn != null ) {
btn.setEnabled( true );
}
}
@Override
public void onFailure( int i, String s ) {
View anchorV = anchor.get();
View btn = actionBtn.get();
if( anchorV != null ) {
Snackbar.make( anchorV, R.string.lbl_sync_fail, Snackbar.LENGTH_LONG ).setAction( R.string.btn_retry, new OnClickListener() {
@Override
public void onClick( View v ) {
addNewBookmarkInternal( newBookmark, actionBtn.get(), anchor.get() );
}
} ).show();
}
if( btn != null ) {
btn.setEnabled( true );
}
}
} );
}
/**
* Add new {@link Bookmark} to remote backend.
*
* @param newBookmark
* A new {@link Bookmark}.
*/
public void addNewRemoteBookmark( Bookmark newBookmark ) {
//Same bookmark should not be added again.
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( newBookmark ) ) {
return;
}
}
mCachedBookmarks.add( newBookmark );
addNewBookmarkInternal( newBookmark );
}
/**
* Add new {@link Bookmark} to backend.
*
* @param newBookmark
* A new {@link Bookmark}.
*/
private void addNewBookmarkInternal( final Bookmark newBookmark ) {
newBookmark.save( App.Instance );
}
/**
* Remove a {@link Bookmark} from remote backend.
*
* @param bookmark
* An old {@link Bookmark}.
* @param btn
* {@link ActionButton} the button to fire the removing.
* @param viewForSnack
* {@link View} anchor for showing {@link Snackbar} messages.
*/
public void removeRemoteBookmark( Bookmark bookmark, ActionButton btn, View viewForSnack ) {
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( bookmark ) ) {
mCachedBookmarks.remove( cached );
btn.setImageResource( R.drawable.ic_not_bookmarked );
btn.setEnabled( false );
removeBookmarkInternal( bookmark, btn, viewForSnack );
break;
}
}
}
/**
* Remove a {@link Bookmark} from backend.
*
* @param bookmark
* An old {@link Bookmark}.
* @param btn
* {@link ActionButton} the button to fire the removing.
* @param viewForSnack
* {@link View} anchor for showing {@link Snackbar} messages.
*/
private void removeBookmarkInternal( final Bookmark bookmark, ActionButton btn, View viewForSnack ) {
final WeakReference<View> anchor = new WeakReference<>( viewForSnack );
final WeakReference<ActionButton> actionBtn = new WeakReference<>( btn );
bookmark.delete( App.Instance, new DeleteListener() {
@Override
public void onSuccess() {
View anchorV = anchor.get();
View btn = actionBtn.get();
if( anchorV != null ) {
Snackbar.make( anchorV, R.string.lbl_sync_success, Snackbar.LENGTH_SHORT ).show();
}
if( btn != null ) {
btn.setEnabled( true );
}
}
@Override
public void onFailure( int i, String s ) {
View anchorV = anchor.get();
View btn = actionBtn.get();
if( anchorV != null ) {
Snackbar.make( anchorV, R.string.lbl_sync_fail, Snackbar.LENGTH_LONG ).setAction( R.string.btn_retry, new OnClickListener() {
@Override
public void onClick( View v ) {
removeBookmarkInternal( bookmark, actionBtn.get(), anchor.get() );
}
} ).show();
}
if( btn != null ) {
btn.setEnabled( true );
}
}
} );
}
/**
* Remove a {@link Bookmark} from remote backend.
*
* @param bookmark
* An old {@link Bookmark}.
*/
public void removeRemoteBookmark( Bookmark bookmark ) {
for( Bookmark cached : mCachedBookmarks ) {
if( cached.equals( bookmark ) ) {
mCachedBookmarks.remove( cached );
removeBookmarkInternal( bookmark );
break;
}
}
}
/**
* Remove a {@link Bookmark} from backend.
*
* @param bookmark
* An old {@link Bookmark}.
*/
private void removeBookmarkInternal( final Bookmark bookmark ) {
bookmark.delete( App.Instance );
}
/**
* Clean all tabs.
*/
public void clean() {
mCachedBookmarks.clear();
}
/**
* @return {@code true} if init cache-list.
*/
public synchronized boolean isInit() {
return mInit;
}
/**
* @return All cached {@link Bookmark}s.
*/
public List<Bookmark> getCachedBookmarks() {
return mCachedBookmarks;
}
}