2017-04-20 18:23:59 +02:00
|
|
|
package jp.juggler.subwaytooter;
|
|
|
|
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
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
|
|
|
|
2017-04-21 14:45:40 +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.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;
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootId;
|
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.TootStatus;
|
|
|
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
|
|
|
import jp.juggler.subwaytooter.util.LogCategory;
|
|
|
|
import jp.juggler.subwaytooter.util.Utils;
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
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 KEY_ACCOUNT_ROW_ID = "account_id";
|
|
|
|
private static final String KEY_TYPE = "type";
|
|
|
|
private static final String KEY_WHO_ID = "who_id";
|
|
|
|
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";
|
2017-04-21 14:45:40 +02:00
|
|
|
|
2017-04-23 20:05:29 +02:00
|
|
|
private final ActMain activity;
|
2017-04-24 06:01:59 +02:00
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
final SavedAccount access_info;
|
2017-04-24 06:01:59 +02:00
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
final int type;
|
2017-04-24 06:01:59 +02:00
|
|
|
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;
|
|
|
|
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 who_id;
|
|
|
|
|
|
|
|
private long status_id;
|
|
|
|
|
|
|
|
private String hashtag;
|
|
|
|
|
|
|
|
String search_query;
|
|
|
|
boolean search_resolve;
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-23 18:19:39 +02:00
|
|
|
int profile_tab = 0;
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-23 20:05:29 +02:00
|
|
|
int scroll_pos;
|
|
|
|
int scroll_y;
|
2017-04-23 15:08:22 +02:00
|
|
|
|
2017-04-23 20:05:29 +02:00
|
|
|
|
|
|
|
Column( ActMain activity, 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;
|
2017-04-23 20:05:29 +02:00
|
|
|
switch(type){
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_CONVERSATION:
|
2017-04-23 20:05:29 +02:00
|
|
|
this.status_id = (Long)getParamAt( params,0 );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-23 20:05:29 +02:00
|
|
|
this.who_id = (Long)getParamAt( params,0 );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
this.hashtag = (String)getParamAt( params,0 );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
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-23 20:05:29 +02:00
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
startLoading();
|
|
|
|
}
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
void encodeJSON( JSONObject item, int old_index ) throws JSONException{
|
2017-04-23 20:05:29 +02:00
|
|
|
item.put( KEY_ACCOUNT_ROW_ID, access_info.db_id );
|
|
|
|
item.put( KEY_TYPE, type );
|
|
|
|
|
|
|
|
switch(type){
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_CONVERSATION:
|
2017-04-23 20:05:29 +02:00
|
|
|
item.put( KEY_STATUS_ID,status_id);
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-23 20:05:29 +02:00
|
|
|
item.put( KEY_WHO_ID, who_id );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
item.put( KEY_HASHTAG,hashtag );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_SEARCH:
|
|
|
|
item.put( KEY_SEARCH_QUERY,search_query);
|
|
|
|
item.put( KEY_SEARCH_RESOLVE,search_resolve);
|
2017-04-23 20:05:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 以下は保存には必要ないが、カラムリスト画面で使う
|
|
|
|
item.put( KEY_COLUMN_ACCESS, access_info.user );
|
2017-04-24 06:01:59 +02:00
|
|
|
item.put( KEY_COLUMN_NAME, getColumnName(true) );
|
2017-04-23 20:05:29 +02:00
|
|
|
item.put( KEY_OLD_INDEX, old_index );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Column( ActMain activity, JSONObject src ){
|
2017-04-21 14:45:40 +02:00
|
|
|
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 );
|
2017-04-23 20:05:29 +02:00
|
|
|
switch(type){
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_CONVERSATION:
|
2017-04-23 20:05:29 +02:00
|
|
|
this.status_id = src.optLong( KEY_STATUS_ID );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-23 20:05:29 +02:00
|
|
|
this.who_id = src.optLong( KEY_WHO_ID );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
this.hashtag = src.optString( KEY_HASHTAG );
|
|
|
|
break;
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_SEARCH:
|
|
|
|
this.search_query = src.optString( KEY_SEARCH_QUERY );
|
|
|
|
this.search_resolve = src.optBoolean( KEY_SEARCH_RESOLVE,false );
|
2017-04-23 20:05:29 +02:00
|
|
|
}
|
2017-04-21 14:45:40 +02:00
|
|
|
startLoading();
|
|
|
|
}
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
final AtomicBoolean is_dispose = new AtomicBoolean();
|
|
|
|
|
|
|
|
void dispose(){
|
|
|
|
is_dispose.set( true );
|
|
|
|
}
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
String getColumnName( boolean bLong ){
|
2017-04-20 18:23:59 +02:00
|
|
|
switch( type ){
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
default:
|
2017-04-21 14:45:40 +02:00
|
|
|
return "?";
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HOME:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.home );
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_LOCAL:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.local_timeline );
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_FEDERATE:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.federate_timeline );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.statuses_of
|
2017-04-20 18:23:59 +02:00
|
|
|
, who_account != null ? access_info.getFullAcct( who_account ) : Long.toString( who_id )
|
|
|
|
);
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_FAVOURITES:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.favourites );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_REPORTS:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.reports );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_NOTIFICATIONS:
|
2017-04-21 14:45:40 +02:00
|
|
|
return activity.getString( R.string.notifications );
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_CONVERSATION:
|
2017-04-23 07:42:09 +02:00
|
|
|
return activity.getString( R.string.conversation_around,status_id );
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
return activity.getString( R.string.hashtag_of ,hashtag );
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_SEARCH:
|
|
|
|
if(bLong){
|
|
|
|
return activity.getString( R.string.search_of ,search_query );
|
|
|
|
}else{
|
|
|
|
return activity.getString( R.string.search );
|
|
|
|
}
|
2017-04-23 20:05:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-23 20:05:29 +02:00
|
|
|
public boolean isSameSpec( SavedAccount ai, int type, Object[] params ){
|
|
|
|
if( type != this.type || ! Utils.equalsNullable(ai.user,access_info.user ) ) return false;
|
|
|
|
switch( type ){
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-23 20:05:29 +02:00
|
|
|
try{
|
|
|
|
long who_id = (Long)getParamAt( params, 0 );
|
|
|
|
return who_id == this.who_id;
|
|
|
|
}catch(Throwable ex){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_CONVERSATION:
|
2017-04-23 20:05:29 +02:00
|
|
|
try{
|
|
|
|
long status_id = (Long)getParamAt( params, 0 );
|
|
|
|
return status_id == this.status_id;
|
|
|
|
}catch(Throwable ex){
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-23 17:16:05 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
try{
|
|
|
|
long status_id = (Long)getParamAt( params, 0 );
|
|
|
|
return status_id == this.status_id;
|
|
|
|
}catch(Throwable ex){
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-24 06:01:59 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2017-04-23 20:05:29 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
interface StatusEntryCallback {
|
2017-04-23 07:42:09 +02:00
|
|
|
void onIterate( TootStatus status );
|
2017-04-22 16:45:26 +02:00
|
|
|
}
|
|
|
|
|
2017-04-23 07:42:09 +02:00
|
|
|
// ブーストやお気に入りの更新に使う。ステータスを列挙する。
|
2017-04-24 06:01:59 +02:00
|
|
|
void findStatus( SavedAccount target_account, long target_status_id, StatusEntryCallback callback ){
|
2017-04-22 16:45:26 +02:00
|
|
|
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;
|
2017-04-23 07:42:09 +02:00
|
|
|
if( reblog != null ){
|
2017-04-22 16:45:26 +02:00
|
|
|
if( target_status_id == reblog.id ){
|
2017-04-24 06:01:59 +02:00
|
|
|
callback.onIterate( reblog );
|
2017-04-22 16:45:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-04-23 17:16:05 +02:00
|
|
|
// ミュート、ブロックが成功した時に呼ばれる
|
2017-04-24 06:01:59 +02:00
|
|
|
void removeStatusByAccount( SavedAccount target_account, long who_id ){
|
2017-04-23 17:16:05 +02:00
|
|
|
if( target_account.user.equals( access_info.user ) ){
|
|
|
|
{
|
|
|
|
// remove from status_list
|
|
|
|
TootStatus.List tmp_list = new TootStatus.List( status_list.size() );
|
|
|
|
for( TootStatus status : status_list ){
|
|
|
|
if( status.account.id == who_id
|
|
|
|
|| ( status.reblog != null && status.reblog.account.id == who_id )
|
|
|
|
){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tmp_list.add( status );
|
|
|
|
}
|
|
|
|
status_list.clear();
|
|
|
|
status_list.addAll( tmp_list );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// remove from notification_list
|
|
|
|
TootNotification.List tmp_list = new TootNotification.List( notification_list.size() );
|
|
|
|
for( TootNotification item : notification_list ){
|
|
|
|
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( item );
|
|
|
|
}
|
|
|
|
notification_list.clear();
|
|
|
|
notification_list.addAll( tmp_list );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-22 16:45:26 +02:00
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-23 17:16:05 +02:00
|
|
|
private final Runnable proc_fireVisualCallback = new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run(){
|
|
|
|
Iterator< VisualCallback > it = visual_callback.iterator();
|
|
|
|
while( it.hasNext() ){
|
|
|
|
it.next().onVisualColumn();
|
|
|
|
}
|
2017-04-20 18:23:59 +02:00
|
|
|
}
|
2017-04-23 17:16:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public void fireVisualCallback(){
|
|
|
|
Utils.runOnMainThread( proc_fireVisualCallback );
|
2017-04-20 18:23:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
AsyncTask< Void, Void, TootApiResult > last_task;
|
|
|
|
|
|
|
|
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 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();
|
|
|
|
}
|
|
|
|
|
2017-04-23 07:42:09 +02:00
|
|
|
static final String PATH_TL_HOME = "/api/v1/timelines/home?limit=80";
|
|
|
|
static final String PATH_TL_LOCAL = "/api/v1/timelines/public?limit=80&local=1";
|
|
|
|
static final String PATH_TL_FEDERATE = "/api/v1/timelines/public?limit=80";
|
|
|
|
static final String PATH_TL_FAVOURITES = "/api/v1/favourites?limit=80";
|
|
|
|
static final String PATH_TL_REPORTS = "/api/v1/reports?limit=80";
|
|
|
|
static final String PATH_TL_NOTIFICATIONS = "/api/v1/notifications?limit=80";
|
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
void startLoading(){
|
|
|
|
cancelLastTask();
|
|
|
|
|
2017-04-23 07:42:09 +02:00
|
|
|
mInitialLoadingError = null;
|
|
|
|
bInitialLoading = true;
|
|
|
|
max_id = null;
|
|
|
|
since_id = null;
|
|
|
|
|
|
|
|
fireVisualCallback();
|
|
|
|
|
2017-04-20 18:23:59 +02:00
|
|
|
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 ){
|
2017-04-23 07:42:09 +02:00
|
|
|
saveRange( result, true, true );
|
2017-04-23 20:05:29 +02:00
|
|
|
tmp_list_status = TootStatus.parseList( log, access_info,result.array );
|
2017-04-20 18:23:59 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TootApiResult parseAccount( TootApiResult result ){
|
|
|
|
if( result != null ){
|
2017-04-23 07:42:09 +02:00
|
|
|
saveRange( result, true, true );
|
2017-04-23 20:05:29 +02:00
|
|
|
who_account = TootAccount.parse( log, access_info,result.object );
|
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 );
|
2017-04-20 18:23:59 +02:00
|
|
|
tmp_list_report = TootReport.parseList( log, result.array );
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TootApiResult parseNotifications( TootApiResult result ){
|
|
|
|
if( result != null ){
|
2017-04-23 07:42:09 +02:00
|
|
|
saveRange( result, true, true );
|
2017-04-23 20:05:29 +02:00
|
|
|
tmp_list_notification = TootNotification.parseList( log, access_info,result.array );
|
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
|
2017-04-22 16:45:26 +02:00
|
|
|
public boolean isApiCancelled(){
|
|
|
|
return isCancelled() || is_dispose.get();
|
2017-04-20 18:23:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-04-22 16:45:26 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
2017-04-21 14:45:40 +02:00
|
|
|
client.setAccount( access_info );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
|
|
|
switch( type ){
|
|
|
|
default:
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HOME:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( PATH_TL_HOME ) );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_LOCAL:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( PATH_TL_LOCAL ) );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_FEDERATE:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( PATH_TL_FEDERATE ) );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-20 18:23:59 +02:00
|
|
|
if( who_account == null ){
|
2017-04-23 07:42:09 +02:00
|
|
|
parseAccount( client.request( "/api/v1/accounts/" + who_id + "?limit=80" ) );
|
2017-04-22 16:45:26 +02:00
|
|
|
client.callback.publishApiProgress( "" );
|
2017-04-20 18:23:59 +02:00
|
|
|
}
|
|
|
|
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( "/api/v1/accounts/" + who_id + "/statuses?limit=80" ) );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_FAVOURITES:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( PATH_TL_FAVOURITES ) );
|
2017-04-23 20:05:29 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
return parseStatuses( client.request( "/api/v1/timelines/tag/"+hashtag+"?limit=80" ) );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_REPORTS:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseReports( client.request( PATH_TL_REPORTS ) );
|
2017-04-20 18:23:59 +02:00
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_NOTIFICATIONS:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseNotifications( client.request( PATH_TL_NOTIFICATIONS ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_CONVERSATION:
|
2017-04-23 07:42:09 +02:00
|
|
|
TootApiResult result = client.request( "/api/v1/statuses/"+status_id );
|
|
|
|
if( result== null || result.object == null ) return result;
|
2017-04-23 20:05:29 +02:00
|
|
|
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( "/api/v1/statuses/"+status_id+"/context" );
|
|
|
|
if( result== null || result.object == null ) return result;
|
2017-04-23 20:05:29 +02:00
|
|
|
TootContext context = TootContext.parse( log,access_info,result.object );
|
2017-04-23 07:42:09 +02:00
|
|
|
tmp_list_status = new TootStatus.List();
|
|
|
|
if( context.ancestors != null ) tmp_list_status.addAll( context.ancestors);
|
|
|
|
tmp_list_status.add(target_status);
|
|
|
|
if( context.descendants != null ) tmp_list_status.addAll( context.descendants);
|
|
|
|
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{
|
|
|
|
switch( type ){
|
|
|
|
default:
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HOME:
|
|
|
|
case TYPE_LOCAL:
|
|
|
|
case TYPE_FEDERATE:
|
|
|
|
case TYPE_PROFILE:
|
|
|
|
case TYPE_FAVOURITES:
|
|
|
|
case TYPE_CONVERSATION:
|
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 07:42:09 +02:00
|
|
|
initList( status_list, tmp_list_status );
|
2017-04-20 18:23:59 +02:00
|
|
|
break;
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_REPORTS:
|
2017-04-23 07:42:09 +02:00
|
|
|
initList( report_list, tmp_list_report );
|
2017-04-20 18:23:59 +02:00
|
|
|
break;
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_NOTIFICATIONS:
|
2017-04-23 07:42:09 +02:00
|
|
|
initList( notification_list, tmp_list_notification );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fireVisualCallback();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AsyncTaskCompat.executeParallel( task );
|
|
|
|
}
|
|
|
|
|
|
|
|
static final Pattern reMaxId = Pattern.compile( "&max_id=(\\d+)" ); // より古いデータの取得に使う
|
|
|
|
static final Pattern reSinceId = Pattern.compile( "&since_id=(\\d+)" ); // より新しいデータの取得に使う
|
|
|
|
|
|
|
|
String max_id;
|
|
|
|
String since_id;
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String addRange( boolean bBottom, String path ){
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
< T extends TootId > void initList( ArrayList< T > dst, ArrayList< T > src ){
|
|
|
|
if( src == null ) return;
|
|
|
|
dst.clear();
|
|
|
|
dst.addAll( src );
|
|
|
|
}
|
|
|
|
|
|
|
|
< T extends TootId > void mergeList( ArrayList< T > dst, ArrayList< T > src, boolean bBottom ){
|
|
|
|
// 古いリストにある要素の集合
|
|
|
|
HashSet< Long > id_set = new HashSet();
|
|
|
|
for( T t : dst ){
|
|
|
|
id_set.add( t.id );
|
|
|
|
}
|
|
|
|
ArrayList< T > tmp_list = new ArrayList<>( src.size() );
|
|
|
|
for( T t : src ){
|
|
|
|
if( id_set.contains( t.id ) ) continue;
|
|
|
|
tmp_list.add( t );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ! bBottom ){
|
|
|
|
tmp_list.addAll( dst );
|
|
|
|
dst.clear();
|
|
|
|
dst.addAll( tmp_list );
|
|
|
|
}else{
|
|
|
|
dst.addAll( tmp_list );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean startRefresh( final boolean bBottom ){
|
|
|
|
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 ){
|
|
|
|
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 >() {
|
|
|
|
|
|
|
|
TootStatus.List tmp_list_status;
|
|
|
|
TootReport.List tmp_list_report;
|
|
|
|
TootNotification.List tmp_list_notification;
|
|
|
|
|
|
|
|
TootApiResult parseStatuses( TootApiResult result ){
|
|
|
|
if( result != null ){
|
|
|
|
saveRange( result, bBottom, ! bBottom );
|
2017-04-23 20:05:29 +02:00
|
|
|
tmp_list_status = TootStatus.parseList( log, access_info, result.array );
|
2017-04-23 07:42:09 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TootApiResult parseAccount( TootApiResult result ){
|
|
|
|
if( result != null ){
|
|
|
|
saveRange( result, bBottom, ! bBottom );
|
2017-04-23 20:05:29 +02:00
|
|
|
who_account = TootAccount.parse( log, access_info,result.object );
|
2017-04-23 07:42:09 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TootApiResult parseReports( TootApiResult result ){
|
|
|
|
if( result != null ){
|
|
|
|
saveRange( result, bBottom, ! bBottom );
|
|
|
|
tmp_list_report = TootReport.parseList( log, result.array );
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TootApiResult parseNotifications( TootApiResult result ){
|
|
|
|
if( result != null ){
|
|
|
|
saveRange( result, bBottom, ! bBottom );
|
2017-04-23 20:05:29 +02:00
|
|
|
tmp_list_notification = TootNotification.parseList( log, access_info,result.array );
|
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:
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HOME:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( addRange( bBottom, PATH_TL_HOME ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_LOCAL:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( addRange( bBottom, PATH_TL_LOCAL ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_FEDERATE:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( addRange( bBottom, PATH_TL_FEDERATE ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_PROFILE:
|
2017-04-23 07:42:09 +02:00
|
|
|
if( who_account == null ){
|
|
|
|
parseAccount( client.request( "/api/v1/accounts/" + who_id + "?limit=80" ) );
|
|
|
|
client.callback.publishApiProgress( "" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return parseStatuses( client.request( addRange( bBottom, "/api/v1/accounts/" + who_id + "/statuses?limit=80" ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_FAVOURITES:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseStatuses( client.request( addRange( bBottom, PATH_TL_FAVOURITES ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 20:05:29 +02:00
|
|
|
return parseStatuses( client.request( addRange( bBottom,"/api/v1/timelines/tag/"+hashtag+"?limit=80" ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_REPORTS:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseReports( client.request( addRange( bBottom, PATH_TL_REPORTS ) ) );
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_NOTIFICATIONS:
|
2017-04-23 07:42:09 +02:00
|
|
|
return parseNotifications( client.request( addRange( bBottom, PATH_TL_NOTIFICATIONS ) ) );
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@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{
|
|
|
|
switch( type ){
|
|
|
|
default:
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_HOME:
|
|
|
|
case TYPE_LOCAL:
|
|
|
|
case TYPE_FEDERATE:
|
|
|
|
case TYPE_PROFILE:
|
|
|
|
case TYPE_FAVOURITES:
|
|
|
|
case TYPE_HASHTAG:
|
2017-04-23 07:42:09 +02:00
|
|
|
mergeList( status_list, tmp_list_status, bBottom );
|
|
|
|
break;
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_REPORTS:
|
2017-04-23 07:42:09 +02:00
|
|
|
mergeList( report_list, tmp_list_report, bBottom );
|
|
|
|
break;
|
|
|
|
|
2017-04-24 06:01:59 +02:00
|
|
|
case TYPE_NOTIFICATIONS:
|
2017-04-23 07:42:09 +02:00
|
|
|
mergeList( notification_list, tmp_list_notification, bBottom );
|
2017-04-20 18:23:59 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|