Merge branch 'master' into patch-2
This commit is contained in:
commit
667c811013
|
@ -10,12 +10,13 @@ import android.net.Uri;
|
|||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.v4.text.BidiFormatter;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v4.view.ViewParentCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
@ -131,10 +132,10 @@ public class ActMain extends AppCompatActivity
|
|||
@Override protected void onSaveInstanceState( Bundle outState ){
|
||||
super.onSaveInstanceState( outState );
|
||||
|
||||
if(pager_adapter != null){
|
||||
if( pager_adapter != null ){
|
||||
outState.putInt( STATE_CURRENT_PAGE, pager.getCurrentItem() );
|
||||
}else{
|
||||
int ve =tablet_layout_manager.findLastVisibleItemPosition();
|
||||
int ve = tablet_layout_manager.findLastVisibleItemPosition();
|
||||
if( ve != RecyclerView.NO_POSITION ){
|
||||
outState.putInt( STATE_CURRENT_PAGE, ve );
|
||||
}
|
||||
|
@ -143,12 +144,12 @@ public class ActMain extends AppCompatActivity
|
|||
|
||||
@Override protected void onRestoreInstanceState( Bundle savedInstanceState ){
|
||||
super.onRestoreInstanceState( savedInstanceState );
|
||||
int pos = savedInstanceState.getInt( STATE_CURRENT_PAGE);
|
||||
int pos = savedInstanceState.getInt( STATE_CURRENT_PAGE );
|
||||
if( pos > 0 && pos < app_state.column_list.size() ){
|
||||
if(pager_adapter != null){
|
||||
pager.setCurrentItem(pos);
|
||||
if( pager_adapter != null ){
|
||||
pager.setCurrentItem( pos );
|
||||
}else{
|
||||
tablet_layout_manager.smoothScrollToPosition( tablet_pager,null,pos );
|
||||
tablet_layout_manager.smoothScrollToPosition( tablet_pager, null, pos );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -440,7 +441,7 @@ public class ActMain extends AppCompatActivity
|
|||
if( vs == ve && vs != RecyclerView.NO_POSITION ){
|
||||
column = app_state.column_list.get( vs );
|
||||
}else{
|
||||
Utils.showToast( this,false,getString(R.string.cant_close_column_by_back_button_when_multiple_column_shown) );
|
||||
Utils.showToast( this, false, getString( R.string.cant_close_column_by_back_button_when_multiple_column_shown ) );
|
||||
}
|
||||
}
|
||||
if( column != null ){
|
||||
|
@ -626,41 +627,39 @@ public class ActMain extends AppCompatActivity
|
|||
float density = dm.density;
|
||||
|
||||
int media_thumb_height = 64;
|
||||
sv = pref.getString(Pref.KEY_MEDIA_THUMB_HEIGHT,"");
|
||||
if( !TextUtils.isEmpty( sv )){
|
||||
sv = pref.getString( Pref.KEY_MEDIA_THUMB_HEIGHT, "" );
|
||||
if( ! TextUtils.isEmpty( sv ) ){
|
||||
try{
|
||||
int iv = Integer.parseInt( sv );
|
||||
if( iv >= 32 ){
|
||||
media_thumb_height = iv;
|
||||
}
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace( );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
app_state.media_thumb_height = (int)(0.5f + media_thumb_height *density);
|
||||
app_state.media_thumb_height = (int) ( 0.5f + media_thumb_height * density );
|
||||
|
||||
int column_w_min_dp = COLUMN_WIDTH_MIN_DP;
|
||||
sv = pref.getString(Pref.KEY_COLUMN_WIDTH,"");
|
||||
if( !TextUtils.isEmpty( sv )){
|
||||
sv = pref.getString( Pref.KEY_COLUMN_WIDTH, "" );
|
||||
if( ! TextUtils.isEmpty( sv ) ){
|
||||
try{
|
||||
int iv = Integer.parseInt( sv );
|
||||
if( iv >= 100 ){
|
||||
column_w_min_dp = iv;
|
||||
}
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace( );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
int column_w_min = (int) ( 0.5f + column_w_min_dp * density );
|
||||
|
||||
int sw = dm.widthPixels;
|
||||
|
||||
|
||||
|
||||
pager = (ViewPager) findViewById( R.id.viewPager );
|
||||
tablet_pager = (RecyclerView) findViewById( R.id.rvPager );
|
||||
|
||||
if( pref.getBoolean(Pref.KEY_DISABLE_TABLET_MODE,false) || sw < column_w_min * 2 ){
|
||||
if( pref.getBoolean( Pref.KEY_DISABLE_TABLET_MODE, false ) || sw < column_w_min * 2 ){
|
||||
tablet_pager.setVisibility( View.GONE );
|
||||
|
||||
// SmartPhone mode
|
||||
|
@ -914,9 +913,10 @@ public class ActMain extends AppCompatActivity
|
|||
// プロフURL
|
||||
if( "https".equals( uri.getScheme() ) ){
|
||||
if( uri.getPath().startsWith( "/@" ) ){
|
||||
// ステータスをアプリ内で開く
|
||||
|
||||
Matcher m = reStatusPage.matcher( uri.toString() );
|
||||
if( m.find() ){
|
||||
// ステータスをアプリ内で開く
|
||||
try{
|
||||
// https://mastodon.juggler.jp/@SubwayTooter/(status_id)
|
||||
final String host = m.group( 1 );
|
||||
|
@ -957,38 +957,47 @@ public class ActMain extends AppCompatActivity
|
|||
return;
|
||||
}
|
||||
|
||||
// ユーザページをアプリ内で開く
|
||||
m = reUserPage.matcher( uri.toString() );
|
||||
if( m.find() ){
|
||||
// ユーザページをアプリ内で開く
|
||||
|
||||
// https://mastodon.juggler.jp/@SubwayTooter
|
||||
final String host = m.group( 1 );
|
||||
final String user = Uri.decode( m.group( 2 ) );
|
||||
|
||||
ArrayList< SavedAccount > account_list_same_host = new ArrayList<>();
|
||||
for( SavedAccount a : SavedAccount.loadAccountList( log ) ){
|
||||
// 1: 検索APIは疑似アカウントでは開けない => startFindAccountが使えない
|
||||
// 2: かりに検索できたとしてもユーザページは疑似アカウントでは開けない
|
||||
|
||||
ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( log );
|
||||
ArrayList< SavedAccount > account_list_filtered = new ArrayList<>();
|
||||
for( SavedAccount a : account_list ){
|
||||
if( a.isPseudo() ) continue;
|
||||
if( host.equalsIgnoreCase( a.host ) ){
|
||||
account_list_same_host.add( a );
|
||||
account_list_filtered.add( a );
|
||||
}
|
||||
}
|
||||
|
||||
// ソートする
|
||||
Collections.sort( account_list_same_host, new Comparator< SavedAccount >() {
|
||||
@Override public int compare( SavedAccount a, SavedAccount b ){
|
||||
return String.CASE_INSENSITIVE_ORDER.compare( AcctColor.getNickname( a.acct ), AcctColor.getNickname( b.acct ) );
|
||||
}
|
||||
} );
|
||||
if( account_list_filtered.isEmpty() ){
|
||||
|
||||
if( account_list_same_host.isEmpty() ){
|
||||
account_list_same_host.add( addPseudoAccount( host ) );
|
||||
for( SavedAccount a : account_list ){
|
||||
if( a.isPseudo() ) continue;
|
||||
account_list_filtered.add( a );
|
||||
}
|
||||
|
||||
if( account_list_filtered.isEmpty() ){
|
||||
// 認証されたアカウントが全くないので、ブラウザで開くしかない
|
||||
openChromeTab( getDefaultInsertPosition(), null, uri.toString(), true );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AccountPicker.pick( this, true, true
|
||||
AccountPicker.pick( this, false, true
|
||||
, getString( R.string.account_picker_open_user_who, user + "@" + host )
|
||||
, account_list_same_host
|
||||
, account_list_filtered
|
||||
, new AccountPicker.AccountPickerCallback() {
|
||||
@Override public void onAccountPicked( @NonNull final SavedAccount ai ){
|
||||
startGetAccount( ai, host, user, new GetAccountCallback() {
|
||||
@Override public void onGetAccount( TootAccount who ){
|
||||
startFindAccount( ai, host, user, new FindAccountCallback() {
|
||||
@Override public void onFindAccount( TootAccount who ){
|
||||
if( who != null ){
|
||||
performOpenUser( getDefaultInsertPosition(), ai, who );
|
||||
return;
|
||||
|
@ -1016,7 +1025,10 @@ public class ActMain extends AppCompatActivity
|
|||
SavedAccount account = SavedAccount.loadAccount( log, db_id );
|
||||
if( account != null ){
|
||||
Column column = addColumn( getDefaultInsertPosition(), account, Column.TYPE_NOTIFICATIONS );
|
||||
|
||||
// 通知を読み直す
|
||||
if( ! column.bInitialLoading ){
|
||||
column.startLoading();
|
||||
}
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
|
@ -1024,6 +1036,8 @@ public class ActMain extends AppCompatActivity
|
|||
return;
|
||||
}
|
||||
|
||||
// OAuth2 認証コールバック
|
||||
|
||||
final ProgressDialog progress = new ProgressDialog( ActMain.this );
|
||||
|
||||
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
|
||||
|
@ -1227,8 +1241,8 @@ public class ActMain extends AppCompatActivity
|
|||
}else if( page_delete > 0 && page_showing == page_delete ){
|
||||
int idx = page_delete - 1;
|
||||
scrollToColumn( idx );
|
||||
Column c = app_state.column_list.get(idx);
|
||||
if( ! c.bInitialLoading ){
|
||||
Column c = app_state.column_list.get( idx );
|
||||
if( ! c.bFirstInitialized ){
|
||||
c.startLoading();
|
||||
}
|
||||
}
|
||||
|
@ -1241,8 +1255,8 @@ public class ActMain extends AppCompatActivity
|
|||
}else if( page_delete > 0 ){
|
||||
int idx = page_delete - 1;
|
||||
scrollToColumn( idx );
|
||||
Column c = app_state.column_list.get(idx);
|
||||
if( ! c.bInitialLoading ){
|
||||
Column c = app_state.column_list.get( idx );
|
||||
if( ! c.bFirstInitialized ){
|
||||
c.startLoading();
|
||||
}
|
||||
}
|
||||
|
@ -1268,7 +1282,7 @@ public class ActMain extends AppCompatActivity
|
|||
Column col = new Column( app_state, ai, this, type, params );
|
||||
index = addColumn( col, index );
|
||||
scrollToColumn( index );
|
||||
if( ! col.bInitialLoading ){
|
||||
if( ! col.bFirstInitialized ){
|
||||
col.startLoading();
|
||||
}
|
||||
return col;
|
||||
|
@ -1321,13 +1335,13 @@ public class ActMain extends AppCompatActivity
|
|||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
interface GetAccountCallback {
|
||||
interface FindAccountCallback {
|
||||
// return account information
|
||||
// if failed, account is null.
|
||||
void onGetAccount( TootAccount account );
|
||||
void onFindAccount( TootAccount account );
|
||||
}
|
||||
|
||||
void startGetAccount( final SavedAccount access_info, final String host, final String user, final GetAccountCallback callback ){
|
||||
void startFindAccount( final SavedAccount access_info, final String host, final String user, final FindAccountCallback callback ){
|
||||
|
||||
final ProgressDialog progress = new ProgressDialog( this );
|
||||
final AsyncTask< Void, Void, TootAccount > task = new AsyncTask< Void, Void, TootAccount >() {
|
||||
|
@ -1380,7 +1394,7 @@ public class ActMain extends AppCompatActivity
|
|||
@Override
|
||||
protected void onPostExecute( TootAccount result ){
|
||||
progress.dismiss();
|
||||
callback.onGetAccount( result );
|
||||
callback.onFindAccount( result );
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -1396,15 +1410,15 @@ public class ActMain extends AppCompatActivity
|
|||
task.executeOnExecutor( App1.task_executor );
|
||||
}
|
||||
|
||||
static final Pattern reHashTag = Pattern.compile( "\\Ahttps://([^/]+)/tags/([^?#]+)\\z" );
|
||||
static final Pattern reUserPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/]+)\\z" );
|
||||
static final Pattern reStatusPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/]+)/(\\d+)\\z" );
|
||||
static final Pattern reHashTag = Pattern.compile( "\\Ahttps://([^/]+)/tags/([^?#]+)(?:\\z|\\?)" );
|
||||
static final Pattern reUserPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/]+)(?:\\z|\\?)" );
|
||||
static final Pattern reStatusPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/]+)/(\\d+)(?:\\z|\\?)" );
|
||||
|
||||
public void openChromeTab( final int pos, final SavedAccount access_info, final String url, boolean noIntercept ){
|
||||
public void openChromeTab( final int pos, @Nullable final SavedAccount access_info, final String url, boolean noIntercept ){
|
||||
try{
|
||||
log.d( "openChromeTab url=%s", url );
|
||||
|
||||
if( ! noIntercept ){
|
||||
if( ! noIntercept && access_info != null ){
|
||||
// ハッシュタグをアプリ内で開く
|
||||
Matcher m = reHashTag.matcher( url );
|
||||
if( m.find() ){
|
||||
|
@ -1446,18 +1460,64 @@ public class ActMain extends AppCompatActivity
|
|||
// https://mastodon.juggler.jp/@SubwayTooter
|
||||
final String host = m.group( 1 );
|
||||
final String user = Uri.decode( m.group( 2 ) );
|
||||
startGetAccount( access_info, host, user, new GetAccountCallback() {
|
||||
@Override public void onGetAccount( TootAccount who ){
|
||||
if( who != null ){
|
||||
performOpenUser( pos, access_info, who );
|
||||
return;
|
||||
}
|
||||
openChromeTab( pos, access_info, url, true );
|
||||
}
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! access_info.isPseudo() ){
|
||||
startFindAccount( access_info, host, user, new FindAccountCallback() {
|
||||
@Override public void onFindAccount( TootAccount who ){
|
||||
if( who != null ){
|
||||
performOpenUser( pos, access_info, who );
|
||||
return;
|
||||
}
|
||||
openChromeTab( pos, access_info, url, true );
|
||||
}
|
||||
} );
|
||||
return;
|
||||
}
|
||||
// 1: 検索APIは疑似アカウントでは開けない => startFindAccountが使えない
|
||||
// 2: かりに検索できたとしてもユーザページは疑似アカウントでは開けない
|
||||
|
||||
ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( log );
|
||||
ArrayList< SavedAccount > account_list_filtered = new ArrayList<>();
|
||||
for( SavedAccount a : account_list ){
|
||||
if( a.isPseudo() ) continue;
|
||||
if( host.equalsIgnoreCase( a.host ) ){
|
||||
account_list_filtered.add( a );
|
||||
}
|
||||
}
|
||||
|
||||
if( account_list_filtered.isEmpty() ){
|
||||
|
||||
for( SavedAccount a : account_list ){
|
||||
if( a.isPseudo() ) continue;
|
||||
account_list_filtered.add( a );
|
||||
}
|
||||
|
||||
if( account_list_filtered.isEmpty() ){
|
||||
// 認証されたアカウントが全くないので、ブラウザで開くしかない
|
||||
openChromeTab( getDefaultInsertPosition(), null, url, true );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AccountPicker.pick( this, false, true
|
||||
, getString( R.string.account_picker_open_user_who, user + "@" + host )
|
||||
, account_list_filtered
|
||||
, new AccountPicker.AccountPickerCallback() {
|
||||
@Override public void onAccountPicked( @NonNull final SavedAccount ai ){
|
||||
startFindAccount( ai, host, user, new FindAccountCallback() {
|
||||
@Override public void onFindAccount( TootAccount who ){
|
||||
if( who != null ){
|
||||
performOpenUser( getDefaultInsertPosition(), ai, who );
|
||||
return;
|
||||
}
|
||||
openChromeTab( getDefaultInsertPosition(), ai, url, true );
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
|
@ -1641,10 +1701,6 @@ public class ActMain extends AppCompatActivity
|
|||
} );
|
||||
}
|
||||
|
||||
public void performReply( SavedAccount account, TootStatus status ){
|
||||
ActPost.open( this, REQUEST_CODE_POST, account.db_id, status );
|
||||
}
|
||||
|
||||
public void performMention( SavedAccount account, TootAccount who ){
|
||||
ActPost.open( this, REQUEST_CODE_POST, account.db_id, "@" + account.getFullAcct( who ) + " " );
|
||||
}
|
||||
|
@ -1969,6 +2025,66 @@ public class ActMain extends AppCompatActivity
|
|||
showColumnMatchAccount( access_info );
|
||||
}
|
||||
|
||||
public void performReply(
|
||||
final SavedAccount access_info
|
||||
, final TootStatus arg_status
|
||||
, final boolean bRemote
|
||||
){
|
||||
if( ! bRemote ){
|
||||
ActPost.open( this, REQUEST_CODE_POST, access_info.db_id, arg_status );
|
||||
return;
|
||||
}
|
||||
|
||||
new AsyncTask< Void, Void, TootApiResult >() {
|
||||
TootStatus target_status;
|
||||
|
||||
@Override protected TootApiResult doInBackground( Void... params ){
|
||||
TootApiClient client = new TootApiClient( ActMain.this, new TootApiClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return isCancelled();
|
||||
}
|
||||
|
||||
@Override public void publishApiProgress( final String s ){
|
||||
}
|
||||
} );
|
||||
client.setAccount( access_info );
|
||||
|
||||
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
||||
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( arg_status.url ) );
|
||||
path = path + "&resolve=1";
|
||||
|
||||
TootApiResult result = client.request( path );
|
||||
if( result != null && result.object != null ){
|
||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
||||
if( tmp != null && tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
||||
target_status = tmp.statuses.get( 0 );
|
||||
log.d( "status id conversion %s => %s", arg_status.id, target_status.id );
|
||||
}
|
||||
if( target_status == null ){
|
||||
return new TootApiResult( getString( R.string.status_id_conversion_failed ) );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled( TootApiResult result ){
|
||||
super.onPostExecute( result );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
if( result == null ){
|
||||
// cancelled.
|
||||
}else if( target_status != null ){
|
||||
ActPost.open( ActMain.this, REQUEST_CODE_POST, access_info.db_id, target_status );
|
||||
}else{
|
||||
Utils.showToast( ActMain.this, true, result.error );
|
||||
}
|
||||
}
|
||||
}.executeOnExecutor( App1.task_executor );
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
private void performAccountSetting(){
|
||||
|
@ -2838,6 +2954,21 @@ public class ActMain extends AppCompatActivity
|
|||
} );
|
||||
}
|
||||
|
||||
void openReplyFromAnotherAccount( @NonNull final SavedAccount access_info, final TootStatus status ){
|
||||
if( status == null ) return;
|
||||
AccountPicker.pick( this, false, false
|
||||
, getString( R.string.account_picker_reply )
|
||||
, makeAccountListNonPseudo( log ), new AccountPicker.AccountPickerCallback() {
|
||||
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
|
||||
performReply(
|
||||
ai
|
||||
, status
|
||||
, ! ai.host.equalsIgnoreCase( access_info.host )
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, TootStatus status ){
|
||||
if( status == null ) return;
|
||||
openFollowFromAnotherAccount( access_info, status.account );
|
||||
|
@ -2855,6 +2986,9 @@ public class ActMain extends AppCompatActivity
|
|||
} );
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// タブレット対応で必要になった関数など
|
||||
|
||||
private boolean closeColumnSetting(){
|
||||
if( pager_adapter != null ){
|
||||
ColumnViewHolder vh = pager_adapter.getColumnViewHolder( pager.getCurrentItem() );
|
||||
|
@ -2911,7 +3045,6 @@ public class ActMain extends AppCompatActivity
|
|||
updateColumnStrip();
|
||||
|
||||
return index;
|
||||
|
||||
}
|
||||
|
||||
private void removeColumn( Column column ){
|
||||
|
@ -2966,15 +3099,15 @@ public class ActMain extends AppCompatActivity
|
|||
private void resizeColumnWidth(){
|
||||
|
||||
int column_w_min_dp = COLUMN_WIDTH_MIN_DP;
|
||||
String sv = pref.getString(Pref.KEY_COLUMN_WIDTH,"");
|
||||
if( !TextUtils.isEmpty( sv )){
|
||||
String sv = pref.getString( Pref.KEY_COLUMN_WIDTH, "" );
|
||||
if( ! TextUtils.isEmpty( sv ) ){
|
||||
try{
|
||||
int iv = Integer.parseInt( sv );
|
||||
if( iv >= 100 ){
|
||||
column_w_min_dp = iv;
|
||||
}
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace( );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,12 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import jp.juggler.subwaytooter.api.TootApiClient;
|
||||
import jp.juggler.subwaytooter.api.TootApiResult;
|
||||
import jp.juggler.subwaytooter.api.entity.TootApplication;
|
||||
import jp.juggler.subwaytooter.api.entity.TootNotification;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||
import jp.juggler.subwaytooter.table.MutedApp;
|
||||
|
@ -146,44 +147,57 @@ public class AlarmService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
TootApiClient client = new TootApiClient( this, new TootApiClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public void publishApiProgress( String s ){
|
||||
|
||||
}
|
||||
} );
|
||||
final AtomicBoolean bAlarmRequired = new AtomicBoolean( false );
|
||||
final HashSet< String > muted_app = MutedApp.getNameSet();
|
||||
final HashSet< String > muted_word = MutedWord.getNameSet();
|
||||
|
||||
boolean bAlarmRequired = false;
|
||||
LinkedList<Thread> thread_list = new LinkedList<>( );
|
||||
for( SavedAccount _a : account_list ){
|
||||
final SavedAccount account = _a;
|
||||
Thread t = new Thread( new Runnable() {
|
||||
@Override public void run(){
|
||||
|
||||
HashSet< String > muted_app = MutedApp.getNameSet();
|
||||
HashSet< String > muted_word = MutedWord.getNameSet();
|
||||
try{
|
||||
if( account.notification_mention
|
||||
|| account.notification_boost
|
||||
|| account.notification_favourite
|
||||
|| account.notification_follow
|
||||
){
|
||||
bAlarmRequired.set(true);
|
||||
|
||||
for( SavedAccount account : account_list ){
|
||||
try{
|
||||
if( account.notification_mention
|
||||
|| account.notification_boost
|
||||
|| account.notification_favourite
|
||||
|| account.notification_follow
|
||||
){
|
||||
bAlarmRequired = true;
|
||||
|
||||
ArrayList< Data > data_list = new ArrayList<>();
|
||||
|
||||
checkAccount( client, data_list, account, muted_app ,muted_word);
|
||||
|
||||
showNotification( account.db_id, data_list );
|
||||
TootApiClient client = new TootApiClient( AlarmService.this, new TootApiClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return false;
|
||||
}
|
||||
@Override public void publishApiProgress( String s ){
|
||||
}
|
||||
} );
|
||||
|
||||
ArrayList< Data > data_list = new ArrayList<>();
|
||||
checkAccount( client, data_list, account, muted_app ,muted_word);
|
||||
showNotification( account.db_id, data_list );
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
} );
|
||||
thread_list.add( t);
|
||||
t.start();
|
||||
}
|
||||
|
||||
for( Thread t : thread_list ){
|
||||
try{
|
||||
t.join();
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace( );
|
||||
}
|
||||
}
|
||||
|
||||
alarm_manager.cancel( pi_next );
|
||||
if( bAlarmRequired ){
|
||||
if( bAlarmRequired.get() ){
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
alarm_manager.setWindow(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP
|
||||
|
|
|
@ -48,7 +48,6 @@ import jp.juggler.subwaytooter.util.Utils;
|
|||
class Column implements StreamReader.Callback {
|
||||
private static final LogCategory log = new LogCategory( "Column" );
|
||||
|
||||
|
||||
interface Callback {
|
||||
boolean isActivityResume();
|
||||
}
|
||||
|
@ -374,6 +373,13 @@ class Column implements StreamReader.Callback {
|
|||
void dispose(){
|
||||
is_dispose.set( true );
|
||||
stopStreaming();
|
||||
|
||||
if( _holder != null ){
|
||||
try{
|
||||
_holder.getListView().setAdapter( null );
|
||||
}catch( Throwable ignored ){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getColumnName( boolean bLong ){
|
||||
|
@ -698,41 +704,43 @@ class Column implements StreamReader.Callback {
|
|||
AlarmService.dataRemoved( context, access_info.db_id );
|
||||
}
|
||||
|
||||
private ColumnViewHolder holder;
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setColumnViewHolder( ColumnViewHolder holder ){
|
||||
this.holder = holder;
|
||||
private ColumnViewHolder _holder;
|
||||
|
||||
void setColumnViewHolder( ColumnViewHolder new_holder ){
|
||||
this._holder = new_holder;
|
||||
}
|
||||
|
||||
private final Runnable proc_showContent = new Runnable() {
|
||||
@Override public void run(){
|
||||
if( holder != null ) holder.showContent();
|
||||
}
|
||||
};
|
||||
private final Runnable proc_showColumnHeader = new Runnable() {
|
||||
@Override public void run(){
|
||||
if( holder != null ) holder.showColumnHeader();
|
||||
}
|
||||
};
|
||||
private final Runnable proc_showColumnColor = new Runnable() {
|
||||
@Override public void run(){
|
||||
if( holder != null ) holder.showColumnColor();
|
||||
}
|
||||
};
|
||||
private ColumnViewHolder getViewHolder(){
|
||||
return is_dispose.get() ? null : _holder;
|
||||
}
|
||||
|
||||
void fireShowContent(){
|
||||
Utils.runOnMainThread( proc_showContent );
|
||||
if( ! Utils.isMainThread() ){
|
||||
throw new RuntimeException( "fireShowColumnHeader: not on main thread." );
|
||||
}
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.showContent();
|
||||
}
|
||||
|
||||
// カラムヘッダ部分だけ更新する
|
||||
void fireShowColumnHeader(){
|
||||
Utils.runOnMainThread( proc_showColumnHeader );
|
||||
if( ! Utils.isMainThread() ){
|
||||
throw new RuntimeException( "fireShowColumnHeader: not on main thread." );
|
||||
}
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.showColumnHeader();
|
||||
}
|
||||
|
||||
void fireColumnColor(){
|
||||
Utils.runOnMainThread( proc_showColumnColor );
|
||||
if( ! Utils.isMainThread() ){
|
||||
throw new RuntimeException( "fireShowColumnHeader: not on main thread." );
|
||||
}
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.showColumnColor();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private AsyncTask< Void, Void, TootApiResult > last_task;
|
||||
|
||||
|
@ -907,6 +915,13 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
fireShowContent();
|
||||
|
||||
try{
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.getRefreshLayout().setRefreshing( false );
|
||||
}catch(Throwable ignored){
|
||||
|
||||
}
|
||||
|
||||
AsyncTask< Void, Void, TootApiResult > task = this.last_task = new AsyncTask< Void, Void, TootApiResult >() {
|
||||
|
||||
TootApiResult parseAccount1( TootApiClient client, String path_base ){
|
||||
|
@ -1166,6 +1181,7 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
if( is_dispose.get() ) return;
|
||||
|
||||
if( isCancelled() || result == null ){
|
||||
return;
|
||||
|
@ -1189,8 +1205,9 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
// 初期ロードの直後は先頭に移動する
|
||||
try{
|
||||
holder.getListView().setSelection( 0 );
|
||||
}catch(Throwable ignored){
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.getListView().setSelection( 0 );
|
||||
}catch( Throwable ignored ){
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1362,14 +1379,15 @@ class Column implements StreamReader.Callback {
|
|||
case TYPE_FEDERATE:
|
||||
startRefresh( true, false, status_id, refresh_after_toot );
|
||||
break;
|
||||
|
||||
case TYPE_PROFILE:
|
||||
if( profile_tab == TAB_STATUS && profile_id == access_info.id ){
|
||||
startRefresh( true, false, status_id, refresh_after_toot );
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CONVERSATION:
|
||||
startLoading();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1381,22 +1399,26 @@ class Column implements StreamReader.Callback {
|
|||
if( last_task != null ){
|
||||
if( ! bSilent ){
|
||||
Utils.showToast( context, true, R.string.column_is_busy );
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.getRefreshLayout().setRefreshing( false );
|
||||
}
|
||||
return;
|
||||
}else if( bBottom && max_id == null ){
|
||||
if( ! bSilent ){
|
||||
Utils.showToast( context, true, R.string.end_of_list );
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.getRefreshLayout().setRefreshing( false );
|
||||
}
|
||||
return;
|
||||
}else if( ! bBottom && since_id == null ){
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ) holder.getRefreshLayout().setRefreshing( false );
|
||||
startLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
if( bSilent ){
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ){
|
||||
holder.getRefreshLayout().setRefreshing( true );
|
||||
}
|
||||
|
@ -1820,6 +1842,8 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
if( is_dispose.get() ) return;
|
||||
|
||||
if( isCancelled() || result == null ){
|
||||
return;
|
||||
}
|
||||
|
@ -1846,6 +1870,7 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
// 事前にスクロール位置を覚えておく
|
||||
ScrollPosition sp = null;
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ){
|
||||
sp = holder.getScrollPosition();
|
||||
}
|
||||
|
@ -1911,6 +1936,7 @@ class Column implements StreamReader.Callback {
|
|||
return;
|
||||
}
|
||||
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
if( holder != null ){
|
||||
holder.getRefreshLayout().setRefreshing( true );
|
||||
}
|
||||
|
@ -2223,10 +2249,12 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
if( is_dispose.get() ) return;
|
||||
|
||||
if( isCancelled() || result == null ){
|
||||
return;
|
||||
}
|
||||
|
||||
last_task = null;
|
||||
bRefreshLoading = false;
|
||||
|
||||
|
@ -2243,16 +2271,18 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
ArrayList< Object > list_new = duplicate_map.filterDuplicate( list_tmp );
|
||||
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
|
||||
// idx番目の要素がListViewのtopから何ピクセル下にあるか
|
||||
int restore_idx = position + 1;
|
||||
int restore_y = 0;
|
||||
if( holder != null ){
|
||||
try{
|
||||
restore_y = getItemTop( restore_idx );
|
||||
restore_y = getItemTop( holder, restore_idx );
|
||||
}catch( IndexOutOfBoundsException ex ){
|
||||
restore_idx = position;
|
||||
try{
|
||||
restore_y = getItemTop( restore_idx );
|
||||
restore_y = getItemTop( holder, restore_idx );
|
||||
}catch( IndexOutOfBoundsException ex2 ){
|
||||
restore_idx = - 1;
|
||||
}
|
||||
|
@ -2267,7 +2297,7 @@ class Column implements StreamReader.Callback {
|
|||
if( holder != null ){
|
||||
//noinspection StatementWithEmptyBody
|
||||
if( restore_idx >= 0 ){
|
||||
setItemTop( restore_idx + added - 1, restore_y );
|
||||
setItemTop( holder, restore_idx + added - 1, restore_y );
|
||||
}else{
|
||||
// ギャップが画面内にない場合、何もしない
|
||||
}
|
||||
|
@ -2293,7 +2323,8 @@ class Column implements StreamReader.Callback {
|
|||
}
|
||||
|
||||
// 特定の要素が特定の位置に来るようにスクロール位置を調整する
|
||||
private void setItemTop( int idx, int y ){
|
||||
private void setItemTop( @NonNull ColumnViewHolder holder, int idx, int y ){
|
||||
|
||||
MyListView listView = holder.getListView();
|
||||
boolean hasHeader = holder.hasHeaderView();
|
||||
if( hasHeader ){
|
||||
|
@ -2309,7 +2340,8 @@ class Column implements StreamReader.Callback {
|
|||
listView.setSelectionFromTop( idx, y );
|
||||
}
|
||||
|
||||
private int getItemTop( int idx ){
|
||||
private int getItemTop( @NonNull ColumnViewHolder holder, int idx ){
|
||||
|
||||
MyListView listView = holder.getListView();
|
||||
boolean hasHeader = holder.hasHeaderView();
|
||||
|
||||
|
@ -2382,6 +2414,7 @@ class Column implements StreamReader.Callback {
|
|||
log.e( ex, "getId() failed. o=", list_new.get( 0 ) );
|
||||
}
|
||||
}
|
||||
ColumnViewHolder holder = getViewHolder();
|
||||
|
||||
// 事前にスクロール位置を覚えておく
|
||||
ScrollPosition sp = null;
|
||||
|
@ -2396,7 +2429,7 @@ class Column implements StreamReader.Callback {
|
|||
if( list_data.size() > 0 ){
|
||||
try{
|
||||
restore_idx = holder.getListView().getFirstVisiblePosition();
|
||||
restore_y = getItemTop( restore_idx );
|
||||
restore_y = getItemTop( holder, restore_idx );
|
||||
}catch( IndexOutOfBoundsException ex ){
|
||||
restore_idx = - 1;
|
||||
restore_y = 0;
|
||||
|
@ -2426,11 +2459,11 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
if( holder != null ){
|
||||
//noinspection StatementWithEmptyBody
|
||||
if( sp == null || ( sp.pos == 0 && sp.top == 0 ) ){
|
||||
if( sp.pos == 0 && sp.top == 0 ){
|
||||
// スクロール位置が先頭なら先頭のまま
|
||||
}else if( restore_idx >= 0 ){
|
||||
//
|
||||
setItemTop( restore_idx + added, restore_y );
|
||||
setItemTop( holder, restore_idx + added, restore_y );
|
||||
}else{
|
||||
// ギャップが画面内にない場合、何もしない
|
||||
}
|
||||
|
@ -2446,6 +2479,7 @@ class Column implements StreamReader.Callback {
|
|||
};
|
||||
|
||||
@Override public void onStreamingMessage( String event_type, Object o ){
|
||||
if( is_dispose.get() ) return;
|
||||
|
||||
if( o instanceof Long ){
|
||||
removeStatus( access_info, (Long) o );
|
||||
|
@ -2529,9 +2563,9 @@ class Column implements StreamReader.Callback {
|
|||
log.d( "onResume: bRefreshingTop is true." );
|
||||
}else if(
|
||||
! bRefreshLoading
|
||||
&& canAutoRefresh()
|
||||
&& ! App1.getAppState( context ).pref.getBoolean( Pref.KEY_DONT_REFRESH_ON_RESUME, false )
|
||||
&& ! dont_auto_refresh
|
||||
&& canAutoRefresh()
|
||||
&& ! App1.getAppState( context ).pref.getBoolean( Pref.KEY_DONT_REFRESH_ON_RESUME, false )
|
||||
&& ! dont_auto_refresh
|
||||
){
|
||||
|
||||
// リフレッシュしてからストリーミング開始
|
||||
|
@ -2589,7 +2623,6 @@ class Column implements StreamReader.Callback {
|
|||
|
||||
private boolean bPutGap;
|
||||
|
||||
|
||||
private void resumeStreaming( boolean bPutGap ){
|
||||
|
||||
if( ! canStreaming() ){
|
||||
|
|
|
@ -14,7 +14,7 @@ class ColumnPagerAdapter extends PagerAdapter {
|
|||
|
||||
private final ActMain activity;
|
||||
private final LayoutInflater inflater;
|
||||
final ArrayList< Column > column_list;
|
||||
private final ArrayList< Column > column_list;
|
||||
private final SparseArray< ColumnViewHolder > holder_list = new SparseArray<>();
|
||||
|
||||
|
||||
|
@ -51,11 +51,11 @@ class ColumnPagerAdapter extends PagerAdapter {
|
|||
container.addView( root, 0 );
|
||||
|
||||
Column column = column_list.get( page_idx );
|
||||
ColumnViewHolder holder = new ColumnViewHolder( activity, column );
|
||||
ColumnViewHolder holder = new ColumnViewHolder( activity,root );
|
||||
//
|
||||
holder_list.put( page_idx, holder );
|
||||
//
|
||||
holder.onPageCreate( root, page_idx, column_list.size() );
|
||||
holder.onPageCreate( column, page_idx, column_list.size() );
|
||||
|
||||
return root;
|
||||
}
|
||||
|
@ -68,8 +68,7 @@ class ColumnPagerAdapter extends PagerAdapter {
|
|||
ColumnViewHolder holder = holder_list.get( page_idx );
|
||||
holder_list.remove( page_idx );
|
||||
if( holder != null ){
|
||||
|
||||
holder.onPageDestroy( view );
|
||||
holder.onPageDestroy();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package jp.juggler.subwaytooter;
|
|||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
|
@ -16,12 +17,12 @@ import android.widget.CompoundButton;
|
|||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout;
|
||||
import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirection;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.table.AcctColor;
|
||||
|
@ -38,66 +39,54 @@ class ColumnViewHolder
|
|||
private static final LogCategory log = new LogCategory( "ColumnViewHolder" );
|
||||
|
||||
final ActMain activity;
|
||||
final Column column;
|
||||
private final AtomicBoolean is_destroyed = new AtomicBoolean( false );
|
||||
private final ItemListAdapter status_adapter;
|
||||
|
||||
ColumnViewHolder( ActMain activity, Column column ){
|
||||
this.activity = activity;
|
||||
this.column = column;
|
||||
this.status_adapter = new ItemListAdapter( activity, column );
|
||||
}
|
||||
@Nullable Column column;
|
||||
@Nullable private HeaderViewHolder vh_header;
|
||||
@Nullable private ItemListAdapter status_adapter;
|
||||
|
||||
private boolean isPageDestroyed(){
|
||||
return is_destroyed.get() || activity.isFinishing();
|
||||
}
|
||||
private final TextView tvLoading;
|
||||
private final MyListView listView;
|
||||
private final SwipyRefreshLayout swipyRefreshLayout;
|
||||
|
||||
void onPageDestroy( @SuppressWarnings("UnusedParameters") View root ){
|
||||
log.d( "onPageDestroy:%s", column.getColumnName( true ) );
|
||||
is_destroyed.set( true );
|
||||
private final View llColumnHeader;
|
||||
private final TextView tvColumnIndex;
|
||||
private final TextView tvColumnContext;
|
||||
private final ImageView ivColumnIcon;
|
||||
private final TextView tvColumnName;
|
||||
|
||||
saveScrollPosition();
|
||||
private final View llColumnSetting;
|
||||
|
||||
column.setColumnViewHolder( null );
|
||||
private final View btnSearch;
|
||||
private final EditText etSearch;
|
||||
private final CheckBox cbResolve;
|
||||
private final EditText etRegexFilter;
|
||||
private final TextView tvRegexFilterError;
|
||||
|
||||
closeBitmaps();
|
||||
private final ImageButton btnColumnSetting;
|
||||
private final ImageButton btnColumnReload;
|
||||
private final ImageButton btnColumnClose;
|
||||
|
||||
activity.closeListItemPopup();
|
||||
private final View flColumnBackground;
|
||||
private final ImageView ivColumnBackgroundImage;
|
||||
private final View llSearch;
|
||||
private final CheckBox cbDontCloseColumn;
|
||||
private final CheckBox cbWithAttachment;
|
||||
private final CheckBox cbDontShowBoost;
|
||||
private final CheckBox cbDontShowReply;
|
||||
private final CheckBox cbDontStreaming;
|
||||
private final CheckBox cbDontAutoRefresh;
|
||||
private final CheckBox cbHideMediaDefault;
|
||||
private final View llRegexFilter;
|
||||
private final Button btnDeleteNotification;
|
||||
|
||||
}
|
||||
|
||||
private TextView tvLoading;
|
||||
private MyListView listView;
|
||||
private TextView tvColumnContext;
|
||||
private TextView tvColumnName;
|
||||
private HeaderViewHolder vh_header;
|
||||
private SwipyRefreshLayout swipyRefreshLayout;
|
||||
private View btnSearch;
|
||||
private EditText etSearch;
|
||||
private CheckBox cbResolve;
|
||||
private View llColumnSetting;
|
||||
private EditText etRegexFilter;
|
||||
private TextView tvRegexFilterError;
|
||||
private ImageView ivColumnIcon;
|
||||
|
||||
private View llColumnHeader;
|
||||
private TextView tvColumnIndex;
|
||||
private ImageButton btnColumnSetting;
|
||||
private ImageButton btnColumnReload;
|
||||
private ImageButton btnColumnClose;
|
||||
|
||||
private View flColumnBackground;
|
||||
private ImageView ivColumnBackgroundImage;
|
||||
|
||||
void onPageCreate( View root, int page_idx, int page_count ){
|
||||
log.d( "onPageCreate:%s", column.getColumnName( true ) );
|
||||
ColumnViewHolder( ActMain arg_activity, View root ){
|
||||
this.activity = arg_activity;
|
||||
|
||||
flColumnBackground = root.findViewById( R.id.flColumnBackground );
|
||||
ivColumnBackgroundImage = (ImageView) root.findViewById( R.id.ivColumnBackgroundImage );
|
||||
llColumnHeader = root.findViewById( R.id.llColumnHeader );
|
||||
|
||||
tvColumnIndex = (TextView) root.findViewById( R.id.tvColumnIndex );
|
||||
tvColumnIndex.setText( activity.getString( R.string.column_index, page_idx + 1, page_count ) );
|
||||
|
||||
tvColumnName = (TextView) root.findViewById( R.id.tvColumnName );
|
||||
tvColumnContext = (TextView) root.findViewById( R.id.tvColumnContext );
|
||||
|
@ -107,207 +96,224 @@ class ColumnViewHolder
|
|||
btnColumnReload = (ImageButton) root.findViewById( R.id.btnColumnReload );
|
||||
btnColumnClose = (ImageButton) root.findViewById( R.id.btnColumnClose );
|
||||
|
||||
tvLoading = (TextView) root.findViewById( R.id.tvLoading );
|
||||
listView = (MyListView) root.findViewById( R.id.listView );
|
||||
|
||||
btnSearch = root.findViewById( R.id.btnSearch );
|
||||
etSearch = (EditText) root.findViewById( R.id.etSearch );
|
||||
cbResolve = (CheckBox) root.findViewById( R.id.cbResolve );
|
||||
|
||||
llSearch = root.findViewById( R.id.llSearch );
|
||||
|
||||
llColumnSetting = root.findViewById( R.id.llColumnSetting );
|
||||
|
||||
cbDontCloseColumn = (CheckBox) root.findViewById( R.id.cbDontCloseColumn );
|
||||
cbWithAttachment = (CheckBox) root.findViewById( R.id.cbWithAttachment );
|
||||
cbDontShowBoost = (CheckBox) root.findViewById( R.id.cbDontShowBoost );
|
||||
cbDontShowReply = (CheckBox) root.findViewById( R.id.cbDontShowReply );
|
||||
cbDontStreaming = (CheckBox) root.findViewById( R.id.cbDontStreaming );
|
||||
cbDontAutoRefresh = (CheckBox) root.findViewById( R.id.cbDontAutoRefresh );
|
||||
cbHideMediaDefault = (CheckBox) root.findViewById( R.id.cbHideMediaDefault );
|
||||
etRegexFilter = (EditText) root.findViewById( R.id.etRegexFilter );
|
||||
llRegexFilter = root.findViewById( R.id.llRegexFilter );
|
||||
tvRegexFilterError = (TextView) root.findViewById( R.id.tvRegexFilterError );
|
||||
listView.setOnItemClickListener( status_adapter );
|
||||
|
||||
btnDeleteNotification = (Button) root.findViewById( R.id.btnDeleteNotification );
|
||||
|
||||
llColumnHeader.setOnClickListener( this );
|
||||
btnColumnSetting.setOnClickListener( this );
|
||||
btnColumnReload.setOnClickListener( this );
|
||||
btnColumnClose.setOnClickListener( this );
|
||||
|
||||
llColumnHeader.setOnClickListener( this );
|
||||
btnDeleteNotification.setOnClickListener( this );
|
||||
|
||||
root.findViewById( R.id.btnColor ).setOnClickListener( this );
|
||||
|
||||
tvLoading = (TextView) root.findViewById( R.id.tvLoading );
|
||||
listView = (MyListView) root.findViewById( R.id.listView );
|
||||
listView.setAdapter( null );
|
||||
if( column.column_type == Column.TYPE_PROFILE ){
|
||||
vh_header = new HeaderViewHolder( activity, column, listView );
|
||||
status_adapter.header = vh_header;
|
||||
}else{
|
||||
status_adapter.header = null;
|
||||
}
|
||||
listView.setAdapter( status_adapter );
|
||||
|
||||
this.swipyRefreshLayout = (SwipyRefreshLayout) root.findViewById( R.id.swipyRefreshLayout );
|
||||
swipyRefreshLayout.setOnRefreshListener( this );
|
||||
swipyRefreshLayout.setDistanceToTriggerSync( (int) ( 0.5f + 20f * activity.density ) );
|
||||
|
||||
View llSearch = root.findViewById( R.id.llSearch );
|
||||
btnSearch = root.findViewById( R.id.btnSearch );
|
||||
etSearch = (EditText) root.findViewById( R.id.etSearch );
|
||||
cbResolve = (CheckBox) root.findViewById( R.id.cbResolve );
|
||||
cbDontCloseColumn.setOnCheckedChangeListener( this );
|
||||
cbWithAttachment.setOnCheckedChangeListener( this );
|
||||
cbDontShowBoost.setOnCheckedChangeListener( this );
|
||||
cbDontShowReply.setOnCheckedChangeListener( this );
|
||||
cbDontStreaming.setOnCheckedChangeListener( this );
|
||||
cbDontAutoRefresh.setOnCheckedChangeListener( this );
|
||||
cbHideMediaDefault.setOnCheckedChangeListener( this );
|
||||
|
||||
listView.setFastScrollEnabled( ! Pref.pref( activity ).getBoolean( Pref.KEY_DISABLE_FAST_SCROLLER, true ) );
|
||||
// 入力の追跡
|
||||
etRegexFilter.addTextChangedListener( new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged( CharSequence s, int start, int count, int after ){
|
||||
}
|
||||
|
||||
boolean bAllowFilter;
|
||||
switch( column.column_type ){
|
||||
default:
|
||||
bAllowFilter = true;
|
||||
break;
|
||||
case Column.TYPE_SEARCH:
|
||||
case Column.TYPE_CONVERSATION:
|
||||
case Column.TYPE_REPORTS:
|
||||
case Column.TYPE_BLOCKS:
|
||||
case Column.TYPE_MUTES:
|
||||
case Column.TYPE_FOLLOW_REQUESTS:
|
||||
case Column.TYPE_NOTIFICATIONS:
|
||||
bAllowFilter = false;
|
||||
break;
|
||||
}
|
||||
@Override
|
||||
public void onTextChanged( CharSequence s, int start, int before, int count ){
|
||||
}
|
||||
|
||||
boolean bAllowFilterBoost;
|
||||
switch( column.column_type ){
|
||||
default:
|
||||
bAllowFilterBoost = false;
|
||||
break;
|
||||
case Column.TYPE_HOME:
|
||||
case Column.TYPE_PROFILE:
|
||||
bAllowFilterBoost = true;
|
||||
break;
|
||||
}
|
||||
|
||||
llColumnSetting = root.findViewById( R.id.llColumnSetting );
|
||||
llColumnSetting.setVisibility( View.GONE );
|
||||
|
||||
CheckBox cb;
|
||||
cb = (CheckBox) root.findViewById( R.id.cbDontCloseColumn );
|
||||
cb.setChecked( column.dont_close );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
|
||||
cb = (CheckBox) root.findViewById( R.id.cbWithAttachment );
|
||||
cb.setChecked( column.with_attachment );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
cb.setEnabled( bAllowFilter );
|
||||
cb.setVisibility( bAllowFilter ? View.VISIBLE : View.GONE );
|
||||
|
||||
cb = (CheckBox) root.findViewById( R.id.cbDontShowBoost );
|
||||
cb.setChecked( column.dont_show_boost );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
cb.setEnabled( bAllowFilter );
|
||||
cb.setVisibility( bAllowFilterBoost ? View.VISIBLE : View.GONE );
|
||||
|
||||
cb = (CheckBox) root.findViewById( R.id.cbDontShowReply );
|
||||
cb.setChecked( column.dont_show_reply );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
cb.setEnabled( bAllowFilter );
|
||||
cb.setVisibility( bAllowFilterBoost ? View.VISIBLE : View.GONE );
|
||||
|
||||
cb = (CheckBox) root.findViewById( R.id.cbDontStreaming );
|
||||
if( ! column.canStreaming() ){
|
||||
cb.setVisibility( View.GONE );
|
||||
}else{
|
||||
cb.setVisibility( View.VISIBLE );
|
||||
cb.setChecked( column.dont_streaming );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
}
|
||||
|
||||
cb = (CheckBox) root.findViewById( R.id.cbDontAutoRefresh );
|
||||
if( ! column.canAutoRefresh() ){
|
||||
cb.setVisibility( View.GONE );
|
||||
}else{
|
||||
cb.setVisibility(View.VISIBLE );
|
||||
cb.setChecked( column.dont_auto_refresh );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
}
|
||||
|
||||
cb = (CheckBox) root.findViewById( R.id.cbHideMediaDefault );
|
||||
if( ! column.canShowMedia() ){
|
||||
cb.setVisibility( View.GONE );
|
||||
}else{
|
||||
cb.setVisibility(View.VISIBLE );
|
||||
cb.setChecked( column.hide_media_default );
|
||||
cb.setOnCheckedChangeListener( this );
|
||||
}
|
||||
|
||||
etRegexFilter = (EditText) root.findViewById( R.id.etRegexFilter );
|
||||
if( ! bAllowFilter ){
|
||||
etRegexFilter.setVisibility( View.GONE );
|
||||
root.findViewById( R.id.llRegexFilter ).setVisibility( View.GONE );
|
||||
}else{
|
||||
etRegexFilter.setText( column.regex_text );
|
||||
// tvRegexFilterErrorの表示を更新
|
||||
tvRegexFilterError = (TextView) root.findViewById( R.id.tvRegexFilterError );
|
||||
isRegexValid();
|
||||
// 入力の追跡
|
||||
etRegexFilter.addTextChangedListener( new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged( CharSequence s, int start, int count, int after ){
|
||||
@Override public void afterTextChanged( Editable s ){
|
||||
if( loading_busy ) return;
|
||||
activity.handler.removeCallbacks( proc_start_filter );
|
||||
if( isRegexValid() ){
|
||||
activity.handler.postDelayed( proc_start_filter, 1500L );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
@Override
|
||||
public void onTextChanged( CharSequence s, int start, int before, int count ){
|
||||
}
|
||||
|
||||
@Override public void afterTextChanged( Editable s ){
|
||||
activity.handler.removeCallbacks( proc_start_filter );
|
||||
if( isRegexValid() ){
|
||||
activity.handler.postDelayed( proc_start_filter, 1500L );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
Button button = (Button) root.findViewById( R.id.btnDeleteNotification );
|
||||
if( column.column_type != Column.TYPE_NOTIFICATIONS ){
|
||||
button.setVisibility( View.GONE );
|
||||
}else{
|
||||
button.setVisibility( View.VISIBLE );
|
||||
button.setOnClickListener( this );
|
||||
|
||||
}
|
||||
|
||||
if( column.column_type != Column.TYPE_SEARCH ){
|
||||
llSearch.setVisibility( View.GONE );
|
||||
}else{
|
||||
llSearch.setVisibility( View.VISIBLE );
|
||||
etSearch.setText( column.search_query );
|
||||
cbResolve.setChecked( column.search_resolve );
|
||||
btnSearch.setOnClickListener( this );
|
||||
etSearch.setOnEditorActionListener( new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction( TextView v, int actionId, KeyEvent event ){
|
||||
btnSearch.setOnClickListener( this );
|
||||
etSearch.setOnEditorActionListener( new TextView.OnEditorActionListener() {
|
||||
@Override public boolean onEditorAction( TextView v, int actionId, KeyEvent event ){
|
||||
if( !loading_busy ){
|
||||
if( actionId == EditorInfo.IME_ACTION_SEARCH ){
|
||||
btnSearch.performClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} );
|
||||
return false;
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
private boolean isPageDestroyed(){
|
||||
return column ==null || activity.isFinishing();
|
||||
}
|
||||
|
||||
void onPageDestroy(){
|
||||
// タブレットモードの場合、onPageCreateより前に呼ばれる
|
||||
|
||||
if( column != null ){
|
||||
log.d( "onPageDestroy #%s", tvColumnName.getText() );
|
||||
saveScrollPosition();
|
||||
listView.setAdapter( null );
|
||||
column.setColumnViewHolder( null );
|
||||
column = null;
|
||||
}
|
||||
|
||||
closeBitmaps();
|
||||
|
||||
activity.closeListItemPopup();
|
||||
}
|
||||
|
||||
switch( column.column_type ){
|
||||
case Column.TYPE_CONVERSATION:
|
||||
case Column.TYPE_SEARCH:
|
||||
swipyRefreshLayout.setEnabled( false );
|
||||
break;
|
||||
default:
|
||||
swipyRefreshLayout.setEnabled( true );
|
||||
break;
|
||||
private static void vg( View v, boolean visible ){
|
||||
v.setVisibility( visible ? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
private boolean loading_busy;
|
||||
|
||||
void onPageCreate( Column column, int page_idx, int page_count ){
|
||||
loading_busy = true;
|
||||
try{
|
||||
this.column = column;
|
||||
|
||||
log.d( "onPageCreate:%s", column.getColumnName( true ) );
|
||||
|
||||
tvColumnIndex.setText( activity.getString( R.string.column_index, page_idx + 1, page_count ) );
|
||||
|
||||
listView.setAdapter( null );
|
||||
|
||||
this.status_adapter = new ItemListAdapter( activity, column );
|
||||
if( column.column_type == Column.TYPE_PROFILE ){
|
||||
vh_header = new HeaderViewHolder( activity, column, listView );
|
||||
status_adapter.header = vh_header;
|
||||
}else{
|
||||
status_adapter.header = null;
|
||||
}
|
||||
|
||||
boolean bAllowFilter;
|
||||
switch( column.column_type ){
|
||||
default:
|
||||
bAllowFilter = true;
|
||||
break;
|
||||
case Column.TYPE_SEARCH:
|
||||
case Column.TYPE_CONVERSATION:
|
||||
case Column.TYPE_REPORTS:
|
||||
case Column.TYPE_BLOCKS:
|
||||
case Column.TYPE_MUTES:
|
||||
case Column.TYPE_FOLLOW_REQUESTS:
|
||||
case Column.TYPE_NOTIFICATIONS:
|
||||
bAllowFilter = false;
|
||||
break;
|
||||
}
|
||||
|
||||
boolean bAllowFilterBoost;
|
||||
switch( column.column_type ){
|
||||
default:
|
||||
bAllowFilterBoost = false;
|
||||
break;
|
||||
case Column.TYPE_HOME:
|
||||
case Column.TYPE_PROFILE:
|
||||
bAllowFilterBoost = true;
|
||||
break;
|
||||
}
|
||||
|
||||
llColumnSetting.setVisibility( View.GONE );
|
||||
|
||||
cbDontCloseColumn.setChecked( column.dont_close );
|
||||
cbWithAttachment.setChecked( column.with_attachment );
|
||||
cbDontShowBoost.setChecked( column.dont_show_boost );
|
||||
cbDontShowReply.setChecked( column.dont_show_reply );
|
||||
cbDontStreaming.setChecked( column.dont_streaming );
|
||||
cbDontAutoRefresh.setChecked( column.dont_auto_refresh );
|
||||
cbHideMediaDefault.setChecked( column.hide_media_default );
|
||||
|
||||
etRegexFilter.setText( column.regex_text );
|
||||
etSearch.setText( column.search_query );
|
||||
cbResolve.setChecked( column.search_resolve );
|
||||
|
||||
vg( cbWithAttachment, bAllowFilter );
|
||||
vg( cbDontShowBoost, bAllowFilterBoost );
|
||||
vg( cbDontShowReply, bAllowFilterBoost );
|
||||
vg( cbDontStreaming, column.canStreaming() );
|
||||
vg( cbDontAutoRefresh, column.canAutoRefresh() );
|
||||
vg( cbHideMediaDefault, column.canShowMedia() );
|
||||
|
||||
vg( etRegexFilter, bAllowFilter );
|
||||
vg( llRegexFilter, bAllowFilter );
|
||||
|
||||
vg( btnDeleteNotification, column.column_type == Column.TYPE_NOTIFICATIONS );
|
||||
vg( llSearch, column.column_type == Column.TYPE_SEARCH );
|
||||
|
||||
// tvRegexFilterErrorの表示を更新
|
||||
if( bAllowFilter ){
|
||||
isRegexValid();
|
||||
}
|
||||
|
||||
switch( column.column_type ){
|
||||
case Column.TYPE_CONVERSATION:
|
||||
case Column.TYPE_SEARCH:
|
||||
swipyRefreshLayout.setEnabled( false );
|
||||
break;
|
||||
default:
|
||||
swipyRefreshLayout.setEnabled( true );
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
listView.setAdapter( status_adapter );
|
||||
listView.setFastScrollEnabled( ! Pref.pref( activity ).getBoolean( Pref.KEY_DISABLE_FAST_SCROLLER, true ) );
|
||||
|
||||
column.setColumnViewHolder( this );
|
||||
|
||||
showColumnColor();
|
||||
|
||||
showContent();
|
||||
}finally{
|
||||
loading_busy = false;
|
||||
}
|
||||
|
||||
if( column.bSimpleList ){
|
||||
listView.setOnItemClickListener( status_adapter );
|
||||
}else{
|
||||
listView.setOnItemClickListener( null );
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
column.setColumnViewHolder( this );
|
||||
|
||||
showColumnColor();
|
||||
|
||||
showContent();
|
||||
}
|
||||
|
||||
void showColumnColor(){
|
||||
if( column == null ) return;
|
||||
|
||||
int c = column.header_bg_color;
|
||||
if( c == 0 ){
|
||||
llColumnHeader.setBackgroundResource( R.drawable.btn_bg_ddd );
|
||||
}else{
|
||||
ViewCompat.setBackground( llColumnHeader,Styler.getAdaptiveRippleDrawable(
|
||||
ViewCompat.setBackground( llColumnHeader, Styler.getAdaptiveRippleDrawable(
|
||||
c,
|
||||
(column.header_fg_color != 0 ? column.header_fg_color :
|
||||
Styler.getAttributeColor( activity,R.attr.colorRippleEffect ))
|
||||
( column.header_fg_color != 0 ? column.header_fg_color :
|
||||
Styler.getAttributeColor( activity, R.attr.colorRippleEffect ) )
|
||||
) );
|
||||
}
|
||||
|
||||
|
@ -393,6 +399,8 @@ class ColumnViewHolder
|
|||
private final Runnable proc_start_filter = new Runnable() {
|
||||
@Override public void run(){
|
||||
if( isPageDestroyed() ) return;
|
||||
if( column == null ) return;
|
||||
|
||||
if( isRegexValid() ){
|
||||
column.regex_text = etRegexFilter.getText().toString();
|
||||
activity.app_state.saveColumnList();
|
||||
|
@ -430,10 +438,13 @@ class ColumnViewHolder
|
|||
}
|
||||
|
||||
@Override public void onRefresh( SwipyRefreshLayoutDirection direction ){
|
||||
if( column == null ) return;
|
||||
column.startRefresh( false, direction == SwipyRefreshLayoutDirection.BOTTOM, - 1L, - 1 );
|
||||
}
|
||||
|
||||
@Override public void onCheckedChanged( CompoundButton view, boolean isChecked ){
|
||||
if( loading_busy || column ==null || status_adapter ==null ) return;
|
||||
|
||||
switch( view.getId() ){
|
||||
|
||||
case R.id.cbDontCloseColumn:
|
||||
|
@ -454,7 +465,6 @@ class ColumnViewHolder
|
|||
column.startLoading();
|
||||
break;
|
||||
|
||||
|
||||
case R.id.cbDontShowReply:
|
||||
column.dont_show_reply = isChecked;
|
||||
activity.app_state.saveColumnList();
|
||||
|
@ -487,6 +497,8 @@ class ColumnViewHolder
|
|||
|
||||
@Override
|
||||
public void onClick( View v ){
|
||||
if( loading_busy || column ==null || status_adapter ==null ) return;
|
||||
|
||||
switch( v.getId() ){
|
||||
case R.id.btnColumnClose:
|
||||
activity.closeColumn( false, column );
|
||||
|
@ -535,13 +547,10 @@ class ColumnViewHolder
|
|||
|
||||
swipyRefreshLayout.setVisibility( View.GONE );
|
||||
|
||||
// ロード完了後に先頭から表示させる
|
||||
if( status_adapter.getCount() > 0 ){
|
||||
listView.setSelectionFromTop( 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
private void showColumnCloseButton(){
|
||||
if( column == null ) return;
|
||||
// カラム保護の状態
|
||||
btnColumnClose.setEnabled( ! column.dont_close );
|
||||
btnColumnClose.setAlpha( column.dont_close ? 0.3f : 1f );
|
||||
|
@ -564,6 +573,7 @@ class ColumnViewHolder
|
|||
|
||||
// カラムヘッダなど、負荷が低い部分の表示更新
|
||||
void showColumnHeader(){
|
||||
if( column == null ) return;
|
||||
|
||||
String acct = column.access_info.acct;
|
||||
AcctColor ac = AcctColor.load( acct );
|
||||
|
@ -592,14 +602,14 @@ class ColumnViewHolder
|
|||
// クラッシュレポートにadapterとリストデータの状態不整合が多かったので、
|
||||
// とりあえずリストデータ変更の通知だけは最優先で行っておく
|
||||
try{
|
||||
status_adapter.notifyDataSetChanged();
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace( );
|
||||
if( status_adapter != null ) status_adapter.notifyDataSetChanged();
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
showColumnHeader();
|
||||
|
||||
if( column.is_dispose.get() ){
|
||||
if( column == null || column.is_dispose.get() ){
|
||||
showError( "column was disposed." );
|
||||
return;
|
||||
}
|
||||
|
@ -645,8 +655,11 @@ class ColumnViewHolder
|
|||
}
|
||||
|
||||
private void restoreScrollPosition(){
|
||||
if( column == null ) return;
|
||||
|
||||
ScrollPosition sp = column.scroll_save;
|
||||
if( sp == null ) return;
|
||||
|
||||
column.scroll_save = null;
|
||||
|
||||
if( listView.getVisibility() == View.VISIBLE ){
|
||||
|
@ -656,11 +669,12 @@ class ColumnViewHolder
|
|||
}
|
||||
|
||||
private void saveScrollPosition(){
|
||||
|
||||
if( listView.getVisibility() == View.VISIBLE ){
|
||||
column.scroll_save = new ScrollPosition( listView );
|
||||
}else{
|
||||
column.scroll_save = new ScrollPosition( 0, 0 );
|
||||
if( column != null && ! column.is_dispose.get() ){
|
||||
if( listView.getVisibility() == View.VISIBLE ){
|
||||
column.scroll_save = new ScrollPosition( listView );
|
||||
}else{
|
||||
column.scroll_save = new ScrollPosition( 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,14 +683,16 @@ class ColumnViewHolder
|
|||
}
|
||||
|
||||
void setScrollPosition( @NonNull ScrollPosition sp, final float delta ){
|
||||
final ListAdapter last_adapter = listView.getAdapter();
|
||||
if( column == null || last_adapter == null ) return;
|
||||
|
||||
sp.restore( listView );
|
||||
|
||||
listView.postDelayed( new Runnable() {
|
||||
@Override public void run(){
|
||||
if( isPageDestroyed() ) return;
|
||||
if( column == null || listView.getAdapter() != last_adapter ) return;
|
||||
listView.scrollListBy( (int) ( delta * activity.density ) );
|
||||
}
|
||||
}, 20L );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
|||
View btnText = viewRoot.findViewById( R.id.btnText );
|
||||
View btnFavouriteAnotherAccount = viewRoot.findViewById( R.id.btnFavouriteAnotherAccount );
|
||||
View btnBoostAnotherAccount = viewRoot.findViewById( R.id.btnBoostAnotherAccount );
|
||||
View btnReplyAnotherAccount = viewRoot.findViewById( R.id.btnReplyAnotherAccount );
|
||||
View btnDelete = viewRoot.findViewById( R.id.btnDelete );
|
||||
View btnReport = viewRoot.findViewById( R.id.btnReport );
|
||||
Button btnMuteApp = (Button) viewRoot.findViewById( R.id.btnMuteApp );
|
||||
|
@ -105,9 +106,11 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
|||
if( account_list_non_pseudo_same_instance.isEmpty() ){
|
||||
btnFavouriteAnotherAccount.setVisibility( View.GONE );
|
||||
btnBoostAnotherAccount.setVisibility( View.GONE );
|
||||
btnReplyAnotherAccount.setVisibility( View.GONE );
|
||||
}else{
|
||||
btnFavouriteAnotherAccount.setOnClickListener( this );
|
||||
btnBoostAnotherAccount.setOnClickListener( this );
|
||||
btnReplyAnotherAccount.setOnClickListener( this );
|
||||
}
|
||||
if( access_info.isPseudo() ){
|
||||
btnDelete.setVisibility( View.GONE );
|
||||
|
@ -254,44 +257,15 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
|||
break;
|
||||
|
||||
case R.id.btnFavouriteAnotherAccount:
|
||||
if( status != null ){
|
||||
AccountPicker.pick( activity, false, false
|
||||
, activity.getString( R.string.account_picker_favourite )
|
||||
// , account_list_non_pseudo_same_instance
|
||||
, account_list_non_pseudo
|
||||
, new AccountPicker.AccountPickerCallback() {
|
||||
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
|
||||
activity.performFavourite(
|
||||
ai
|
||||
, ! ai.host.equalsIgnoreCase( access_info.host )
|
||||
, true
|
||||
, status
|
||||
, activity.favourite_complete_callback
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
activity.openFavouriteFromAnotherAccount( access_info,status );
|
||||
break;
|
||||
|
||||
case R.id.btnBoostAnotherAccount:
|
||||
if( status != null ){
|
||||
AccountPicker.pick( activity, false, false
|
||||
, activity.getString( R.string.account_picker_boost )
|
||||
// , account_list_non_pseudo_same_instance
|
||||
, account_list_non_pseudo
|
||||
, new AccountPicker.AccountPickerCallback() {
|
||||
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
|
||||
activity.performBoost(
|
||||
ai
|
||||
, ! ai.host.equalsIgnoreCase( access_info.host )
|
||||
, true
|
||||
, status
|
||||
, false
|
||||
, activity.boost_complete_callback
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
activity.openBoostFromAnotherAccount( access_info,status );
|
||||
break;
|
||||
|
||||
case R.id.btnReplyAnotherAccount:
|
||||
activity.openReplyFromAnotherAccount( access_info,status );
|
||||
break;
|
||||
|
||||
case R.id.btnDelete:
|
||||
|
|
|
@ -78,9 +78,11 @@ class ItemListAdapter extends BaseAdapter implements AdapterView.OnItemClickList
|
|||
|
||||
@Override
|
||||
public void onItemClick( AdapterView< ? > parent, View view, int position, long id ){
|
||||
Object tag = view.getTag();
|
||||
if( tag instanceof ItemViewHolder ){
|
||||
( (ItemViewHolder) tag ).onItemClick( (MyListView) parent, view );
|
||||
if( column.bSimpleList ){
|
||||
Object tag = view.getTag();
|
||||
if( tag instanceof ItemViewHolder ){
|
||||
( (ItemViewHolder) tag ).onItemClick( (MyListView) parent, view );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
|||
//
|
||||
v = viewRoot.findViewById( R.id.btnReply );
|
||||
v.setOnClickListener( this );
|
||||
v.setOnLongClickListener( this );
|
||||
|
||||
}
|
||||
|
||||
|
@ -117,9 +118,9 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
|||
break;
|
||||
case R.id.btnReply:
|
||||
if( access_info.isPseudo() ){
|
||||
Utils.showToast( activity, false, R.string.not_available_for_pseudo_account );
|
||||
activity.openReplyFromAnotherAccount( access_info, status );
|
||||
}else{
|
||||
activity.performReply( access_info, status );
|
||||
activity.performReply( access_info, status ,false);
|
||||
}
|
||||
break;
|
||||
case R.id.btnBoost:
|
||||
|
@ -184,6 +185,10 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
|||
activity.openFollowFromAnotherAccount( access_info, status );
|
||||
break;
|
||||
|
||||
case R.id.btnReply:
|
||||
activity.openReplyFromAnotherAccount( access_info, status );
|
||||
break;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class TabletColumnPagerAdapter extends RecyclerView.Adapter<TabletColumnViewHold
|
|||
@Override public TabletColumnViewHolder onCreateViewHolder( ViewGroup parent, int viewType ){
|
||||
View v = mLayoutInflater.inflate( R.layout.page_column, parent, false );
|
||||
|
||||
return new TabletColumnViewHolder( v );
|
||||
return new TabletColumnViewHolder( activity,v );
|
||||
}
|
||||
|
||||
@Override public void onBindViewHolder( TabletColumnViewHolder holder, int position ){
|
||||
|
@ -45,7 +45,7 @@ class TabletColumnPagerAdapter extends RecyclerView.Adapter<TabletColumnViewHold
|
|||
holder.itemView.setLayoutParams( lp );
|
||||
}
|
||||
|
||||
holder.bind( activity, column_list.get(position), position , column_list.size() );
|
||||
holder.bind( column_list.get(position), position , column_list.size() );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,26 +9,22 @@ class TabletColumnViewHolder extends RecyclerView.ViewHolder{
|
|||
static final LogCategory log = new LogCategory( "TabletColumnViewHolder" );
|
||||
|
||||
|
||||
ColumnViewHolder vh;
|
||||
private int old_position;
|
||||
final ColumnViewHolder vh;
|
||||
|
||||
TabletColumnViewHolder( View v ){
|
||||
private int old_position = -1;
|
||||
|
||||
TabletColumnViewHolder( ActMain activity, View v ){
|
||||
super( v );
|
||||
|
||||
vh =new ColumnViewHolder( activity ,v);
|
||||
v.findViewById( R.id.vTabletDivider ).setVisibility( View.VISIBLE );
|
||||
}
|
||||
|
||||
void bind( ActMain activity, Column column,int position,int column_count ){
|
||||
if( vh != null ){
|
||||
log.d("destroy #%s",old_position);
|
||||
vh.onPageDestroy( itemView );
|
||||
vh = null;
|
||||
}
|
||||
void bind(Column column,int position,int column_count ){
|
||||
log.d("bind. %d => %d ",old_position,position);
|
||||
|
||||
old_position = position;
|
||||
log.d("create #%s",position);
|
||||
vh =new ColumnViewHolder( activity, column);
|
||||
vh.onPageCreate( itemView,position,column_count );
|
||||
vh.onPageDestroy();
|
||||
|
||||
vh.onPageCreate( column, position,column_count );
|
||||
|
||||
if( ! column.bFirstInitialized ){
|
||||
column.startLoading();
|
||||
|
|
|
@ -67,7 +67,7 @@ public class TootApiResult {
|
|||
while( m.find()){
|
||||
String url = m.group(1);
|
||||
String rel = m.group(2);
|
||||
log.d("Link %s,%s",rel,url);
|
||||
// log.d("Link %s,%s",rel,url);
|
||||
if( "next".equals( rel )) link_older = url;
|
||||
if( "prev".equals( rel )) link_newer = url;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ import org.json.JSONObject;
|
|||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
@ -138,7 +140,7 @@ public class TootStatus extends TootId {
|
|||
status.media_attachments = TootAttachment.parseList( log, src.optJSONArray( "media_attachments" ) );
|
||||
status.mentions = TootMention.parseList( log, src.optJSONArray( "mentions" ) );
|
||||
status.tags = TootTag.parseList( log, src.optJSONArray( "tags" ) );
|
||||
status.application = TootApplication.parse( log,src.optJSONObject( "application" )); // null
|
||||
status.application = TootApplication.parse( log, src.optJSONObject( "application" ) ); // null
|
||||
|
||||
status.time_created_at = parseTime( log, status.created_at );
|
||||
status.decoded_content = HTMLDecoder.decodeHTML( account, status.content );
|
||||
|
@ -172,22 +174,32 @@ public class TootStatus extends TootId {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static final Pattern reTime = Pattern.compile("\\A(\\d+\\D+\\d+\\D+\\d+\\D+\\d+\\D+\\d+\\D+\\d+\\D+\\d+)");
|
||||
private static final SimpleDateFormat date_format_utc = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault() );
|
||||
private static final Pattern reTime = Pattern.compile( "\\A(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)" );
|
||||
|
||||
private static final TimeZone tz_utc = TimeZone.getTimeZone( "UTC" );
|
||||
|
||||
static long parseTime( LogCategory log, String strTime ){
|
||||
if( ! TextUtils.isEmpty( strTime ) ){
|
||||
try{
|
||||
Matcher m = reTime.matcher( strTime );
|
||||
if(!m.find() ){
|
||||
log.d("!!invalid time format: %s",strTime);
|
||||
if( ! m.find() ){
|
||||
log.d( "!!invalid time format: %s", strTime );
|
||||
}else{
|
||||
date_format_utc.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
|
||||
return date_format_utc.parse( m.group( 1 ) ).getTime();
|
||||
GregorianCalendar g = new GregorianCalendar( tz_utc );
|
||||
g.set(
|
||||
Utils.parse_int( m.group( 1 ), 1 ),
|
||||
Utils.parse_int( m.group( 2 ), 1 ) - 1,
|
||||
Utils.parse_int( m.group( 3 ), 1 ),
|
||||
Utils.parse_int( m.group( 4 ), 0 ),
|
||||
Utils.parse_int( m.group( 5 ), 0 ),
|
||||
Utils.parse_int( m.group( 6 ), 0 )
|
||||
);
|
||||
g.set( Calendar.MILLISECOND, Utils.parse_int( m.group( 7 ), 0 ) );
|
||||
return g.getTimeInMillis();
|
||||
}
|
||||
}catch( Throwable ex ){// ParseException, ArrayIndexOutOfBoundsException
|
||||
}catch( Throwable ex ){// ParseException, ArrayIndexOutOfBoundsException
|
||||
ex.printStackTrace();
|
||||
log.e( ex, "TootStatus.parseTime failed. src=%s",strTime );
|
||||
log.e( ex, "TootStatus.parseTime failed. src=%s", strTime );
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
|
@ -230,7 +242,6 @@ public class TootStatus extends TootId {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean checkMuted( HashSet< String > muted_app, HashSet< String > muted_word ){
|
||||
|
||||
// app mute
|
||||
|
@ -244,7 +255,7 @@ public class TootStatus extends TootId {
|
|||
}
|
||||
|
||||
// word mute
|
||||
for( String word: muted_word ){
|
||||
for( String word : muted_word ){
|
||||
if( decoded_content != null && decoded_content.toString().contains( word ) ){
|
||||
return true;
|
||||
}
|
||||
|
@ -255,7 +266,7 @@ public class TootStatus extends TootId {
|
|||
|
||||
// reblog
|
||||
//noinspection RedundantIfStatement
|
||||
if( reblog != null && reblog.checkMuted( muted_app,muted_word ) ){
|
||||
if( reblog != null && reblog.checkMuted( muted_app, muted_word ) ){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -263,5 +274,4 @@ public class TootStatus extends TootId {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -886,6 +886,10 @@ public class Utils {
|
|||
return resources.getString( string_id, args ) + String.format( " :%s %s", ex.getClass().getSimpleName(), ex.getMessage() );
|
||||
}
|
||||
|
||||
public static boolean isMainThread( ){
|
||||
return Looper.getMainLooper().getThread() == Thread.currentThread();
|
||||
}
|
||||
|
||||
public static void runOnMainThread( @NonNull Runnable proc ){
|
||||
if( Looper.getMainLooper().getThread() == Thread.currentThread() ){
|
||||
proc.run();
|
||||
|
|
|
@ -133,7 +133,20 @@
|
|||
android:text="@string/boost_from_another_account"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnReplyAnotherAccount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_bg_transparent"
|
||||
android:gravity="start|center_vertical"
|
||||
android:minHeight="32dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:text="@string/reply_from_another_account"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/btnDelete"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="MissingTranslation"
|
||||
>
|
||||
|
||||
<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>
|
||||
<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>
|
||||
<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>
|
||||
|
@ -332,4 +333,5 @@
|
|||
<string name="with_attachment">Avec pièce(s) jointe(s)</string>
|
||||
<string name="word_was_muted">Ce mot a été interdit.</string>
|
||||
<string name="your_statuses">Vos statuts</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -476,11 +476,11 @@
|
|||
<!---->
|
||||
<string name="confirm_follow_request_who_from">%2$s から鍵付きユーザ %1$s にフォローリクエストを送りますか?</string>
|
||||
<!---->
|
||||
<string name="confirm_follow_who_from">%2$s から %1$s をフォローしますか?</string>
|
||||
<string name="confirm_follow_who_from">%2$s で %1$s をフォローしますか?</string>
|
||||
<!---->
|
||||
<string name="confirm_post_from">%1$s から投稿します。よろしいですか?</string>
|
||||
<!---->
|
||||
<string name="confirm_unfollow_who_from">%2$s から %1$s をフォロー解除しますか?</string>
|
||||
<string name="confirm_unfollow_who_from">%2$s で %1$s をフォロー解除しますか?</string>
|
||||
<!---->
|
||||
<string name="dont_confirm_again">次回から確認しない</string>
|
||||
<!---->
|
||||
|
@ -599,4 +599,6 @@
|
|||
<string name="disable_tablet_mode">タブレットモードを使わない(アプリ再起動が必要)</string>
|
||||
<string name="media_thumbnail_height">添付メディアのサムネイルの高さ(デフォルト=64(dp)、アプリ再起動が必要)</string>
|
||||
<string name="minimum_column_width">カラム最小幅(デフォルト=300(dp)、アプリ再起動が必要)</string>
|
||||
<string name="account_picker_reply">どのアカウントで返信しますか?</string>
|
||||
<string name="reply_from_another_account">別アカウントで返信</string>
|
||||
</resources>
|
|
@ -309,4 +309,6 @@
|
|||
<string name="disable_tablet_mode">Disable tablet mode (app restart required)</string>
|
||||
<string name="minimum_column_width">Minimum column width (default=300(dp),app restart required)</string>
|
||||
<string name="media_thumbnail_height">Media Thumbnail height (default=64(dp), app restart required)</string>
|
||||
<string name="account_picker_reply">Which account do you reply from?</string>
|
||||
<string name="reply_from_another_account">Reply from another account</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue