package jp.juggler.subwaytooter; import android.os.AsyncTask; import android.support.v4.os.AsyncTaskCompat; import org.json.JSONException; import org.json.JSONObject; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicBoolean; import jp.juggler.subwaytooter.api.TootApiClient; import jp.juggler.subwaytooter.api.TootApiResult; import jp.juggler.subwaytooter.api.entity.TootAccount; import jp.juggler.subwaytooter.api.entity.TootNotification; import jp.juggler.subwaytooter.api.entity.TootReport; import jp.juggler.subwaytooter.api.entity.TootStatus; import jp.juggler.subwaytooter.table.SavedAccount; import jp.juggler.subwaytooter.util.LogCategory; import jp.juggler.subwaytooter.util.Utils; public class Column { static final LogCategory log = new LogCategory( "Column" ); static final String KEY_ACCOUNT_ROW_ID = "account_id"; static final String KEY_TYPE = "type"; static final String KEY_WHO_ID = "who_id"; final ActMain activity; final SavedAccount access_info; final int type; final long who_id; static final int TYPE_TL_HOME = 1; static final int TYPE_TL_LOCAL = 2; static final int TYPE_TL_FEDERATE = 3; static final int TYPE_TL_STATUSES = 4; static final int TYPE_TL_FAVOURITES = 5; static final int TYPE_TL_REPORTS = 6; static final int TYPE_TL_NOTIFICATIONS = 7; public Column( ActMain activity, SavedAccount access_info, int type ){ this( activity, access_info, type, access_info.id ); } public Column( ActMain activity, SavedAccount access_info, int type, long who_id, Object... params ){ this.activity = activity; this.access_info = access_info; this.type = type; this.who_id = who_id; startLoading(); } public Column( ActMain activity, JSONObject src ){ this.activity = activity; this.access_info = SavedAccount.loadAccount( log, src.optLong( KEY_ACCOUNT_ROW_ID ) ); if( access_info == null ) throw new RuntimeException( "missing account" ); this.type = src.optInt( KEY_TYPE ); this.who_id = src.optLong( KEY_WHO_ID ); startLoading(); } final AtomicBoolean is_dispose = new AtomicBoolean(); void dispose(){ is_dispose.set( true ); } public void encodeJSON( JSONObject item ) throws JSONException{ item.put( KEY_ACCOUNT_ROW_ID , access_info.db_id ); item.put( KEY_TYPE, type ); item.put( KEY_WHO_ID, who_id ); } public String getColumnName(){ switch( type ){ default: return "?"; case TYPE_TL_HOME: return activity.getString( R.string.home ); case TYPE_TL_LOCAL: return activity.getString( R.string.local_timeline ); case TYPE_TL_FEDERATE: return activity.getString( R.string.federate_timeline ); case TYPE_TL_STATUSES: return activity.getString( R.string.statuses_of , who_account != null ? access_info.getFullAcct( who_account ) : Long.toString( who_id ) ); case TYPE_TL_FAVOURITES: return activity.getString( R.string.favourites ); case TYPE_TL_REPORTS: return activity.getString( R.string.reports ); case TYPE_TL_NOTIFICATIONS: return activity.getString( R.string.notifications ); } } public interface StatusEntryCallback{ void onIterate(TootStatus status); } public void findStatus( SavedAccount target_account,long target_status_id ,StatusEntryCallback callback){ if( target_account.user.equals( access_info.user ) ){ for( int i = 0, ie = status_list.size() ; i < ie ; ++ i ){ TootStatus status = status_list.get( i ); if( target_status_id == status.id ){ callback.onIterate( status ); } TootStatus reblog = status.reblog; if( reblog!= null ){ if( target_status_id == reblog.id ){ callback.onIterate( status ); } } } } } public interface VisualCallback { void onVisualColumn(); } final LinkedList< VisualCallback > visual_callback = new LinkedList<>(); void addVisualListener( VisualCallback listener ){ if( listener == null ) return; Iterator< VisualCallback > it = visual_callback.iterator(); while( it.hasNext() ){ VisualCallback vc = it.next(); if( vc == listener ) return; } visual_callback.add( listener ); } void removeVisualListener( VisualCallback listener ){ if( listener == null ) return; Iterator< VisualCallback > it = visual_callback.iterator(); while( it.hasNext() ){ VisualCallback vc = it.next(); if( vc == listener ) it.remove(); } } public void fireVisualCallback(){ Iterator< VisualCallback > it = visual_callback.iterator(); while( it.hasNext() ){ it.next().onVisualColumn(); } } AsyncTask< Void, Void, TootApiResult > last_task; void cancelLastTask(){ if( last_task != null ) last_task.cancel( true ); } boolean is_loading = false; String task_progress; String error = null; final TootStatus.List status_list = new TootStatus.List(); final TootReport.List report_list = new TootReport.List(); final TootNotification.List notification_list = new TootNotification.List(); volatile TootAccount who_account; public void reload(){ status_list.clear(); startLoading(); } void startLoading(){ error = null; is_loading = true; fireVisualCallback(); cancelLastTask(); AsyncTask< Void, Void, TootApiResult > task = this.last_task = new AsyncTask< Void, Void, TootApiResult >() { TootStatus.List tmp_list_status; TootReport.List tmp_list_report; TootNotification.List tmp_list_notification; TootApiResult parseStatuses( TootApiResult result ){ if( result != null ){ tmp_list_status = TootStatus.parseList( log, result.array ); } return result; } TootApiResult parseAccount( TootApiResult result ){ if( result != null ){ who_account = TootAccount.parse( log, result.object ); } return result; } TootApiResult parseReports( TootApiResult result ){ if( result != null ){ tmp_list_report = TootReport.parseList( log, result.array ); } return result; } TootApiResult parseNotifications( TootApiResult result ){ if( result != null ){ tmp_list_notification = TootNotification.parseList( log, result.array ); } return result; } @Override protected TootApiResult doInBackground( Void... params ){ TootApiClient client = new TootApiClient( activity, new TootApiClient.Callback() { @Override public boolean isApiCancelled(){ return isCancelled() || is_dispose.get(); } @Override public void publishApiProgress( final String s ){ Utils.runOnMainThread( new Runnable() { @Override public void run(){ if( isCancelled() ) return; task_progress = s; fireVisualCallback(); } } ); } } ); client.setAccount( access_info ); switch( type ){ default: case TYPE_TL_HOME: return parseStatuses( client.request( "/api/v1/timelines/home" ) ); case TYPE_TL_LOCAL: return parseStatuses( client.request( "/api/v1/timelines/public?local=1" ) ); case TYPE_TL_FEDERATE: return parseStatuses( client.request( "/api/v1/timelines/public" ) ); case TYPE_TL_STATUSES: if( who_account == null ){ parseAccount( client.request( "/api/v1/accounts/" + who_id ) ); client.callback.publishApiProgress( "" ); } return parseStatuses( client.request( "/api/v1/accounts/" + who_id + "/statuses" ) ); case TYPE_TL_FAVOURITES: return parseStatuses( client.request( "/api/v1/favourites" ) ); case TYPE_TL_REPORTS: return parseReports( client.request( "/api/v1/reports" ) ); case TYPE_TL_NOTIFICATIONS: return parseNotifications( client.request( "/api/v1/notifications" ) ); } } @Override protected void onCancelled( TootApiResult result ){ onPostExecute( null ); } @Override protected void onPostExecute( TootApiResult result ){ is_loading = false; if( result == null ){ Column.this.error = activity.getString( R.string.cancelled ); }else if( result.error != null ){ Column.this.error = result.error; }else{ switch( type ){ default: case TYPE_TL_HOME: case TYPE_TL_LOCAL: case TYPE_TL_FEDERATE: case TYPE_TL_STATUSES: case TYPE_TL_FAVOURITES: if( tmp_list_status != null ){ for( int i = tmp_list_status.size() - 1 ; i >= 0 ; -- i ){ status_list.add( 0, tmp_list_status.get( i ) ); } } break; case TYPE_TL_REPORTS: if( tmp_list_report != null ){ for( int i = tmp_list_report.size() - 1 ; i >= 0 ; -- i ){ report_list.add( 0, tmp_list_report.get( i ) ); } } break; case TYPE_TL_NOTIFICATIONS: if( tmp_list_notification != null ){ for( int i = tmp_list_notification.size() - 1 ; i >= 0 ; -- i ){ notification_list.add( 0, tmp_list_notification.get( i ) ); } } break; } } fireVisualCallback(); } }; AsyncTaskCompat.executeParallel( task ); } }