SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/Column.java

870 lines
26 KiB
Java
Raw Normal View History

2017-04-20 18:23:59 +02:00
package jp.juggler.subwaytooter;
import android.content.Intent;
import android.net.Uri;
2017-04-20 18:23:59 +02:00
import android.os.AsyncTask;
import android.support.annotation.NonNull;
2017-04-20 18:23:59 +02:00
import android.support.v4.os.AsyncTaskCompat;
2017-04-23 07:42:09 +02:00
import android.text.TextUtils;
2017-04-20 18:23:59 +02:00
import org.json.JSONException;
import org.json.JSONObject;
2017-04-23 07:42:09 +02:00
import java.util.ArrayList;
import java.util.HashSet;
2017-04-20 18:23:59 +02:00
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
2017-04-20 18:23:59 +02:00
import java.util.concurrent.atomic.AtomicBoolean;
2017-04-23 07:42:09 +02:00
import java.util.regex.Matcher;
import java.util.regex.Pattern;
2017-04-20 18:23:59 +02:00
import jp.juggler.subwaytooter.api.TootApiClient;
import jp.juggler.subwaytooter.api.TootApiResult;
import jp.juggler.subwaytooter.api.entity.TootAccount;
2017-04-23 07:42:09 +02:00
import jp.juggler.subwaytooter.api.entity.TootContext;
2017-04-20 18:23:59 +02:00
import jp.juggler.subwaytooter.api.entity.TootNotification;
import jp.juggler.subwaytooter.api.entity.TootReport;
import jp.juggler.subwaytooter.api.entity.TootResults;
2017-04-20 18:23:59 +02:00
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;
class Column {
private static final LogCategory log = new LogCategory( "Column" );
private static Object getParamAt( Object[] params, int idx ){
if( params == null || idx >= params.length ){
throw new IndexOutOfBoundsException( "getParamAt idx=" + idx );
}
return params[ idx ];
}
private static final String PATH_HOME = "/api/v1/timelines/home?limit=80";
private static final String PATH_LOCAL = "/api/v1/timelines/public?limit=80&local=1";
private static final String PATH_FEDERATE = "/api/v1/timelines/public?limit=80";
private static final String PATH_FAVOURITES = "/api/v1/favourites?limit=80";
private static final String PATH_REPORTS = "/api/v1/reports?limit=80";
private static final String PATH_NOTIFICATIONS = "/api/v1/notifications?limit=80";
private static final String PATH_ACCOUNT = "/api/v1/accounts/%d?limit=80"; // 1:account_id
private static final String PATH_ACCOUNT_STATUSES = "/api/v1/accounts/%d/statuses?limit=80"; // 1:account_id
private static final String PATH_ACCOUNT_FOLLOWING = "/api/v1/accounts/%d/following?limit=80"; // 1:account_id
private static final String PATH_ACCOUNT_FOLLOWERS = "/api/v1/accounts/%d/followers?limit=80"; // 1:account_id
private static final String PATH_HASHTAG = "/api/v1/timelines/tag/%s?limit=80"; // 1: hashtag(url encoded)
private static final String PATH_STATUSES = "/api/v1/statuses/%d"; // 1:status_id
private static final String PATH_STATUSES_CONTEXT = "/api/v1/statuses/%d/context"; // 1:status_id
private static final String PATH_SEARCH = "/api/v1/search?limit=80&q=%s"; // 1: query(urlencoded) , also, append "&resolve=1" if resolve non-local accounts
private static final String KEY_ACCOUNT_ROW_ID = "account_id";
private static final String KEY_TYPE = "type";
private static final String KEY_PROFILE_ID = "profile_id";
private static final String KEY_PROFILE_TAB = "tab";
private static final String KEY_STATUS_ID = "status_id";
private static final String KEY_HASHTAG = "hashtag";
private static final String KEY_SEARCH_QUERY = "search_query";
private static final String KEY_SEARCH_RESOLVE = "search_resolve";
2017-04-23 07:42:09 +02:00
static final String KEY_COLUMN_ACCESS = "column_access";
static final String KEY_COLUMN_NAME = "column_name";
static final String KEY_OLD_INDEX = "old_index";
private final @NonNull ActMain activity;
final @NonNull SavedAccount access_info;
2017-04-20 18:23:59 +02:00
final int type;
static final int TYPE_HOME = 1;
static final int TYPE_LOCAL = 2;
static final int TYPE_FEDERATE = 3;
static final int TYPE_PROFILE = 4;
static final int TYPE_FAVOURITES = 5;
private static final int TYPE_REPORTS = 6;
static final int TYPE_NOTIFICATIONS = 7;
static final int TYPE_CONVERSATION = 8;
static final int TYPE_HASHTAG = 9;
static final int TYPE_SEARCH = 10;
private long profile_id;
volatile TootAccount who_account;
int profile_tab = TAB_STATUS;
static final int TAB_STATUS = 0;
static final int TAB_FOLLOWING = 1;
static final int TAB_FOLLOWERS = 2;
private long status_id;
private String hashtag;
String search_query;
boolean search_resolve;
2017-04-20 18:23:59 +02:00
int scroll_pos;
int scroll_y;
Column( @NonNull ActMain activity, @NonNull SavedAccount access_info, int type, Object... params ){
2017-04-20 18:23:59 +02:00
this.activity = activity;
this.access_info = access_info;
this.type = type;
switch( type ){
case TYPE_CONVERSATION:
this.status_id = (Long) getParamAt( params, 0 );
break;
case TYPE_PROFILE:
this.profile_id = (Long) getParamAt( params, 0 );
break;
case TYPE_HASHTAG:
this.hashtag = (String) getParamAt( params, 0 );
break;
case TYPE_SEARCH:
this.search_query = (String) getParamAt( params, 0 );
this.search_resolve = (Boolean) getParamAt( params, 1 );
2017-04-23 07:42:09 +02:00
}
2017-04-20 18:23:59 +02:00
startLoading();
}
void encodeJSON( JSONObject item, int old_index ) throws JSONException{
item.put( KEY_ACCOUNT_ROW_ID, access_info.db_id );
item.put( KEY_TYPE, type );
switch( type ){
case TYPE_CONVERSATION:
item.put( KEY_STATUS_ID, status_id );
break;
case TYPE_PROFILE:
item.put( KEY_PROFILE_ID, profile_id );
item.put( KEY_PROFILE_TAB, profile_tab );
break;
case TYPE_HASHTAG:
item.put( KEY_HASHTAG, hashtag );
break;
case TYPE_SEARCH:
item.put( KEY_SEARCH_QUERY, search_query );
item.put( KEY_SEARCH_RESOLVE, search_resolve );
break;
}
// 以下は保存には必要ないが、カラムリスト画面で使う
item.put( KEY_COLUMN_ACCESS, access_info.acct );
item.put( KEY_COLUMN_NAME, getColumnName( true ) );
item.put( KEY_OLD_INDEX, old_index );
}
Column( @NonNull ActMain activity, JSONObject src ){
this.activity = activity;
SavedAccount ac = SavedAccount.loadAccount( log, src.optLong( KEY_ACCOUNT_ROW_ID ) );
if( ac == null ) throw new RuntimeException( "missing account" );
this.access_info = ac;
this.type = src.optInt( KEY_TYPE );
switch( type ){
case TYPE_CONVERSATION:
this.status_id = src.optLong( KEY_STATUS_ID );
break;
case TYPE_PROFILE:
this.profile_id = src.optLong( KEY_PROFILE_ID );
this.profile_tab = src.optInt( KEY_PROFILE_TAB );
break;
case TYPE_HASHTAG:
this.hashtag = src.optString( KEY_HASHTAG );
break;
case TYPE_SEARCH:
this.search_query = src.optString( KEY_SEARCH_QUERY );
this.search_resolve = src.optBoolean( KEY_SEARCH_RESOLVE, false );
}
startLoading();
}
2017-04-20 18:23:59 +02:00
final AtomicBoolean is_dispose = new AtomicBoolean();
void dispose(){
is_dispose.set( true );
}
String getColumnName( boolean bLong ){
2017-04-20 18:23:59 +02:00
switch( type ){
2017-04-20 18:23:59 +02:00
default:
return "?";
case TYPE_HOME:
return activity.getString( R.string.home );
case TYPE_LOCAL:
return activity.getString( R.string.local_timeline );
case TYPE_FEDERATE:
return activity.getString( R.string.federate_timeline );
2017-04-20 18:23:59 +02:00
case TYPE_PROFILE:
return activity.getString( R.string.statuses_of
, who_account != null ? access_info.getFullAcct( who_account ) : Long.toString( profile_id )
2017-04-20 18:23:59 +02:00
);
case TYPE_FAVOURITES:
return activity.getString( R.string.favourites );
2017-04-20 18:23:59 +02:00
case TYPE_REPORTS:
return activity.getString( R.string.reports );
2017-04-20 18:23:59 +02:00
case TYPE_NOTIFICATIONS:
return activity.getString( R.string.notifications );
case TYPE_CONVERSATION:
return activity.getString( R.string.conversation_around, status_id );
case TYPE_HASHTAG:
return activity.getString( R.string.hashtag_of, hashtag );
case TYPE_SEARCH:
if( bLong ){
return activity.getString( R.string.search_of, search_query );
}else{
return activity.getString( R.string.search );
}
}
}
boolean isSameSpec( SavedAccount ai, int type, Object[] params ){
if( type != this.type || ! Utils.equalsNullable( ai.acct, access_info.acct ) ) return false;
switch( type ){
default:
return true;
case TYPE_PROFILE:
try{
long who_id = (Long) getParamAt( params, 0 );
return who_id == this.profile_id;
}catch( Throwable ex ){
return false;
}
case TYPE_CONVERSATION:
try{
long status_id = (Long) getParamAt( params, 0 );
return status_id == this.status_id;
}catch( Throwable ex ){
return false;
}
case TYPE_HASHTAG:
try{
long status_id = (Long) getParamAt( params, 0 );
return status_id == this.status_id;
}catch( Throwable ex ){
return false;
}
case TYPE_SEARCH:
try{
String q = (String) getParamAt( params, 0 );
boolean r = (Boolean) getParamAt( params, 1 );
return Utils.equalsNullable( q, this.search_query )
&& r == this.search_resolve;
}catch( Throwable ex ){
return false;
}
}
}
interface StatusEntryCallback {
2017-04-23 07:42:09 +02:00
void onIterate( TootStatus status );
}
2017-04-23 07:42:09 +02:00
// ブーストやお気に入りの更新に使う。ステータスを列挙する。
void findStatus( SavedAccount target_account, long target_status_id, StatusEntryCallback callback ){
if( target_account.acct.equals( access_info.acct ) ){
for( int i = 0, ie = list_data.size() ; i < ie ; ++ i ){
Object data = list_data.get( i );
//
if( data instanceof TootNotification ){
data = ( (TootNotification) data ).status;
}
//
if( data instanceof TootStatus ){
//
TootStatus status = (TootStatus) data;
if( target_status_id == status.id ){
callback.onIterate( status );
}
//
TootStatus reblog = status.reblog;
if( reblog != null ){
if( target_status_id == reblog.id ){
callback.onIterate( reblog );
}
}
}
}
}
}
// ミュート、ブロックが成功した時に呼ばれる
void removeStatusByAccount( SavedAccount target_account, long who_id ){
if( ! target_account.acct.equals( access_info.acct ) ) return;
{
// remove from status_list
ArrayList< Object > tmp_list = new ArrayList<>( list_data.size() );
for( Object o : list_data ){
if( o instanceof TootStatus ){
TootStatus item = (TootStatus) o;
if( item.account.id == who_id
|| ( item.reblog != null && item.reblog.account.id == who_id )
){
continue;
}
}
if( o instanceof TootNotification ){
TootNotification item = (TootNotification) o;
if( item.account.id == who_id ) continue;
if( item.status != null ){
if( item.status.account.id == who_id ) continue;
if( item.status.reblog != null && item.status.reblog.account.id == who_id )
continue;
}
}
tmp_list.add( o );
}
list_data.clear();
list_data.addAll( tmp_list );
}
}
interface VisualCallback {
2017-04-20 18:23:59 +02:00
void onVisualColumn();
}
private final LinkedList< VisualCallback > visual_callback = new LinkedList<>();
2017-04-20 18:23:59 +02:00
void addVisualListener( VisualCallback listener ){
if( listener == null ) return;
for( VisualCallback vc : visual_callback ){
2017-04-20 18:23:59 +02:00
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();
}
}
private final Runnable proc_fireVisualCallback = new Runnable() {
@Override public void run(){
for( VisualCallback aVisual_callback : visual_callback ){
aVisual_callback.onVisualColumn();
}
2017-04-20 18:23:59 +02:00
}
};
void fireVisualCallback(){
Utils.runOnMainThread( proc_fireVisualCallback );
2017-04-20 18:23:59 +02:00
}
private AsyncTask< Void, Void, TootApiResult > last_task;
2017-04-20 18:23:59 +02:00
private void cancelLastTask(){
2017-04-23 07:42:09 +02:00
if( last_task != null ){
last_task.cancel( true );
last_task = null;
//
bInitialLoading = false;
bRefreshLoading = false;
mInitialLoadingError = activity.getString( R.string.cancelled );
//
}
2017-04-20 18:23:59 +02:00
}
2017-04-23 07:42:09 +02:00
boolean bInitialLoading;
boolean bRefreshLoading;
String mInitialLoadingError;
String mRefreshLoadingError;
2017-04-20 18:23:59 +02:00
String task_progress;
final ArrayList< Object > list_data = new ArrayList<>();
2017-04-20 18:23:59 +02:00
void reload(){
list_data.clear();
2017-04-20 18:23:59 +02:00
startLoading();
}
private void startLoading(){
2017-04-20 18:23:59 +02:00
cancelLastTask();
mRefreshLoadingError = null;
bRefreshLoading = false;
2017-04-23 07:42:09 +02:00
mInitialLoadingError = null;
bInitialLoading = true;
max_id = null;
since_id = null;
2017-04-23 07:42:09 +02:00
fireVisualCallback();
2017-04-20 18:23:59 +02:00
AsyncTask< Void, Void, TootApiResult > task = this.last_task = new AsyncTask< Void, Void, TootApiResult >() {
TootApiResult parseAccount1( TootApiResult result ){
if( result != null ){
who_account = TootAccount.parse( log, access_info, result.object );
}
return result;
}
ArrayList< Object > list_tmp;
2017-04-20 18:23:59 +02:00
TootApiResult parseStatuses( TootApiResult result ){
if( result != null ){
2017-04-23 07:42:09 +02:00
saveRange( result, true, true );
list_tmp = new ArrayList<>();
list_tmp.addAll( TootStatus.parseList( log, access_info, result.array ) );
2017-04-20 18:23:59 +02:00
}
return result;
}
TootApiResult parseAccountList( TootApiResult result ){
2017-04-20 18:23:59 +02:00
if( result != null ){
2017-04-23 07:42:09 +02:00
saveRange( result, true, true );
list_tmp = new ArrayList<>();
list_tmp.addAll( TootAccount.parseList( log, access_info, result.array ) );
2017-04-20 18:23:59 +02:00
}
return result;
}
TootApiResult parseReports( TootApiResult result ){
if( result != null ){
2017-04-23 07:42:09 +02:00
saveRange( result, true, true );
list_tmp = new ArrayList<>();
list_tmp.addAll( TootReport.parseList( log, result.array ) );
2017-04-20 18:23:59 +02:00
}
return result;
}
TootApiResult parseNotifications( TootApiResult result ){
if( result != null ){
2017-04-23 07:42:09 +02:00
saveRange( result, true, true );
TootNotification.List src= TootNotification.parseList( log, access_info, result.array );
if( src != null){
list_tmp = new ArrayList<>();
list_tmp.addAll( src );
//
AlarmService.injectData( activity,access_info.db_id, src );
}
2017-04-20 18:23:59 +02:00
}
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();
2017-04-20 18:23:59 +02:00
}
@Override
public void publishApiProgress( final String s ){
2017-04-20 18:23:59 +02:00
Utils.runOnMainThread( new Runnable() {
@Override
public void run(){
if( isCancelled() ) return;
task_progress = s;
fireVisualCallback();
}
} );
}
} );
client.setAccount( access_info );
2017-04-20 18:23:59 +02:00
TootApiResult result;
2017-04-20 18:23:59 +02:00
switch( type ){
2017-04-20 18:23:59 +02:00
default:
case TYPE_HOME:
return parseStatuses( client.request( PATH_HOME ) );
2017-04-20 18:23:59 +02:00
case TYPE_LOCAL:
return parseStatuses( client.request( PATH_LOCAL ) );
2017-04-20 18:23:59 +02:00
case TYPE_FEDERATE:
return parseStatuses( client.request( PATH_FEDERATE ) );
2017-04-20 18:23:59 +02:00
case TYPE_PROFILE:
2017-04-20 18:23:59 +02:00
if( who_account == null ){
parseAccount1( client.request(
String.format( Locale.JAPAN, PATH_ACCOUNT, profile_id ) ) );
client.callback.publishApiProgress( "" );
2017-04-20 18:23:59 +02:00
}
switch( profile_tab ){
default:
case TAB_STATUS:
return parseStatuses( client.request(
String.format( Locale.JAPAN, PATH_ACCOUNT_STATUSES, profile_id ) ) );
case TAB_FOLLOWING:
return parseAccountList( client.request(
String.format( Locale.JAPAN, PATH_ACCOUNT_FOLLOWING, profile_id ) ) );
case TAB_FOLLOWERS:
return parseAccountList( client.request(
String.format( Locale.JAPAN, PATH_ACCOUNT_FOLLOWERS, profile_id ) ) );
}
2017-04-20 18:23:59 +02:00
case TYPE_FAVOURITES:
return parseStatuses( client.request( PATH_FAVOURITES ) );
case TYPE_HASHTAG:
return parseStatuses( client.request(
String.format( Locale.JAPAN, PATH_HASHTAG, Uri.encode( hashtag ) ) ) );
2017-04-20 18:23:59 +02:00
case TYPE_REPORTS:
return parseReports( client.request( PATH_REPORTS ) );
2017-04-20 18:23:59 +02:00
case TYPE_NOTIFICATIONS:
return parseNotifications( client.request( PATH_NOTIFICATIONS ) );
2017-04-23 07:42:09 +02:00
case TYPE_CONVERSATION:
// 指定された発言そのもの
result = client.request(
String.format( Locale.JAPAN, PATH_STATUSES, status_id ) );
if( result == null || result.object == null ) return result;
TootStatus target_status = TootStatus.parse( log, access_info, result.object );
2017-04-23 07:42:09 +02:00
target_status.conversation_main = true;
// 前後の会話
result = client.request(
String.format( Locale.JAPAN, PATH_STATUSES_CONTEXT, status_id ) );
if( result == null || result.object == null ) return result;
// 一つのリストにまとめる
TootContext context = TootContext.parse( log, access_info, result.object );
list_tmp = new ArrayList<>( 1 + context.ancestors.size() + context.descendants.size() );
if( context.ancestors != null ) list_tmp.addAll( context.ancestors );
list_tmp.add( target_status );
if( context.descendants != null ) list_tmp.addAll( context.descendants );
//
return result;
case TYPE_SEARCH:
String path = String.format( Locale.JAPAN, PATH_SEARCH, Uri.encode( search_query ) );
if( search_resolve ) path = path + "&resolve=1";
result = client.request( path );
if( result == null || result.object == null ) return result;
TootResults tmp = TootResults.parse( log, access_info, result.object );
if( tmp != null ){
list_tmp = new ArrayList<>();
list_tmp.addAll( tmp.hashtags );
list_tmp.addAll( tmp.accounts );
list_tmp.addAll( tmp.statuses );
}
2017-04-23 07:42:09 +02:00
return result;
2017-04-20 18:23:59 +02:00
}
}
@Override
protected void onCancelled( TootApiResult result ){
onPostExecute( null );
}
@Override
protected void onPostExecute( TootApiResult result ){
2017-04-23 07:42:09 +02:00
if( isCancelled() || result == null ){
return;
}
bInitialLoading = false;
last_task = null;
if( result.error != null ){
Column.this.mInitialLoadingError = result.error;
2017-04-20 18:23:59 +02:00
}else{
if( list_tmp != null ){
list_data.clear();
list_data.addAll( list_tmp );
2017-04-23 07:42:09 +02:00
}
}
fireVisualCallback();
}
};
AsyncTaskCompat.executeParallel( task );
}
private static final Pattern reMaxId = Pattern.compile( "&max_id=(\\d+)" ); // より古いデータの取得に使う
private static final Pattern reSinceId = Pattern.compile( "&since_id=(\\d+)" ); // より新しいデータの取得に使う
2017-04-23 07:42:09 +02:00
private String max_id;
private String since_id;
2017-04-23 07:42:09 +02:00
private void saveRange( TootApiResult result, boolean bBottom, boolean bTop ){
// Link: <https://mastodon.juggler.jp/api/v1/timelines/home?limit=80&max_id=405228>; rel="next",
// <https://mastodon.juggler.jp/api/v1/timelines/home?limit=80&since_id=436946>; rel="prev"
if( result.response != null ){
String sv = result.response.header( "Link" );
if( ! TextUtils.isEmpty( sv ) ){
if( bBottom ){
Matcher m = reMaxId.matcher( sv );
if( m.find() ){
max_id = m.group( 1 );
//log.d( "col=%s,max_id=%s", this.hashCode(), max_id );
2017-04-23 07:42:09 +02:00
}
}
if( bTop ){
Matcher m = reSinceId.matcher( sv );
if( m.find() ){
since_id = m.group( 1 );
//log.d( "col=%s,since_id=%s", this.hashCode(), since_id );
2017-04-23 07:42:09 +02:00
}
}
}
}
}
private String addRange( boolean bBottom, String path ){
2017-04-23 07:42:09 +02:00
char delm = ( - 1 != path.indexOf( '?' ) ? '&' : '?' );
if( bBottom ){
if( max_id != null ) return path + delm + "max_id=" + max_id;
}else{
if( since_id != null ) return path + delm + "since_id=" + since_id;
}
return path;
}
boolean startRefresh( final boolean bBottom ){
2017-04-23 07:42:09 +02:00
if( last_task != null ){
log.d( "busy" );
return false;
}else if( bBottom && max_id == null ){
log.d( "startRefresh failed. missing max_id" );
return false;
}else if( ! bBottom && since_id == null ){
2017-04-23 07:42:09 +02:00
log.d( "startRefresh failed. missing since_id" );
return false;
}
bRefreshLoading = true;
mRefreshLoadingError = null;
AsyncTask< Void, Void, TootApiResult > task = this.last_task = new AsyncTask< Void, Void, TootApiResult >() {
TootApiResult parseAccount1( TootApiResult result ){
if( result != null ){
who_account = TootAccount.parse( log, access_info, result.object );
}
return result;
}
2017-04-23 07:42:09 +02:00
TootApiResult parseAccountList( TootApiResult result ){
2017-04-23 07:42:09 +02:00
if( result != null ){
saveRange( result, bBottom, ! bBottom );
list_tmp = new ArrayList<>();
list_tmp.addAll( TootAccount.parseList( log, access_info, result.array ) );
2017-04-23 07:42:09 +02:00
}
return result;
}
ArrayList< Object > list_tmp;
TootApiResult parseStatuses( TootApiResult result ){
2017-04-23 07:42:09 +02:00
if( result != null ){
saveRange( result, bBottom, ! bBottom );
list_tmp = new ArrayList<>();
list_tmp.addAll( TootStatus.parseList( log, access_info, result.array ) );
2017-04-23 07:42:09 +02:00
}
return result;
}
TootApiResult parseReports( TootApiResult result ){
if( result != null ){
saveRange( result, bBottom, ! bBottom );
list_tmp = new ArrayList<>();
list_tmp.addAll( TootReport.parseList( log, result.array ) );
2017-04-23 07:42:09 +02:00
}
return result;
}
TootApiResult parseNotifications( TootApiResult result ){
if( result != null ){
saveRange( result, bBottom, ! bBottom );
TootNotification.List src = TootNotification.parseList( log, access_info, result.array );
if( src != null ){
list_tmp = new ArrayList<>();
list_tmp.addAll( src );
//
AlarmService.injectData( activity,access_info.db_id, src );
}
2017-04-23 07:42:09 +02:00
}
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();
2017-04-20 18:23:59 +02:00
}
2017-04-23 07:42:09 +02:00
} );
}
} );
client.setAccount( access_info );
switch( type ){
default:
case TYPE_HOME:
return parseStatuses( client.request( addRange( bBottom, PATH_HOME ) ) );
2017-04-23 07:42:09 +02:00
case TYPE_LOCAL:
return parseStatuses( client.request( addRange( bBottom, PATH_LOCAL ) ) );
2017-04-23 07:42:09 +02:00
case TYPE_FEDERATE:
return parseStatuses( client.request( addRange( bBottom, PATH_FEDERATE ) ) );
case TYPE_FAVOURITES:
return parseStatuses( client.request( addRange( bBottom, PATH_FAVOURITES ) ) );
case TYPE_REPORTS:
return parseReports( client.request( addRange( bBottom, PATH_REPORTS ) ) );
case TYPE_NOTIFICATIONS:
return parseNotifications( client.request( addRange( bBottom, PATH_NOTIFICATIONS ) ) );
2017-04-23 07:42:09 +02:00
case TYPE_PROFILE:
2017-04-23 07:42:09 +02:00
if( who_account == null ){
parseAccount1( client.request(
String.format( Locale.JAPAN, PATH_ACCOUNT, profile_id ) ) );
2017-04-23 07:42:09 +02:00
client.callback.publishApiProgress( "" );
}
switch( profile_tab ){
default:
case TAB_STATUS:
return parseStatuses( client.request(addRange( bBottom,
String.format( Locale.JAPAN, PATH_ACCOUNT_STATUSES, profile_id ) ) ));
case TAB_FOLLOWING:
return parseAccountList( client.request(addRange( bBottom,
String.format( Locale.JAPAN, PATH_ACCOUNT_FOLLOWING, profile_id ) ) ));
case TAB_FOLLOWERS:
return parseAccountList( client.request(addRange( bBottom,
String.format( Locale.JAPAN, PATH_ACCOUNT_FOLLOWERS, profile_id ) ) ));
}
2017-04-23 07:42:09 +02:00
case TYPE_HASHTAG:
return parseStatuses( client.request( addRange( bBottom,
String.format( Locale.JAPAN, PATH_HASHTAG, Uri.encode( hashtag ) ) ) ) );
2017-04-23 07:42:09 +02:00
}
}
@Override
protected void onCancelled( TootApiResult result ){
onPostExecute( null );
}
@Override
protected void onPostExecute( TootApiResult result ){
if( isCancelled() || result == null ){
return;
}
last_task = null;
bRefreshLoading = false;
if( result.error != null ){
Column.this.mRefreshLoadingError = result.error;
}else{
if( list_tmp != null ){
// 古いリストにある要素のIDの集合集合
HashSet< Long > set_status_id = new HashSet<>();
HashSet< Long > set_notification_id = new HashSet<>();
HashSet< Long > set_report_id = new HashSet<>();
HashSet< Long > set_account_id = new HashSet<>();
for( Object o : list_data ){
if( o instanceof TootStatus ){
set_status_id.add( ( (TootStatus) o ).id );
}else if( o instanceof TootNotification ){
set_notification_id.add( ( (TootNotification) o ).id );
}else if( o instanceof TootReport ){
set_report_id.add( ( (TootReport) o ).id );
}else if( o instanceof TootAccount ){
set_account_id.add( ( (TootAccount) o ).id );
}
}
ArrayList< Object > list_new = new ArrayList<>();
for( Object o : list_tmp ){
if( o instanceof TootStatus ){
if( set_status_id.contains( ( (TootStatus) o ).id ) ) continue;
}else if( o instanceof TootNotification ){
if( set_notification_id.contains( ( (TootNotification) o ).id ) )
continue;
}else if( o instanceof TootReport ){
if( set_report_id.contains( ( (TootReport) o ).id ) ) continue;
}else if( o instanceof TootAccount ){
if( set_account_id.contains( ( (TootAccount) o ).id ) ) continue;
}
list_new.add( o );
}
if( ! bBottom ){
// 新しいデータの後に今のデータが並ぶ
list_new.addAll( list_data );
list_data.clear();
list_data.addAll( list_new );
}else{
// 今のデータの後にさらに古いデータが続く
list_data.addAll( list_new );
}
2017-04-20 18:23:59 +02:00
}
}
2017-04-20 18:23:59 +02:00
fireVisualCallback();
}
};
AsyncTaskCompat.executeParallel( task );
2017-04-23 07:42:09 +02:00
return true;
2017-04-20 18:23:59 +02:00
}
2017-04-23 07:42:09 +02:00
2017-04-20 18:23:59 +02:00
}