「別アカウントでお気に入り/ブースト/返信/フォロー/プロフ/メッセージ」のアカウント選択ダイアログで同タンスのアカウントを先頭に表示する

This commit is contained in:
tateisu 2017-09-15 03:28:55 +09:00
parent 6831d31664
commit 57e17a41cf
6 changed files with 178 additions and 140 deletions

View File

@ -9,8 +9,8 @@ android {
applicationId "jp.juggler.subwaytooter" applicationId "jp.juggler.subwaytooter"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 26
versionCode 150 versionCode 151
versionName "1.5.0" versionName "1.5.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }

View File

@ -181,7 +181,7 @@ public class ActMain extends AppCompatActivity
static final String STATE_CURRENT_PAGE = "current_page"; static final String STATE_CURRENT_PAGE = "current_page";
@Override protected void onSaveInstanceState( Bundle outState ){ @Override protected void onSaveInstanceState( Bundle outState ){
log.d("onSaveInstanceState"); log.d( "onSaveInstanceState" );
super.onSaveInstanceState( outState ); super.onSaveInstanceState( outState );
if( pager_adapter != null ){ if( pager_adapter != null ){
@ -195,7 +195,7 @@ public class ActMain extends AppCompatActivity
} }
@Override protected void onRestoreInstanceState( Bundle savedInstanceState ){ @Override protected void onRestoreInstanceState( Bundle savedInstanceState ){
log.d("onRestoreInstanceState"); log.d( "onRestoreInstanceState" );
super.onRestoreInstanceState( 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( pos > 0 && pos < app_state.column_list.size() ){
@ -215,7 +215,7 @@ public class ActMain extends AppCompatActivity
@Override protected void onStart(){ @Override protected void onStart(){
super.onStart(); super.onStart();
bStart = true; bStart = true;
log.d( "onStart" ); log.d( "onStart" );
@ -229,16 +229,15 @@ public class ActMain extends AppCompatActivity
SavedAccount sa = SavedAccount.loadAccount( ActMain.this, log, column.access_info.db_id ); SavedAccount sa = SavedAccount.loadAccount( ActMain.this, log, column.access_info.db_id );
if( sa == null ) continue; if( sa == null ) continue;
} }
new_order.add( i ); new_order.add( i );
} }
if( new_order.size() != app_state.column_list.size() ){ if( new_order.size() != app_state.column_list.size() ){
setOrder( new_order ); setOrder( new_order );
} }
} }
// 各カラムのアカウント設定を読み直す // 各カラムのアカウント設定を読み直す
reloadAccountSetting(); reloadAccountSetting();
@ -250,20 +249,18 @@ public class ActMain extends AppCompatActivity
column.onStart( this ); column.onStart( this );
} }
// カラムの表示範囲インジケータを更新 // カラムの表示範囲インジケータを更新
updateColumnStripSelection( - 1, - 1f ); updateColumnStripSelection( - 1, - 1f );
// 相対時刻表示 // 相対時刻表示
proc_updateRelativeTime.run(); proc_updateRelativeTime.run();
} }
@Override protected void onStop(){ @Override protected void onStop(){
log.d( "onStop" ); log.d( "onStop" );
bStart = false; bStart = false;
handler.removeCallbacks( proc_updateRelativeTime ); handler.removeCallbacks( proc_updateRelativeTime );
@ -275,7 +272,7 @@ public class ActMain extends AppCompatActivity
app_state.stream_reader.stopAll(); app_state.stream_reader.stopAll();
super.onStop(); super.onStop();
} }
@Override protected void onResume(){ @Override protected void onResume(){
@ -316,7 +313,6 @@ public class ActMain extends AppCompatActivity
} }
pref.edit().putInt( Pref.KEY_LAST_COLUMN_POS, column_pos ).apply(); pref.edit().putInt( Pref.KEY_LAST_COLUMN_POS, column_pos ).apply();
super.onPause(); super.onPause();
} }
@ -371,8 +367,6 @@ public class ActMain extends AppCompatActivity
} }
} }
@Override public void onClick( View v ){ @Override public void onClick( View v ){
switch( v.getId() ){ switch( v.getId() ){
case R.id.btnMenu: case R.id.btnMenu:
@ -410,10 +404,9 @@ public class ActMain extends AppCompatActivity
} }
} }
post_helper.content = etQuickToot.getText().toString().trim(); post_helper.content = etQuickToot.getText().toString().trim();
post_helper.spoiler_text = null; post_helper.spoiler_text = null;
post_helper.visibility = account.visibility; post_helper.visibility = account.visibility;
post_helper.bNSFW = false; post_helper.bNSFW = false;
post_helper.in_reply_to_id = - 1L; post_helper.in_reply_to_id = - 1L;
post_helper.attachment_list = null; post_helper.attachment_list = null;
@ -802,7 +795,7 @@ public class ActMain extends AppCompatActivity
setContentView( R.layout.act_main ); setContentView( R.layout.act_main );
dont_crop_media_thumbnail = pref.getBoolean( Pref.KEY_DONT_CROP_MEDIA_THUMBNAIL, false ); dont_crop_media_thumbnail = pref.getBoolean( Pref.KEY_DONT_CROP_MEDIA_THUMBNAIL, false );
String sv = pref.getString( Pref.KEY_TIMELINE_FONT, null ); String sv = pref.getString( Pref.KEY_TIMELINE_FONT, null );
if( ! TextUtils.isEmpty( sv ) ){ if( ! TextUtils.isEmpty( sv ) ){
try{ try{
@ -821,13 +814,13 @@ public class ActMain extends AppCompatActivity
} }
}else if( timeline_font != null ){ }else if( timeline_font != null ){
try{ try{
timeline_font_bold = Typeface.create( timeline_font ,Typeface.BOLD ); timeline_font_bold = Typeface.create( timeline_font, Typeface.BOLD );
}catch( Throwable ex ){ }catch( Throwable ex ){
log.trace( ex ); log.trace( ex );
} }
} }
mShortAcctLocalUser = pref.getBoolean( Pref.KEY_SHORT_ACCT_LOCAL_USER ,false); mShortAcctLocalUser = pref.getBoolean( Pref.KEY_SHORT_ACCT_LOCAL_USER, false );
{ {
float icon_size_dp = 48f; float icon_size_dp = 48f;
@ -839,10 +832,10 @@ public class ActMain extends AppCompatActivity
}else{ }else{
icon_size_dp = fv; icon_size_dp = fv;
} }
}catch(Throwable ex){ }catch( Throwable ex ){
log.trace( ex ); log.trace( ex );
} }
mAvatarIconSize = (int)(0.5f + icon_size_dp * density ); mAvatarIconSize = (int) ( 0.5f + icon_size_dp * density );
} }
llEmpty = findViewById( R.id.llEmpty ); llEmpty = findViewById( R.id.llEmpty );
@ -884,8 +877,8 @@ public class ActMain extends AppCompatActivity
etQuickToot.setImeOptions( EditorInfo.IME_ACTION_NONE ); etQuickToot.setImeOptions( EditorInfo.IME_ACTION_NONE );
// 最後に指定する必要がある // 最後に指定する必要がある
etQuickToot.setMaxLines( 5 ); etQuickToot.setMaxLines( 5 );
etQuickToot.setVerticalScrollBarEnabled(true); etQuickToot.setVerticalScrollBarEnabled( true );
etQuickToot.setScrollbarFadingEnabled(false); etQuickToot.setScrollbarFadingEnabled( false );
}else{ }else{
etQuickToot.setInputType( InputType.TYPE_CLASS_TEXT ); etQuickToot.setInputType( InputType.TYPE_CLASS_TEXT );
etQuickToot.setImeOptions( EditorInfo.IME_ACTION_SEND ); etQuickToot.setImeOptions( EditorInfo.IME_ACTION_SEND );
@ -1252,7 +1245,7 @@ public class ActMain extends AppCompatActivity
String username = "?"; String username = "?";
String full_acct = username + "@" + host; String full_acct = username + "@" + host;
SavedAccount account = SavedAccount.loadPseudoAccount( this,log, full_acct ); SavedAccount account = SavedAccount.loadAccountByAcct( this, log, full_acct );
if( account != null ){ if( account != null ){
return account; return account;
} }
@ -1809,7 +1802,6 @@ public class ActMain extends AppCompatActivity
Utils.showToast( ActMain.this, false, R.string.app_was_muted ); Utils.showToast( ActMain.this, false, R.string.app_was_muted );
} }
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
interface FindAccountCallback { interface FindAccountCallback {
@ -2022,16 +2014,16 @@ public class ActMain extends AppCompatActivity
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
public void openHashTag( int pos, SavedAccount access_info, String tag ){ public void openHashTag( int pos, SavedAccount access_info, String tag ){
while( tag.startsWith( "#" ) ) tag = tag.substring( 1 ); while( tag.startsWith( "#" ) ) tag = tag.substring( 1 );
addColumn( pos, access_info, Column.TYPE_HASHTAG, tag ); addColumn( pos, access_info, Column.TYPE_HASHTAG, tag );
} }
// 他インスタンスのハッシュタグの表示 // 他インスタンスのハッシュタグの表示
private void openHashTagOtherInstance( final int pos, final SavedAccount access_info, final String url, final String host, String tag ){ private void openHashTagOtherInstance( final int pos, final SavedAccount access_info, final String url, final String host, String tag ){
while( tag.startsWith( "#" ) ) tag = tag.substring( 1 ); while( tag.startsWith( "#" ) ) tag = tag.substring( 1 );
openHashTagOtherInstance_sub(pos,access_info,url,host,tag); openHashTagOtherInstance_sub( pos, access_info, url, host, tag );
} }
// 他インスタンスのハッシュタグの表示 // 他インスタンスのハッシュタグの表示
private void openHashTagOtherInstance_sub( final int pos, final SavedAccount access_info, final String url, final String host, final String tag ){ private void openHashTagOtherInstance_sub( final int pos, final SavedAccount access_info, final String url, final String host, final String tag ){
@ -2042,13 +2034,12 @@ public class ActMain extends AppCompatActivity
// ソートする // ソートする
SavedAccount.sort( account_list ); SavedAccount.sort( account_list );
ArrayList< SavedAccount > list_original = new ArrayList<>( ); ArrayList< SavedAccount > list_original = new ArrayList<>();
ArrayList< SavedAccount > list_original_pseudo = new ArrayList<>( ); ArrayList< SavedAccount > list_original_pseudo = new ArrayList<>();
ArrayList< SavedAccount > list_other = new ArrayList<>( ); ArrayList< SavedAccount > list_other = new ArrayList<>();
for( SavedAccount a : account_list ){ for( SavedAccount a : account_list ){
log.d("sort? %s",a.acct); log.d( "sort? %s", a.acct );
if( ! host.equalsIgnoreCase( a.host ) ){ if( ! host.equalsIgnoreCase( a.host ) ){
list_other.add( a ); list_other.add( a );
}else if( a.isPseudo() ){ }else if( a.isPseudo() ){
@ -2081,7 +2072,7 @@ public class ActMain extends AppCompatActivity
for( SavedAccount a : list_original ){ for( SavedAccount a : list_original ){
final SavedAccount _a = a; final SavedAccount _a = a;
dialog.addAction( AcctColor.getStringWithNickname( ActMain.this,R.string.open_in_account,a.acct ), new Runnable() { dialog.addAction( AcctColor.getStringWithNickname( ActMain.this, R.string.open_in_account, a.acct ), new Runnable() {
@Override public void run(){ @Override public void run(){
openHashTag( pos, _a, tag ); openHashTag( pos, _a, tag );
} }
@ -2090,7 +2081,7 @@ public class ActMain extends AppCompatActivity
// //
for( SavedAccount a : list_original_pseudo ){ for( SavedAccount a : list_original_pseudo ){
final SavedAccount _a = a; final SavedAccount _a = a;
dialog.addAction( AcctColor.getStringWithNickname( ActMain.this,R.string.open_in_account,a.acct ), new Runnable() { dialog.addAction( AcctColor.getStringWithNickname( ActMain.this, R.string.open_in_account, a.acct ), new Runnable() {
@Override public void run(){ @Override public void run(){
openHashTag( pos, _a, tag ); openHashTag( pos, _a, tag );
} }
@ -2099,18 +2090,18 @@ public class ActMain extends AppCompatActivity
// //
for( SavedAccount a : list_other ){ for( SavedAccount a : list_other ){
final SavedAccount _a = a; final SavedAccount _a = a;
dialog.addAction( AcctColor.getStringWithNickname( ActMain.this,R.string.open_in_account,a.acct ), new Runnable() { dialog.addAction( AcctColor.getStringWithNickname( ActMain.this, R.string.open_in_account, a.acct ), new Runnable() {
@Override public void run(){ @Override public void run(){
openHashTag( pos, _a, tag ); openHashTag( pos, _a, tag );
} }
} ); } );
} }
dialog.show( this,"#"+ tag ); dialog.show( this, "#" + tag );
} }
final MyClickableSpan.LinkClickCallback link_click_listener = new MyClickableSpan.LinkClickCallback() { final MyClickableSpan.LinkClickCallback link_click_listener = new MyClickableSpan.LinkClickCallback() {
@Override public void onClickLink( View view, @NonNull final MyClickableSpan span){ @Override public void onClickLink( View view, @NonNull final MyClickableSpan span ){
View view_orig = view; View view_orig = view;
@ -2142,7 +2133,7 @@ public class ActMain extends AppCompatActivity
if( m.find() ){ if( m.find() ){
// https://mastodon.juggler.jp/tags/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%B0 // https://mastodon.juggler.jp/tags/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%B0
final String host = m.group( 1 ); final String host = m.group( 1 );
final String tag = span.text.startsWith( "#" )? span.text : "#"+ Uri.decode( m.group( 2 ) ); final String tag = span.text.startsWith( "#" ) ? span.text : "#" + Uri.decode( m.group( 2 ) );
ActionsDialog d = new ActionsDialog() ActionsDialog d = new ActionsDialog()
.addAction( getString( R.string.open_hashtag_column ), new Runnable() { .addAction( getString( R.string.open_hashtag_column ), new Runnable() {
@ -2150,49 +2141,47 @@ public class ActMain extends AppCompatActivity
openHashTagOtherInstance( pos, (SavedAccount) span.lcc, span.url, host, tag ); openHashTagOtherInstance( pos, (SavedAccount) span.lcc, span.url, host, tag );
} }
} ) } )
.addAction( getString( R.string.quote_hashtag_of ,tag ), new Runnable() { .addAction( getString( R.string.quote_hashtag_of, tag ), new Runnable() {
@Override public void run(){ @Override public void run(){
openPost( tag + " "); openPost( tag + " " );
} }
} ); } );
final ArrayList<String> tag_list = new ArrayList<>( ); final ArrayList< String > tag_list = new ArrayList<>();
try{ try{
//noinspection ConstantConditions //noinspection ConstantConditions
CharSequence cs = ((TextView)view_orig).getText(); CharSequence cs = ( (TextView) view_orig ).getText();
if( cs instanceof Spannable){ if( cs instanceof Spannable ){
Spannable content = (Spannable) cs; Spannable content = (Spannable) cs;
for( MyClickableSpan s : content.getSpans( 0,content.length(), MyClickableSpan.class ) ){ for( MyClickableSpan s : content.getSpans( 0, content.length(), MyClickableSpan.class ) ){
m = reUrlHashTag.matcher( s.url ); m = reUrlHashTag.matcher( s.url );
if( m.find() ){ if( m.find() ){
String s_tag = s.text.startsWith( "#" )? s.text : "#"+Uri.decode( m.group( 2 ) ); String s_tag = s.text.startsWith( "#" ) ? s.text : "#" + Uri.decode( m.group( 2 ) );
tag_list.add( s_tag ); tag_list.add( s_tag );
} }
} }
} }
}catch(Throwable ex){ }catch( Throwable ex ){
log.trace(ex); log.trace( ex );
} }
if(tag_list.size() > 1 ){ if( tag_list.size() > 1 ){
StringBuilder sb = new StringBuilder( ); StringBuilder sb = new StringBuilder();
for( String s : tag_list){ for( String s : tag_list ){
if( sb.length() > 0 ) sb.append(' '); if( sb.length() > 0 ) sb.append( ' ' );
sb.append( s ); sb.append( s );
} }
final String tag_all = sb.toString(); final String tag_all = sb.toString();
d.addAction( getString( R.string.quote_all_hashtag_of ,tag_all), new Runnable() { d.addAction( getString( R.string.quote_all_hashtag_of, tag_all ), new Runnable() {
@Override public void run(){ @Override public void run(){
openPost( tag_all +" "); openPost( tag_all + " " );
} }
} ); } );
} }
d.show(ActMain.this,tag); d.show( ActMain.this, tag );
return; return;
} }
openChromeTab( pos, (SavedAccount) span.lcc, span.url, false ); openChromeTab( pos, (SavedAccount) span.lcc, span.url, false );
} }
}; };
@ -2230,11 +2219,15 @@ public class ActMain extends AppCompatActivity
ActPost.open( this, REQUEST_CODE_POST, account.db_id, "@" + account.getFullAcct( who ) + " " ); ActPost.open( this, REQUEST_CODE_POST, account.db_id, "@" + account.getFullAcct( who ) + " " );
} }
public void performMentionFromAnotherAccount( SavedAccount access_info, final TootAccount who, ArrayList< SavedAccount > account_list_non_pseudo ){ public void performMentionFromAnotherAccount( SavedAccount access_info, @Nullable final TootAccount who ){
if( who == null ) return;
String who_host = access_info.getAccountHost( who );
final String initial_text = "@" + access_info.getFullAcct( who ) + " "; final String initial_text = "@" + access_info.getFullAcct( who ) + " ";
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_toot ) , getString( R.string.account_picker_toot )
, account_list_non_pseudo, new AccountPicker.AccountPickerCallback() { , makeAccountList( log, false, who_host )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){ @Override public void onAccountPicked( @NonNull SavedAccount ai ){
ActPost.open( ActMain.this, REQUEST_CODE_POST, ai.db_id, initial_text ); ActPost.open( ActMain.this, REQUEST_CODE_POST, ai.db_id, initial_text );
} }
@ -2314,9 +2307,13 @@ public class ActMain extends AppCompatActivity
}.executeOnExecutor( App1.task_executor ); }.executeOnExecutor( App1.task_executor );
} }
void openProfileFromAnotherAccount( final int pos, @NonNull final SavedAccount access_info, final TootAccount who ){ void openProfileFromAnotherAccount( final int pos, @NonNull final SavedAccount access_info, @Nullable final TootAccount who ){
if( who == null ) return;
String who_host = access_info.getAccountHost( who );
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_open_user_who, AcctColor.getNickname( who.acct ) ) , getString( R.string.account_picker_open_user_who, AcctColor.getNickname( who.acct ) )
, makeAccountList( log, false, who_host )
, new AccountPicker.AccountPickerCallback() { , new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){ @Override public void onAccountPicked( @NonNull SavedAccount ai ){
if( ai.host.equalsIgnoreCase( access_info.host ) ){ if( ai.host.equalsIgnoreCase( access_info.host ) ){
@ -2370,23 +2367,18 @@ public class ActMain extends AppCompatActivity
// 文脈がないもしくは疑似アカウントだった // 文脈がないもしくは疑似アカウントだった
// 疑似アカウントではユーザ情報APIを呼べないし検索APIも使えない
// 疑似ではないアカウントの一覧 // 疑似ではないアカウントの一覧
ArrayList< SavedAccount > account_list_filtered = new ArrayList<>();
for( SavedAccount a : SavedAccount.loadAccountList( ActMain.this, log ) ){
if( a.isPseudo() ) continue;
account_list_filtered.add( a );
}
if( account_list_filtered.isEmpty() ){ if( ! SavedAccount.hasRealAccount(log) ){
// アカウントがないのでchrome tab で開くしかない // 疑似アカウントではユーザ情報APIを呼べないし検索APIも使えない
// chrome tab で開くしかない
openChromeTab( pos, access_info, url, true ); openChromeTab( pos, access_info, url, true );
}else{ }else{
// アカウントを選択して開く // アカウントを選択して開く
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_open_user_who, AcctColor.getNickname( user + "@" + host ) ) , getString( R.string.account_picker_open_user_who, AcctColor.getNickname( user + "@" + host ) )
, account_list_filtered , makeAccountList( log,false,host )
, new AccountPicker.AccountPickerCallback() { , new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){ @Override public void onAccountPicked( @NonNull SavedAccount ai ){
openProfileRemote( pos, ai, url ); openProfileRemote( pos, ai, url );
@ -2813,10 +2805,11 @@ public class ActMain extends AppCompatActivity
// static final Pattern reUriActivityPubToot = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE ); // static final Pattern reUriActivityPubToot = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE );
public void openStatusOtherInstance( int pos, @NonNull SavedAccount access_info, @NonNull TootStatusLike status ){ public void openStatusOtherInstance( int pos, @NonNull SavedAccount access_info, @Nullable TootStatusLike status ){
if( status.account == null ){ // アカウント情報がないと出来ないことがある
// アカウント情報がないと出来ないことがある if( status == null || status.account == null ) return;
}else if( status instanceof MSPToot ){
if( status instanceof MSPToot ){
// トゥート検索の場合 // トゥート検索の場合
openStatusOtherInstance( pos, access_info, status.url openStatusOtherInstance( pos, access_info, status.url
, status.id , status.id
@ -2927,7 +2920,7 @@ public class ActMain extends AppCompatActivity
SavedAccount.sort( local_account_list ); SavedAccount.sort( local_account_list );
for( SavedAccount a : local_account_list ){ for( SavedAccount a : local_account_list ){
final SavedAccount _a = a; final SavedAccount _a = a;
dialog.addAction( AcctColor.getStringWithNickname( ActMain.this,R.string.open_in_account,a.acct ), new Runnable() { dialog.addAction( AcctColor.getStringWithNickname( ActMain.this, R.string.open_in_account, a.acct ), new Runnable() {
@Override public void run(){ @Override public void run(){
openStatusLocal( pos, _a, status_id_original ); openStatusLocal( pos, _a, status_id_original );
} }
@ -2938,7 +2931,7 @@ public class ActMain extends AppCompatActivity
SavedAccount.sort( access_account_list ); SavedAccount.sort( access_account_list );
for( SavedAccount a : access_account_list ){ for( SavedAccount a : access_account_list ){
final SavedAccount _a = a; final SavedAccount _a = a;
dialog.addAction( AcctColor.getStringWithNickname( ActMain.this,R.string.open_in_account,a.acct ), new Runnable() { dialog.addAction( AcctColor.getStringWithNickname( ActMain.this, R.string.open_in_account, a.acct ), new Runnable() {
@Override public void run(){ @Override public void run(){
openStatusLocal( pos, _a, status_id_access ); openStatusLocal( pos, _a, status_id_access );
} }
@ -2946,10 +2939,10 @@ public class ActMain extends AppCompatActivity
} }
// その他の実アカウント // その他の実アカウント
SavedAccount.sort( other_account_list); SavedAccount.sort( other_account_list );
for( SavedAccount a : other_account_list ){ for( SavedAccount a : other_account_list ){
final SavedAccount _a = a; final SavedAccount _a = a;
dialog.addAction( AcctColor.getStringWithNickname( ActMain.this,R.string.open_in_account,a.acct ), new Runnable() { dialog.addAction( AcctColor.getStringWithNickname( ActMain.this, R.string.open_in_account, a.acct ), new Runnable() {
@Override public void run(){ @Override public void run(){
openStatusRemote( pos, _a, url ); openStatusRemote( pos, _a, url );
} }
@ -3077,7 +3070,7 @@ public class ActMain extends AppCompatActivity
} ); } );
client.setAccount( access_info ); client.setAccount( access_info );
TootApiResult result; TootApiResult result;
Request.Builder request_builder = new Request.Builder() Request.Builder request_builder = new Request.Builder()
.post( RequestBody.create( .post( RequestBody.create(
TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED
@ -3105,21 +3098,22 @@ public class ActMain extends AppCompatActivity
@Override @Override
protected void onPostExecute( TootApiResult result ){ protected void onPostExecute( TootApiResult result ){
try{ try{
progress.dismiss(); progress.dismiss();
}catch(Throwable ignored){ }catch( Throwable ignored ){
} }
//noinspection StatementWithEmptyBody //noinspection StatementWithEmptyBody
if( result == null ){ if( result == null ){
// cancelled. // cancelled.
}else if( new_status != null ){ }else if( new_status != null ){
for( Column column : app_state.column_list ){ for( Column column : app_state.column_list ){
column.findStatus( access_info.host, new_status.id, new Column.StatusEntryCallback() { column.findStatus( access_info.host, new_status.id, new Column.StatusEntryCallback() {
@Override public boolean onIterate( SavedAccount account, TootStatus status ){ @Override
public boolean onIterate( SavedAccount account, TootStatus status ){
status.pinned = bSet; status.pinned = bSet;
return true; return true;
} }
@ -3128,7 +3122,7 @@ public class ActMain extends AppCompatActivity
}else{ }else{
Utils.showToast( ActMain.this, true, result.error ); Utils.showToast( ActMain.this, true, result.error );
} }
// 結果に関わらず更新中状態から復帰させる // 結果に関わらず更新中状態から復帰させる
showColumnMatchAccount( access_info ); showColumnMatchAccount( access_info );
} }
@ -3137,14 +3131,14 @@ public class ActMain extends AppCompatActivity
progress.setIndeterminate( true ); progress.setIndeterminate( true );
progress.setCancelable( true ); progress.setCancelable( true );
progress.setMessage( getString(R.string.profile_pin_progress)); progress.setMessage( getString( R.string.profile_pin_progress ) );
progress.setOnCancelListener( new DialogInterface.OnCancelListener() { progress.setOnCancelListener( new DialogInterface.OnCancelListener() {
@Override public void onCancel( DialogInterface dialog ){ @Override public void onCancel( DialogInterface dialog ){
task.cancel( true ); task.cancel( true );
} }
} ); } );
progress.show(); progress.show();
task.executeOnExecutor( App1.task_executor ); task.executeOnExecutor( App1.task_executor );
} }
@ -3451,7 +3445,7 @@ public class ActMain extends AppCompatActivity
result = client.request( "/api/v1/accounts/" + who.id result = client.request( "/api/v1/accounts/" + who.id
+ ( bFollow ? "/follow" : "/unfollow" ) + ( bFollow ? "/follow" : "/unfollow" )
, request_builder ); , request_builder );
if( result != null && result.object != null ){ if( result != null && result.object != null ){
// 1.6.0 rc2 からフォローAPIのレスポンスに含まれるrelationは虚偽の内容を返すようになるらしい // 1.6.0 rc2 からフォローAPIのレスポンスに含まれるrelationは虚偽の内容を返すようになるらしい
// https://github.com/tootsuite/mastodon/pull/4799 // https://github.com/tootsuite/mastodon/pull/4799
// 実際の情報を取得するためリレーションを読み直す // 実際の情報を取得するためリレーションを読み直す
@ -3509,7 +3503,7 @@ public class ActMain extends AppCompatActivity
}else if( bFollow && who.locked && result.response != null && result.response.code() == 422 ){ }else if( bFollow && who.locked && result.response != null && result.response.code() == 422 ){
Utils.showToast( ActMain.this, false, R.string.cant_follow_locked_user ); Utils.showToast( ActMain.this, false, R.string.cant_follow_locked_user );
}else if(result.response !=null && result.response.code()==500){ }else if( result.response != null && result.response.code() == 500 ){
Utils.showToast( ActMain.this, false, R.string.already_followed ); Utils.showToast( ActMain.this, false, R.string.already_followed );
}else{ }else{
Utils.showToast( ActMain.this, false, result.error ); Utils.showToast( ActMain.this, false, result.error );
@ -3630,7 +3624,7 @@ public class ActMain extends AppCompatActivity
}else if( locked && result.response != null && result.response.code() == 422 ){ }else if( locked && result.response != null && result.response.code() == 422 ){
Utils.showToast( ActMain.this, false, R.string.cant_follow_locked_user ); Utils.showToast( ActMain.this, false, R.string.cant_follow_locked_user );
}else if(result.response !=null && result.response.code()==500){ }else if( result.response != null && result.response.code() == 500 ){
Utils.showToast( ActMain.this, false, R.string.already_followed ); Utils.showToast( ActMain.this, false, R.string.already_followed );
}else{ }else{
Utils.showToast( ActMain.this, false, result.error ); Utils.showToast( ActMain.this, false, result.error );
@ -4055,6 +4049,7 @@ public class ActMain extends AppCompatActivity
Utils.showToast( ActMain.this, false, R.string.unboost_succeeded ); Utils.showToast( ActMain.this, false, R.string.unboost_succeeded );
} }
}; };
private void openOSSLicense(){ private void openOSSLicense(){
startActivity( new Intent( this, ActOSSLicense.class ) ); startActivity( new Intent( this, ActOSSLicense.class ) );
} }
@ -4194,6 +4189,20 @@ public class ActMain extends AppCompatActivity
return dst; return dst;
} }
private ArrayList< SavedAccount > makeAccountList( @NonNull LogCategory log, boolean bAllowPseudo, @Nullable String pickup_host ){
ArrayList< SavedAccount > list_same_host = new ArrayList<>();
ArrayList< SavedAccount > list_other_host = new ArrayList<>();
for( SavedAccount a : SavedAccount.loadAccountList( ActMain.this, log ) ){
if( a.isPseudo() && ( a.isNA() || ! bAllowPseudo ) ) continue;
( pickup_host == null || pickup_host.equalsIgnoreCase( a.host ) ? list_same_host : list_other_host ).add( a );
}
SavedAccount.sort( list_same_host );
SavedAccount.sort( list_other_host );
list_same_host.addAll( list_other_host );
return list_same_host;
}
// 別アカ操作と別タンスの関係 // 別アカ操作と別タンスの関係
static final int NOT_CROSS_ACCOUNT = 1; static final int NOT_CROSS_ACCOUNT = 1;
static final int CROSS_ACCOUNT_SAME_INSTANCE = 2; static final int CROSS_ACCOUNT_SAME_INSTANCE = 2;
@ -4211,9 +4220,11 @@ public class ActMain extends AppCompatActivity
void openBoostFromAnotherAccount( @NonNull final SavedAccount timeline_account, @Nullable final TootStatusLike status ){ void openBoostFromAnotherAccount( @NonNull final SavedAccount timeline_account, @Nullable final TootStatusLike status ){
if( status == null ) return; if( status == null ) return;
String who_host = status.account == null ? null : timeline_account.getAccountHost( status.account );
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_boost ) , getString( R.string.account_picker_boost )
, makeAccountListNonPseudo( log ) , makeAccountList( log, false, who_host )
, new AccountPicker.AccountPickerCallback() { , new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount action_account ){ @Override public void onAccountPicked( @NonNull SavedAccount action_account ){
performBoost( performBoost(
@ -4228,11 +4239,13 @@ public class ActMain extends AppCompatActivity
} ); } );
} }
void openFavouriteFromAnotherAccount( @NonNull final SavedAccount timeline_account, final TootStatusLike status ){ void openFavouriteFromAnotherAccount( @NonNull final SavedAccount timeline_account, @Nullable final TootStatusLike status ){
if( status == null ) return; if( status == null ) return;
String who_host = status.account == null ? null : timeline_account.getAccountHost( status.account );
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_favourite ) , getString( R.string.account_picker_favourite )
, makeAccountListNonPseudo( log ) , makeAccountList( log, false, who_host )
, new AccountPicker.AccountPickerCallback() { , new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount action_account ){ @Override public void onAccountPicked( @NonNull SavedAccount action_account ){
performFavourite( performFavourite(
@ -4246,10 +4259,13 @@ public class ActMain extends AppCompatActivity
} ); } );
} }
void openReplyFromAnotherAccount( final TootStatusLike status ){ void openReplyFromAnotherAccount( @NonNull final SavedAccount timeline_account, @Nullable final TootStatusLike status ){
if( status == null ) return;
String who_host = status.account == null ? null : timeline_account.getAccountHost( status.account );
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_reply ) , getString( R.string.account_picker_reply )
, makeAccountListNonPseudo( log ), new AccountPicker.AccountPickerCallback() { , makeAccountList( log, false, who_host )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){ @Override public void onAccountPicked( @NonNull SavedAccount ai ){
if( status instanceof MSPToot ){ if( status instanceof MSPToot ){
// MSPの場合status.url https://instance/@user/:status_id の形式になる // MSPの場合status.url https://instance/@user/:status_id の形式になる
@ -4283,12 +4299,15 @@ public class ActMain extends AppCompatActivity
// openFollowFromAnotherAccount( access_info, status.account ); // openFollowFromAnotherAccount( access_info, status.account );
// } // }
void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, final TootAccount account ){ void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, @Nullable final TootAccount account ){
if( account == null ) return; if( account == null ) return;
String who_host = access_info.getAccountHost( account );
final String who_acct = access_info.getFullAcct( account ); final String who_acct = access_info.getFullAcct( account );
AccountPicker.pick( this, false, false AccountPicker.pick( this, false, false
, getString( R.string.account_picker_follow ) , getString( R.string.account_picker_follow )
, makeAccountListNonPseudo( log ), new AccountPicker.AccountPickerCallback() { , makeAccountList( log, false, who_host )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){ @Override public void onAccountPicked( @NonNull SavedAccount ai ){
callRemoteFollow( ai, who_acct, account.locked, false, follow_complete_callback ); callRemoteFollow( ai, who_acct, account.locked, false, follow_complete_callback );
} }
@ -4464,8 +4483,6 @@ public class ActMain extends AppCompatActivity
tablet_pager_adapter.notifyDataSetChanged(); tablet_pager_adapter.notifyDataSetChanged();
} }
private void scrollToColumn( int index, boolean bAlign ){ private void scrollToColumn( int index, boolean bAlign ){
scrollColumnStrip( index ); scrollColumnStrip( index );
@ -4628,16 +4645,16 @@ public class ActMain extends AppCompatActivity
if( host.equalsIgnoreCase( a.host ) ) account_list.add( a ); if( host.equalsIgnoreCase( a.host ) ) account_list.add( a );
} }
if( account_list.isEmpty() ){ if( account_list.isEmpty() ){
SavedAccount ai = addPseudoAccount( host ); SavedAccount ai = addPseudoAccount( host );
if( ai != null ){ if( ai != null ){
addColumn( getDefaultInsertPosition(), ai, Column.TYPE_LOCAL ); addColumn( getDefaultInsertPosition(), ai, Column.TYPE_LOCAL );
} }
}else{ }else{
SavedAccount.sort( account_list);
AccountPicker.pick( this, true, false AccountPicker.pick( this, true, false
, getString( R.string.account_picker_add_timeline_of, host ) , getString( R.string.account_picker_add_timeline_of, host )
, account_list, new AccountPicker.AccountPickerCallback() { , account_list
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){ @Override public void onAccountPicked( @NonNull SavedAccount ai ){
addColumn( getDefaultInsertPosition(), ai, Column.TYPE_LOCAL ); addColumn( getDefaultInsertPosition(), ai, Column.TYPE_LOCAL );
} }
@ -4687,7 +4704,7 @@ public class ActMain extends AppCompatActivity
}; };
int nAutoCwCellWidth = 0; int nAutoCwCellWidth = 0;
int nAutoCwLines =0; int nAutoCwLines = 0;
private void resizeAutoCW( int column_w ){ private void resizeAutoCW( int column_w ){
String sv = pref.getString( Pref.KEY_AUTO_CW_LINES, "" ); String sv = pref.getString( Pref.KEY_AUTO_CW_LINES, "" );
@ -4696,35 +4713,35 @@ public class ActMain extends AppCompatActivity
int lv_pad = (int) ( 0.5f + 12 * density ); int lv_pad = (int) ( 0.5f + 12 * density );
int icon_width = mAvatarIconSize; int icon_width = mAvatarIconSize;
int icon_end = (int) ( 0.5f + 4 * density ); int icon_end = (int) ( 0.5f + 4 * density );
nAutoCwCellWidth = column_w - lv_pad*2 - icon_width - icon_end; nAutoCwCellWidth = column_w - lv_pad * 2 - icon_width - icon_end;
} }
// この後各カラムは再描画される // この後各カラムは再描画される
} }
void checkAutoCW( @NonNull TootStatusLike status, @NonNull CharSequence text ){ void checkAutoCW( @NonNull TootStatusLike status, @NonNull CharSequence text ){
if( nAutoCwCellWidth <= 0 ){ if( nAutoCwCellWidth <= 0 ){
// 設定が無効 // 設定が無効
status.auto_cw = null; status.auto_cw = null;
return; return;
} }
TootStatusLike.AutoCW a = status.auto_cw; TootStatusLike.AutoCW a = status.auto_cw;
if( a != null && a.refActivity.get() == ActMain.this && a.cell_width == nAutoCwCellWidth ){ if( a != null && a.refActivity.get() == ActMain.this && a.cell_width == nAutoCwCellWidth ){
// 以前に計算した値がまだ使える // 以前に計算した値がまだ使える
return; return;
} }
if( a == null ) a = status.auto_cw = new TootStatusLike.AutoCW(); if( a == null ) a = status.auto_cw = new TootStatusLike.AutoCW();
// 計算時の条件(文字フォント文字サイズカラム幅を覚えておいて再利用時に同じか確認する // 計算時の条件(文字フォント文字サイズカラム幅を覚えておいて再利用時に同じか確認する
a.refActivity =new WeakReference< Object >( ActMain.this ); a.refActivity = new WeakReference< Object >( ActMain.this );
a.cell_width = nAutoCwCellWidth; a.cell_width = nAutoCwCellWidth;
a.decoded_spoiler_text = null; a.decoded_spoiler_text = null;
// テキストをレイアウトして行数を測定 // テキストをレイアウトして行数を測定
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( nAutoCwCellWidth,LinearLayout.LayoutParams.WRAP_CONTENT ); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( nAutoCwCellWidth, LinearLayout.LayoutParams.WRAP_CONTENT );
TextView tv = new TextView(this); TextView tv = new TextView( this );
tv.setLayoutParams( lp ); tv.setLayoutParams( lp );
if( ! Float.isNaN( timeline_font_size_sp ) ){ if( ! Float.isNaN( timeline_font_size_sp ) ){
tv.setTextSize( timeline_font_size_sp ); tv.setTextSize( timeline_font_size_sp );
@ -4734,8 +4751,8 @@ public class ActMain extends AppCompatActivity
} }
tv.setText( text ); tv.setText( text );
tv.measure( tv.measure(
View.MeasureSpec.makeMeasureSpec( nAutoCwCellWidth, View.MeasureSpec.EXACTLY) View.MeasureSpec.makeMeasureSpec( nAutoCwCellWidth, View.MeasureSpec.EXACTLY )
,View.MeasureSpec.makeMeasureSpec( 0, View.MeasureSpec.UNSPECIFIED) , View.MeasureSpec.makeMeasureSpec( 0, View.MeasureSpec.UNSPECIFIED )
); );
Layout l = tv.getLayout(); Layout l = tv.getLayout();
if( l != null ){ if( l != null ){

View File

@ -325,7 +325,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
break; break;
case R.id.btnReplyAnotherAccount: case R.id.btnReplyAnotherAccount:
activity.openReplyFromAnotherAccount( status ); activity.openReplyFromAnotherAccount( access_info,status );
break; break;
case R.id.btnConversationAnotherAccount: case R.id.btnConversationAnotherAccount:
@ -462,21 +462,15 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
break; break;
case R.id.btnFollowFromAnotherAccount: case R.id.btnFollowFromAnotherAccount:
if( who != null ){ activity.openFollowFromAnotherAccount( access_info, who );
activity.openFollowFromAnotherAccount( access_info, who );
}
break; break;
case R.id.btnSendMessageFromAnotherAccount: case R.id.btnSendMessageFromAnotherAccount:
if( who != null ){ activity.performMentionFromAnotherAccount( access_info, who );
activity.performMentionFromAnotherAccount( access_info, who, account_list_non_pseudo );
}
break; break;
case R.id.btnOpenProfileFromAnotherAccount: case R.id.btnOpenProfileFromAnotherAccount:
if( who != null ){ activity.openProfileFromAnotherAccount( pos, access_info, who );
activity.openProfileFromAnotherAccount( pos, access_info, who );
}
break; break;
case R.id.btnNickname: case R.id.btnNickname:

View File

@ -148,7 +148,7 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
if( status instanceof TootStatus && ! access_info.isPseudo() ){ if( status instanceof TootStatus && ! access_info.isPseudo() ){
activity.performReply( access_info, (TootStatus) status ); activity.performReply( access_info, (TootStatus) status );
}else{ }else{
activity.openReplyFromAnotherAccount( status ); activity.openReplyFromAnotherAccount( access_info, status );
} }
break; break;
@ -218,13 +218,13 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
break; break;
case R.id.btnFollow2: case R.id.btnFollow2:
if( status != null && status.account != null ){ if( status != null ){
activity.openFollowFromAnotherAccount( access_info, status.account ); activity.openFollowFromAnotherAccount( access_info, status.account );
} }
break; break;
case R.id.btnReply: case R.id.btnReply:
activity.openReplyFromAnotherAccount( status ); activity.openReplyFromAnotherAccount( access_info, status );
break; break;
} }

View File

@ -41,7 +41,8 @@ public class AccountPicker {
){ ){
ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( activity,ActMain.log ); ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( activity,ActMain.log );
pick( activity, bAllowPseudo, bAuto, message, account_list, callback ,null ); SavedAccount.sort( account_list );
pick( activity, bAllowPseudo, bAuto, message, account_list, true,callback ,null );
} }
public static void pick( public static void pick(
@ -50,10 +51,10 @@ public class AccountPicker {
, boolean bAuto , boolean bAuto
, String message , String message
, @NonNull final AccountPickerCallback callback , @NonNull final AccountPickerCallback callback
, @Nullable final DialogInterface.OnDismissListener dissmiss_callback , @Nullable final DialogInterface.OnDismissListener dismiss_callback
){ ){
ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( activity,ActMain.log ); ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( activity,ActMain.log );
pick( activity, bAllowPseudo, bAuto, message, account_list, callback ,dissmiss_callback ); pick( activity, bAllowPseudo, bAuto, message, account_list, true, callback ,dismiss_callback );
} }
public static void pick( public static void pick(
@ -64,15 +65,16 @@ public class AccountPicker {
, @NonNull final ArrayList< SavedAccount > account_list , @NonNull final ArrayList< SavedAccount > account_list
, @NonNull final AccountPickerCallback callback , @NonNull final AccountPickerCallback callback
){ ){
pick( activity, bAllowPseudo, bAuto, message, account_list, callback ,null ); pick( activity, bAllowPseudo, bAuto, message, account_list, false, callback ,null );
} }
public static void pick( private static void pick(
@NonNull AppCompatActivity activity @NonNull AppCompatActivity activity
, boolean bAllowPseudo , boolean bAllowPseudo
, boolean bAuto , boolean bAuto
, String message , String message
, @NonNull final ArrayList< SavedAccount > account_list , @NonNull final ArrayList< SavedAccount > account_list
,boolean bSort
, @NonNull final AccountPickerCallback callback , @NonNull final AccountPickerCallback callback
, @Nullable final DialogInterface.OnDismissListener dismiss_callback , @Nullable final DialogInterface.OnDismissListener dismiss_callback
){ ){
@ -95,12 +97,16 @@ public class AccountPicker {
} }
} }
if(bSort){
SavedAccount.sort( account_list );
}
if( bAuto && account_list.size() == 1 ){ if( bAuto && account_list.size() == 1 ){
callback.onAccountPicked( account_list.get( 0 ) ); callback.onAccountPicked( account_list.get( 0 ) );
return; return;
} }
SavedAccount.sort( account_list );
@SuppressLint("InflateParams") View viewRoot = activity.getLayoutInflater().inflate( R.layout.dlg_account_picker, null, false ); @SuppressLint("InflateParams") View viewRoot = activity.getLayoutInflater().inflate( R.layout.dlg_account_picker, null, false );

View File

@ -98,7 +98,7 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
return instance; return instance;
} }
public void setInstance(@NonNull TootInstance instance){ public void setInstance(@NonNull TootInstance instance){
if( instance != null ) refInstance.set(instance); refInstance.set(instance);
} }
@ -462,7 +462,7 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
} }
@Nullable @Nullable
public static SavedAccount loadPseudoAccount( Context context, @NonNull LogCategory log, String full_acct ){ public static SavedAccount loadAccountByAcct( Context context, @NonNull LogCategory log, String full_acct ){
try{ try{
Cursor cursor = App1.getDB().query( table, null, COL_USER + "=?", new String[]{ full_acct }, null, null, null ); Cursor cursor = App1.getDB().query( table, null, COL_USER + "=?", new String[]{ full_acct }, null, null, null );
try{ try{
@ -474,11 +474,28 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
} }
}catch( Throwable ex ){ }catch( Throwable ex ){
log.trace( ex ); log.trace( ex );
log.e( ex, "loadPseudoAccount failed." ); log.e( ex, "loadAccountByAcct failed." );
} }
return null; return null;
} }
public static boolean hasRealAccount( @NonNull LogCategory log ){
try{
Cursor cursor = App1.getDB().query( table, null, COL_USER + " NOT LIKE '?@%'", null , null, null, null, "1");
try{
if( cursor.moveToNext() ){
return true;
}
}finally{
cursor.close();
}
}catch( Throwable ex ){
log.trace( ex );
log.e( ex, "hasNonPseudoAccount failed." );
}
return false;
}
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public @NonNull String getAccountHost( @Nullable String acct ){ public @NonNull String getAccountHost( @Nullable String acct ){
@ -665,4 +682,8 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
Collections.sort( account_list, account_comparator ); Collections.sort( account_list, account_comparator );
} }
public @NonNull String getAcctHost( @NonNull TootAccount who ){
String host = who.getAcctHost();
return host != null ? host : this.host;
}
} }