お気に入り操作時に変更中の表示が出なくなっていたバグの修正。トゥート検索機能を追加。
This commit is contained in:
parent
e5626c5539
commit
6f0454e76f
|
@ -2,6 +2,7 @@
|
||||||
<dictionary name="tateisu">
|
<dictionary name="tateisu">
|
||||||
<words>
|
<words>
|
||||||
<w>adamrocker</w>
|
<w>adamrocker</w>
|
||||||
|
<w>apikey</w>
|
||||||
<w>dont</w>
|
<w>dont</w>
|
||||||
<w>emoji</w>
|
<w>emoji</w>
|
||||||
<w>emojione</w>
|
<w>emojione</w>
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
<w>unfollow</w>
|
<w>unfollow</w>
|
||||||
<w>unmute</w>
|
<w>unmute</w>
|
||||||
<w>unreblog</w>
|
<w>unreblog</w>
|
||||||
|
<w>utoken</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
|
@ -9,8 +9,8 @@ android {
|
||||||
applicationId "jp.juggler.subwaytooter"
|
applicationId "jp.juggler.subwaytooter"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 93
|
versionCode 95
|
||||||
versionName "0.9.3"
|
versionName "0.9.5"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ import jp.juggler.subwaytooter.api.entity.TootApplication;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootRelationShip;
|
import jp.juggler.subwaytooter.api.entity.TootRelationShip;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootResults;
|
import jp.juggler.subwaytooter.api.entity.TootResults;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
import jp.juggler.subwaytooter.dialog.AccountPicker;
|
import jp.juggler.subwaytooter.dialog.AccountPicker;
|
||||||
import jp.juggler.subwaytooter.dialog.DlgConfirm;
|
import jp.juggler.subwaytooter.dialog.DlgConfirm;
|
||||||
import jp.juggler.subwaytooter.dialog.LoginForm;
|
import jp.juggler.subwaytooter.dialog.LoginForm;
|
||||||
|
@ -198,11 +199,16 @@ public class ActMain extends AppCompatActivity
|
||||||
boolean bRemoved = false;
|
boolean bRemoved = false;
|
||||||
for( int i = 0, ie = app_state.column_list.size() ; i < ie ; ++ i ){
|
for( int i = 0, ie = app_state.column_list.size() ; i < ie ; ++ i ){
|
||||||
Column column = app_state.column_list.get( i );
|
Column column = app_state.column_list.get( i );
|
||||||
SavedAccount sa = SavedAccount.loadAccount( log, column.access_info.db_id );
|
|
||||||
if( sa == null ){
|
if( column.access_info.isNA() ){
|
||||||
bRemoved = true;
|
// 検索カラムはアカウント削除とか無関係
|
||||||
}else{
|
}else{
|
||||||
new_order.add( i );
|
SavedAccount sa = SavedAccount.loadAccount( log, column.access_info.db_id );
|
||||||
|
if( sa == null ){
|
||||||
|
bRemoved = true;
|
||||||
|
}else{
|
||||||
|
new_order.add( i );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( bRemoved ){
|
if( bRemoved ){
|
||||||
|
@ -607,6 +613,9 @@ public class ActMain extends AppCompatActivity
|
||||||
}else if( id == R.id.nav_muted_word ){
|
}else if( id == R.id.nav_muted_word ){
|
||||||
startActivity( new Intent( this, ActMutedWord.class ) );
|
startActivity( new Intent( this, ActMutedWord.class ) );
|
||||||
|
|
||||||
|
}else if( id == R.id.mastodon_search_portal ){
|
||||||
|
addColumn( getDefaultInsertPosition(), SavedAccount.getNA(),Column.TYPE_SEARCH_PORTAL , "" );
|
||||||
|
|
||||||
// }else if( id == R.id.nav_translation ){
|
// }else if( id == R.id.nav_translation ){
|
||||||
// Intent intent = new Intent(this, TransCommuActivity.class);
|
// Intent intent = new Intent(this, TransCommuActivity.class);
|
||||||
// intent.putExtra(TransCommuActivity.APPLICATION_CODE_EXTRA, "FJlDoBKitg");
|
// intent.putExtra(TransCommuActivity.APPLICATION_CODE_EXTRA, "FJlDoBKitg");
|
||||||
|
@ -1356,7 +1365,7 @@ public class ActMain extends AppCompatActivity
|
||||||
SavedAccount a = column.access_info;
|
SavedAccount a = column.access_info;
|
||||||
if( done_list.contains( a ) ) continue;
|
if( done_list.contains( a ) ) continue;
|
||||||
done_list.add( a );
|
done_list.add( a );
|
||||||
a.reloadSetting();
|
if( !a.isNA() ) a.reloadSetting();
|
||||||
column.fireShowColumnHeader();
|
column.fireShowColumnHeader();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1368,7 +1377,7 @@ public class ActMain extends AppCompatActivity
|
||||||
if( ! Utils.equalsNullable( a.acct, account.acct ) ) continue;
|
if( ! Utils.equalsNullable( a.acct, account.acct ) ) continue;
|
||||||
if( done_list.contains( a ) ) continue;
|
if( done_list.contains( a ) ) continue;
|
||||||
done_list.add( a );
|
done_list.add( a );
|
||||||
a.reloadSetting();
|
if( !a.isNA() ) a.reloadSetting();
|
||||||
column.fireShowColumnHeader();
|
column.fireShowColumnHeader();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1463,6 +1472,7 @@ public class ActMain extends AppCompatActivity
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void performMuteApp( @NonNull TootApplication application ){
|
public void performMuteApp( @NonNull TootApplication application ){
|
||||||
MutedApp.save( application.name );
|
MutedApp.save( application.name );
|
||||||
|
@ -1557,6 +1567,47 @@ public class ActMain extends AppCompatActivity
|
||||||
try{
|
try{
|
||||||
log.d( "openChromeTab url=%s", url );
|
log.d( "openChromeTab url=%s", url );
|
||||||
|
|
||||||
|
if( !noIntercept && access_info != null && access_info.isNA() ){
|
||||||
|
// トゥート検索カラムではaccess_infoは何にも紐ついていない
|
||||||
|
|
||||||
|
// ハッシュタグをアプリ内で開く
|
||||||
|
Matcher m = reHashTag.matcher( url );
|
||||||
|
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
|
||||||
|
String host = m.group( 1 );
|
||||||
|
String tag = Uri.decode( m.group( 2 ) );
|
||||||
|
openHashTagOtherInstance( pos, access_info, url, host, tag );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ステータスページをアプリから開く
|
||||||
|
m = reStatusPage.matcher( url );
|
||||||
|
if( m.find() ){
|
||||||
|
try{
|
||||||
|
// https://mastodon.juggler.jp/@SubwayTooter/(status_id)
|
||||||
|
final String host = m.group( 1 );
|
||||||
|
final long status_id = Long.parseLong( m.group( 3 ), 10 );
|
||||||
|
openStatusOtherInstance( pos, access_info, url, host, status_id );
|
||||||
|
return;
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
Utils.showToast( this, ex, "can't parse status id." );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ユーザページをアプリ内で開く
|
||||||
|
m = reUserPage.matcher( url );
|
||||||
|
if( m.find() ){
|
||||||
|
// https://mastodon.juggler.jp/@SubwayTooter
|
||||||
|
final String host = m.group( 1 );
|
||||||
|
final String user = Uri.decode( m.group( 2 ) );
|
||||||
|
|
||||||
|
openProfileByHostUser( pos,access_info,url,host,user );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if( ! noIntercept && access_info != null ){
|
if( ! noIntercept && access_info != null ){
|
||||||
// ハッシュタグをアプリ内で開く
|
// ハッシュタグをアプリ内で開く
|
||||||
Matcher m = reHashTag.matcher( url );
|
Matcher m = reHashTag.matcher( url );
|
||||||
|
@ -1635,15 +1686,19 @@ public class ActMain extends AppCompatActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openStatus( int pos, @NonNull SavedAccount access_info, @NonNull TootStatus status ){
|
public void openStatus( int pos, @NonNull SavedAccount access_info, @NonNull TootStatusLike status ){
|
||||||
openStatus( pos, access_info, status.id );
|
if( access_info.host.equalsIgnoreCase( status.status_host ) ){
|
||||||
|
openStatus( pos, access_info, status.id );
|
||||||
|
}else{
|
||||||
|
openStatusOtherInstance( pos, access_info,status.url,status.status_host,status.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openStatus( int pos, @NonNull SavedAccount access_info, long status_id ){
|
public void openStatus( int pos, @NonNull SavedAccount access_info, long status_id ){
|
||||||
addColumn( pos, access_info, Column.TYPE_CONVERSATION, status_id );
|
addColumn( pos, access_info, Column.TYPE_CONVERSATION, status_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openStatusOtherInstance( final int pos, final SavedAccount access_info, final String url, final String host, final long status_id ){
|
void openStatusOtherInstance( final int pos, final SavedAccount access_info, final String url, final String host, final long status_id ){
|
||||||
ActionsDialog dialog = new ActionsDialog();
|
ActionsDialog dialog = new ActionsDialog();
|
||||||
|
|
||||||
// ブラウザで表示する
|
// ブラウザで表示する
|
||||||
|
@ -1851,7 +1906,7 @@ public class ActMain extends AppCompatActivity
|
||||||
|
|
||||||
if( result != null && result.object != null ){
|
if( result != null && result.object != null ){
|
||||||
|
|
||||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
TootResults tmp = TootResults.parse( log, access_info, access_info.host, result.object );
|
||||||
if( tmp != null ){
|
if( tmp != null ){
|
||||||
if( tmp.accounts != null && ! tmp.accounts.isEmpty() ){
|
if( tmp.accounts != null && ! tmp.accounts.isEmpty() ){
|
||||||
who_local = tmp.accounts.get( 0 );
|
who_local = tmp.accounts.get( 0 );
|
||||||
|
@ -1974,7 +2029,7 @@ public class ActMain extends AppCompatActivity
|
||||||
|
|
||||||
public void performFavourite(
|
public void performFavourite(
|
||||||
final SavedAccount access_info
|
final SavedAccount access_info
|
||||||
, final TootStatus arg_status
|
, final TootStatusLike arg_status
|
||||||
, final int nCrossAccountMode
|
, final int nCrossAccountMode
|
||||||
, final boolean bSet
|
, final boolean bSet
|
||||||
, final RelationChangedCallback callback
|
, final RelationChangedCallback callback
|
||||||
|
@ -2002,7 +2057,7 @@ public class ActMain extends AppCompatActivity
|
||||||
client.setAccount( access_info );
|
client.setAccount( access_info );
|
||||||
TootApiResult result;
|
TootApiResult result;
|
||||||
|
|
||||||
TootStatus target_status;
|
TootStatusLike target_status;
|
||||||
if( nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE ){
|
if( nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE ){
|
||||||
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
||||||
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( arg_status.url ) );
|
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( arg_status.url ) );
|
||||||
|
@ -2013,7 +2068,7 @@ public class ActMain extends AppCompatActivity
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
target_status = null;
|
target_status = null;
|
||||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
TootResults tmp = TootResults.parse( log, access_info, access_info.host,result.object );
|
||||||
if( tmp != null ){
|
if( tmp != null ){
|
||||||
if( tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
if( tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
||||||
target_status = tmp.statuses.get( 0 );
|
target_status = tmp.statuses.get( 0 );
|
||||||
|
@ -2043,7 +2098,7 @@ public class ActMain extends AppCompatActivity
|
||||||
)
|
)
|
||||||
, request_builder );
|
, request_builder );
|
||||||
if( result != null && result.object != null ){
|
if( result != null && result.object != null ){
|
||||||
new_status = TootStatus.parse( log, access_info, result.object );
|
new_status = TootStatus.parse( log, access_info, access_info.host, result.object );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -2108,7 +2163,7 @@ public class ActMain extends AppCompatActivity
|
||||||
|
|
||||||
public void performBoost(
|
public void performBoost(
|
||||||
final SavedAccount access_info
|
final SavedAccount access_info
|
||||||
, final TootStatus arg_status
|
, final TootStatusLike arg_status
|
||||||
, final int nCrossAccountMode
|
, final int nCrossAccountMode
|
||||||
, final boolean bSet
|
, final boolean bSet
|
||||||
, final boolean bConfirmed
|
, final boolean bConfirmed
|
||||||
|
@ -2172,7 +2227,7 @@ public class ActMain extends AppCompatActivity
|
||||||
|
|
||||||
TootApiResult result;
|
TootApiResult result;
|
||||||
|
|
||||||
TootStatus target_status;
|
TootStatusLike target_status;
|
||||||
if( nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE ){
|
if( nCrossAccountMode == CROSS_ACCOUNT_REMOTE_INSTANCE ){
|
||||||
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
||||||
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( arg_status.url ) );
|
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( arg_status.url ) );
|
||||||
|
@ -2183,7 +2238,7 @@ public class ActMain extends AppCompatActivity
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
target_status = null;
|
target_status = null;
|
||||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
TootResults tmp = TootResults.parse( log, access_info, access_info.host,result.object );
|
||||||
if( tmp != null ){
|
if( tmp != null ){
|
||||||
if( tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
if( tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
||||||
target_status = tmp.statuses.get( 0 );
|
target_status = tmp.statuses.get( 0 );
|
||||||
|
@ -2213,7 +2268,7 @@ public class ActMain extends AppCompatActivity
|
||||||
// reblog,unreblog のレスポンスは信用ならんのでステータスを再取得する
|
// reblog,unreblog のレスポンスは信用ならんのでステータスを再取得する
|
||||||
result = client.request( "/api/v1/statuses/" + target_status.id );
|
result = client.request( "/api/v1/statuses/" + target_status.id );
|
||||||
if( result != null && result.object != null ){
|
if( result != null && result.object != null ){
|
||||||
new_status = TootStatus.parse( log, access_info, result.object );
|
new_status = TootStatus.parse( log, access_info, access_info.host,result.object );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2276,14 +2331,18 @@ public class ActMain extends AppCompatActivity
|
||||||
public void performReply(
|
public void performReply(
|
||||||
final SavedAccount access_info
|
final SavedAccount access_info
|
||||||
, final TootStatus arg_status
|
, final TootStatus arg_status
|
||||||
, final boolean bRemote
|
|
||||||
){
|
){
|
||||||
if( ! bRemote ){
|
ActPost.open( this, REQUEST_CODE_POST, access_info.db_id, arg_status );
|
||||||
ActPost.open( this, REQUEST_CODE_POST, access_info.db_id, arg_status );
|
}
|
||||||
return;
|
|
||||||
}
|
public void performReplyRemote(
|
||||||
|
final SavedAccount access_info
|
||||||
|
,final String remote_status_url
|
||||||
|
,final long remote_status_id
|
||||||
|
){
|
||||||
|
final ProgressDialog progress = new ProgressDialog( this );
|
||||||
|
|
||||||
new AsyncTask< Void, Void, TootApiResult >() {
|
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
|
||||||
TootStatus target_status;
|
TootStatus target_status;
|
||||||
|
|
||||||
@Override protected TootApiResult doInBackground( Void... params ){
|
@Override protected TootApiResult doInBackground( Void... params ){
|
||||||
|
@ -2298,15 +2357,15 @@ public class ActMain extends AppCompatActivity
|
||||||
client.setAccount( access_info );
|
client.setAccount( access_info );
|
||||||
|
|
||||||
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
// 検索APIに他タンスのステータスのURLを投げると、自タンスのステータスを得られる
|
||||||
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( arg_status.url ) );
|
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( remote_status_url ) );
|
||||||
path = path + "&resolve=1";
|
path = path + "&resolve=1";
|
||||||
|
|
||||||
TootApiResult result = client.request( path );
|
TootApiResult result = client.request( path );
|
||||||
if( result != null && result.object != null ){
|
if( result != null && result.object != null ){
|
||||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
TootResults tmp = TootResults.parse( log, access_info, access_info.host,result.object );
|
||||||
if( tmp != null && tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
if( tmp != null && tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
||||||
target_status = tmp.statuses.get( 0 );
|
target_status = tmp.statuses.get( 0 );
|
||||||
log.d( "status id conversion %s => %s", arg_status.id, target_status.id );
|
log.d( "status id conversion %s => %s", remote_status_id, target_status.id );
|
||||||
}
|
}
|
||||||
if( target_status == null ){
|
if( target_status == null ){
|
||||||
return new TootApiResult( getString( R.string.status_id_conversion_failed ) );
|
return new TootApiResult( getString( R.string.status_id_conversion_failed ) );
|
||||||
|
@ -2322,6 +2381,7 @@ public class ActMain extends AppCompatActivity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute( TootApiResult result ){
|
protected void onPostExecute( TootApiResult result ){
|
||||||
|
progress.dismiss();
|
||||||
if( result == null ){
|
if( result == null ){
|
||||||
// cancelled.
|
// cancelled.
|
||||||
}else if( target_status != null ){
|
}else if( target_status != null ){
|
||||||
|
@ -2330,7 +2390,18 @@ public class ActMain extends AppCompatActivity
|
||||||
Utils.showToast( ActMain.this, true, result.error );
|
Utils.showToast( ActMain.this, true, result.error );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.executeOnExecutor( App1.task_executor );
|
};
|
||||||
|
|
||||||
|
progress.setIndeterminate( true );
|
||||||
|
progress.setCancelable( true );
|
||||||
|
progress.setMessage( getString(R.string.progress_synchronize_toot) );
|
||||||
|
progress.setOnCancelListener( new DialogInterface.OnCancelListener() {
|
||||||
|
@Override public void onCancel( DialogInterface dialog ){
|
||||||
|
task.cancel( true );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
progress.show();
|
||||||
|
task.executeOnExecutor( App1.task_executor );
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
@ -3251,7 +3322,7 @@ public class ActMain extends AppCompatActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void openBoostFromAnotherAccount( @NonNull final SavedAccount timeline_account, final TootStatus status ){
|
void openBoostFromAnotherAccount( @NonNull final SavedAccount timeline_account, @Nullable final TootStatusLike status ){
|
||||||
if( status == null ) return;
|
if( status == null ) return;
|
||||||
AccountPicker.pick( this, false, false
|
AccountPicker.pick( this, false, false
|
||||||
, getString( R.string.account_picker_boost )
|
, getString( R.string.account_picker_boost )
|
||||||
|
@ -3270,7 +3341,7 @@ public class ActMain extends AppCompatActivity
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
void openFavouriteFromAnotherAccount( @NonNull final SavedAccount timeline_account, final TootStatus status ){
|
void openFavouriteFromAnotherAccount( @NonNull final SavedAccount timeline_account, final TootStatusLike status ){
|
||||||
if( status == null ) return;
|
if( status == null ) return;
|
||||||
AccountPicker.pick( this, false, false
|
AccountPicker.pick( this, false, false
|
||||||
, getString( R.string.account_picker_favourite )
|
, getString( R.string.account_picker_favourite )
|
||||||
|
@ -3288,25 +3359,38 @@ public class ActMain extends AppCompatActivity
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
void openReplyFromAnotherAccount( @NonNull final SavedAccount access_info, final TootStatus status ){
|
|
||||||
if( status == null ) return;
|
void openReplyFromAnotherAccount( final TootStatusLike status){
|
||||||
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() {
|
, makeAccountListNonPseudo( log ), new AccountPicker.AccountPickerCallback() {
|
||||||
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
|
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
|
||||||
performReply(
|
if( (status instanceof TootStatus) && ai.host.equalsIgnoreCase( status.status_host ) ){
|
||||||
ai
|
performReply( ai, (TootStatus)status );
|
||||||
, status
|
}else{
|
||||||
, ! ai.host.equalsIgnoreCase( access_info.host )
|
performReplyRemote( ai,status.url,status.id );
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, TootStatus status ){
|
// void openReplyFromAnotherAccount( @NonNull final SavedAccount access_info, final String status_url,final long status_id ){
|
||||||
if( status == null ) return;
|
//
|
||||||
openFollowFromAnotherAccount( access_info, status.account );
|
// final String status_host = getHostFromStatusUrl(status_url);
|
||||||
}
|
// if( status_host ==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 ){
|
||||||
|
// performReplyRemote( ai,status_url,status_id );
|
||||||
|
// }
|
||||||
|
// } );
|
||||||
|
// }
|
||||||
|
// void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, TootStatus status ){
|
||||||
|
// if( status == null ) return;
|
||||||
|
// openFollowFromAnotherAccount( access_info, status.account );
|
||||||
|
// }
|
||||||
|
|
||||||
void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, final TootAccount account ){
|
void openFollowFromAnotherAccount( @NonNull SavedAccount access_info, final TootAccount account ){
|
||||||
if( account == null ) return;
|
if( account == null ) return;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package jp.juggler.subwaytooter;
|
package jp.juggler.subwaytooter;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
|
@ -25,14 +26,12 @@ import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
@ -47,7 +46,6 @@ import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -397,7 +395,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
|
||||||
sv = intent.getStringExtra( KEY_REPLY_STATUS );
|
sv = intent.getStringExtra( KEY_REPLY_STATUS );
|
||||||
if( sv != null ){
|
if( sv != null ){
|
||||||
try{
|
try{
|
||||||
TootStatus reply_status = TootStatus.parse( log, account, new JSONObject( sv ) );
|
TootStatus reply_status = TootStatus.parse( log, account, account.host,new JSONObject( sv ) );
|
||||||
|
|
||||||
// CW をリプライ元に合わせる
|
// CW をリプライ元に合わせる
|
||||||
if( ! TextUtils.isEmpty( reply_status.spoiler_text ) ){
|
if( ! TextUtils.isEmpty( reply_status.spoiler_text ) ){
|
||||||
|
@ -898,7 +896,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
|
||||||
|
|
||||||
TootApiResult result = client.request( path );
|
TootApiResult result = client.request( path );
|
||||||
if( result != null && result.object != null ){
|
if( result != null && result.object != null ){
|
||||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
TootResults tmp = TootResults.parse( log, access_info, access_info.host,result.object );
|
||||||
if( tmp != null && tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
if( tmp != null && tmp.statuses != null && ! tmp.statuses.isEmpty() ){
|
||||||
target_status = tmp.statuses.get( 0 );
|
target_status = tmp.statuses.get( 0 );
|
||||||
}
|
}
|
||||||
|
@ -1607,7 +1605,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
|
||||||
|
|
||||||
TootApiResult result = client.request( "/api/v1/statuses", request_builder );
|
TootApiResult result = client.request( "/api/v1/statuses", request_builder );
|
||||||
if( result != null && result.object != null ){
|
if( result != null && result.object != null ){
|
||||||
status = TootStatus.parse( log, account, result.object );
|
status = TootStatus.parse( log, account, account.host,result.object );
|
||||||
|
|
||||||
Spannable s = status.decoded_content;
|
Spannable s = status.decoded_content;
|
||||||
MyClickableSpan[] span_list = s.getSpans( 0, s.length(), MyClickableSpan.class );
|
MyClickableSpan[] span_list = s.getSpans( 0, s.length(), MyClickableSpan.class );
|
||||||
|
@ -1982,7 +1980,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append( src.substring( 0, mushroom_start ) );
|
sb.append( src.substring( 0, mushroom_start ) );
|
||||||
int new_sel_start = sb.length();
|
// int new_sel_start = sb.length();
|
||||||
sb.append( text );
|
sb.append( text );
|
||||||
int new_sel_end = sb.length();
|
int new_sel_end = sb.length();
|
||||||
sb.append( src.substring( mushroom_end ) );
|
sb.append( src.substring( mushroom_end ) );
|
||||||
|
@ -2028,6 +2026,8 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void showRecommendedPlugin( String title ){
|
private void showRecommendedPlugin( String title ){
|
||||||
String language_code = getString( R.string.language_code );
|
String language_code = getString( R.string.language_code );
|
||||||
int res_id;
|
int res_id;
|
||||||
|
@ -2038,46 +2038,37 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
|
||||||
}else{
|
}else{
|
||||||
res_id = R.raw.recommended_plugin_en;
|
res_id = R.raw.recommended_plugin_en;
|
||||||
}
|
}
|
||||||
try{
|
byte[] data = Utils.loadRawResource(this,res_id);
|
||||||
InputStream is = getResources().openRawResource( res_id );
|
if( data != null ){
|
||||||
try{
|
String text = Utils.decodeUTF8( data );
|
||||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
@SuppressLint("InflateParams")
|
||||||
IOUtils.copy( is, bao );
|
View viewRoot = getLayoutInflater().inflate( R.layout.dlg_plugin_missing, null, false );
|
||||||
String text = Utils.decodeUTF8( bao.toByteArray() );
|
|
||||||
|
TextView tvText = (TextView) viewRoot.findViewById( R.id.tvText );
|
||||||
View viewRoot = getLayoutInflater().inflate( R.layout.dlg_plugin_missing, null, false );
|
LinkClickContext lcc = new LinkClickContext() {
|
||||||
|
@Override public AcctColor findAcctColor( String url ){
|
||||||
TextView tvText = (TextView) viewRoot.findViewById( R.id.tvText );
|
return null;
|
||||||
LinkClickContext lcc = new LinkClickContext() {
|
|
||||||
@Override public AcctColor findAcctColor( String url ){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
CharSequence sv = HTMLDecoder.decodeHTML( lcc, text, false, null );
|
|
||||||
tvText.setText( sv );
|
|
||||||
tvText.setMovementMethod( LinkMovementMethod.getInstance() );
|
|
||||||
|
|
||||||
TextView tvTitle = (TextView) viewRoot.findViewById( R.id.tvTitle );
|
|
||||||
if( TextUtils.isEmpty( title ) ){
|
|
||||||
tvTitle.setVisibility( View.GONE );
|
|
||||||
}else{
|
|
||||||
tvTitle.setText( title );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
CharSequence sv = HTMLDecoder.decodeHTML( lcc, text, false, null );
|
||||||
|
tvText.setText( sv );
|
||||||
|
tvText.setMovementMethod( LinkMovementMethod.getInstance() );
|
||||||
|
|
||||||
|
TextView tvTitle = (TextView) viewRoot.findViewById( R.id.tvTitle );
|
||||||
|
if( TextUtils.isEmpty( title ) ){
|
||||||
|
tvTitle.setVisibility( View.GONE );
|
||||||
|
}else{
|
||||||
|
tvTitle.setText( title );
|
||||||
|
|
||||||
new AlertDialog.Builder( this )
|
|
||||||
.setView( viewRoot )
|
|
||||||
.setCancelable( true )
|
|
||||||
.setNeutralButton( R.string.close, null )
|
|
||||||
.show();
|
|
||||||
|
|
||||||
}finally{
|
|
||||||
IOUtils.closeQuietly( is );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}catch( Throwable ex ){
|
new AlertDialog.Builder( this )
|
||||||
ex.printStackTrace();
|
.setView( viewRoot )
|
||||||
|
.setCancelable( true )
|
||||||
|
.setNeutralButton( R.string.close, null )
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final MyClickableSpan.LinkClickCallback link_click_listener = new MyClickableSpan.LinkClickCallback() {
|
final MyClickableSpan.LinkClickCallback link_click_listener = new MyClickableSpan.LinkClickCallback() {
|
||||||
|
|
|
@ -13,6 +13,8 @@ import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.entity.MSPToot;
|
||||||
import jp.juggler.subwaytooter.table.MutedWord;
|
import jp.juggler.subwaytooter.table.MutedWord;
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||||
|
@ -25,7 +27,7 @@ public class ActText extends AppCompatActivity implements View.OnClickListener {
|
||||||
static final String EXTRA_TEXT = "text";
|
static final String EXTRA_TEXT = "text";
|
||||||
static final String EXTRA_CONTENT_START = "content_start";
|
static final String EXTRA_CONTENT_START = "content_start";
|
||||||
|
|
||||||
static void encodeStatus( Intent intent, Context context, SavedAccount access_info, TootStatus status ){
|
static void encodeStatus( Intent intent, Context context, SavedAccount access_info, TootStatusLike status ){
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append( context.getString( R.string.send_header_url ) );
|
sb.append( context.getString( R.string.send_header_url ) );
|
||||||
sb.append( ": " );
|
sb.append( ": " );
|
||||||
|
@ -33,7 +35,15 @@ public class ActText extends AppCompatActivity implements View.OnClickListener {
|
||||||
sb.append( "\n" );
|
sb.append( "\n" );
|
||||||
sb.append( context.getString( R.string.send_header_date ) );
|
sb.append( context.getString( R.string.send_header_date ) );
|
||||||
sb.append( ": " );
|
sb.append( ": " );
|
||||||
sb.append( TootStatus.formatTime( status.time_created_at ) );
|
|
||||||
|
if( status instanceof TootStatus ){
|
||||||
|
TootStatus ts = (TootStatus)status;
|
||||||
|
sb.append( TootStatus.formatTime( ts.time_created_at ) );
|
||||||
|
}else if( status instanceof MSPToot ){
|
||||||
|
MSPToot ts = (MSPToot)status;
|
||||||
|
sb.append( ts.created_at );
|
||||||
|
}
|
||||||
|
|
||||||
sb.append( "\n" );
|
sb.append( "\n" );
|
||||||
sb.append( context.getString( R.string.send_header_from_acct ) );
|
sb.append( context.getString( R.string.send_header_from_acct ) );
|
||||||
sb.append( ": " );
|
sb.append( ": " );
|
||||||
|
@ -63,7 +73,7 @@ public class ActText extends AppCompatActivity implements View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void open( ActMain activity, SavedAccount access_info, TootStatus status ){
|
public static void open( ActMain activity, SavedAccount access_info, TootStatusLike status ){
|
||||||
Intent intent = new Intent( activity, ActText.class );
|
Intent intent = new Intent( activity, ActText.class );
|
||||||
encodeStatus( intent,activity, access_info, status );
|
encodeStatus( intent,activity, access_info, status );
|
||||||
|
|
||||||
|
|
|
@ -636,7 +636,7 @@ public class AlarmService extends IntentService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TootNotification notification = TootNotification.parse( log, account, src );
|
TootNotification notification = TootNotification.parse( log, account,account.host ,src );
|
||||||
if( notification == null ){
|
if( notification == null ){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,6 +328,7 @@ public class AppDataExporter {
|
||||||
case Pref.KEY_STREAM_LISTENER_SECRET:
|
case Pref.KEY_STREAM_LISTENER_SECRET:
|
||||||
case Pref.KEY_STREAM_LISTENER_CONFIG_DATA:
|
case Pref.KEY_STREAM_LISTENER_CONFIG_DATA:
|
||||||
case Pref.KEY_CLIENT_NAME:
|
case Pref.KEY_CLIENT_NAME:
|
||||||
|
case Pref.KEY_MASTODON_SEARCH_PORTAL_USER_TOKEN:
|
||||||
String sv = reader.nextString();
|
String sv = reader.nextString();
|
||||||
e.putString( k, sv );
|
e.putString( k, sv );
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.LinkedList;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
import jp.juggler.subwaytooter.util.MyClickableSpan;
|
import jp.juggler.subwaytooter.util.MyClickableSpan;
|
||||||
|
@ -134,34 +135,34 @@ class AppState {
|
||||||
|
|
||||||
private final HashSet< String > map_busy_fav = new HashSet<>();
|
private final HashSet< String > map_busy_fav = new HashSet<>();
|
||||||
|
|
||||||
boolean isBusyFav( SavedAccount account, TootStatus status ){
|
boolean isBusyFav( SavedAccount account, @NonNull TootStatusLike status ){
|
||||||
String busy_key = account.host + ":" + status.id;
|
final String key = account.acct +":" + status.status_host + ":" + status.id;
|
||||||
return map_busy_fav.contains( busy_key );
|
return map_busy_fav.contains( key );
|
||||||
}
|
}
|
||||||
boolean setBusyFav( SavedAccount account, TootStatus status ){
|
boolean setBusyFav( SavedAccount account, @NonNull TootStatusLike status ){
|
||||||
final String busy_key = account.acct +":" + status.uri;
|
final String key = account.acct +":" + status.status_host + ":" + status.id;
|
||||||
return map_busy_fav.add( busy_key );
|
return map_busy_fav.add( key );
|
||||||
}
|
}
|
||||||
boolean resetBusyFav( SavedAccount account, TootStatus status ){
|
boolean resetBusyFav( SavedAccount account, @NonNull TootStatusLike status ){
|
||||||
final String busy_key = account.acct +":" + status.uri;
|
final String key = account.acct +":" + status.status_host + ":" + status.id;
|
||||||
return map_busy_fav.remove( busy_key );
|
return map_busy_fav.remove( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
private final HashSet< String > map_busy_boost = new HashSet<>();
|
private final HashSet< String > map_busy_boost = new HashSet<>();
|
||||||
|
|
||||||
boolean isBusyBoost( @NonNull SavedAccount account, @NonNull TootStatus status ){
|
boolean isBusyBoost( @NonNull SavedAccount account, @NonNull TootStatusLike status ){
|
||||||
final String busy_key = account.acct +":" + status.uri;
|
final String key = account.acct +":" + status.status_host + ":" + status.id;
|
||||||
return map_busy_boost.contains( busy_key );
|
return map_busy_boost.contains( key );
|
||||||
}
|
}
|
||||||
boolean setBusyBoost( SavedAccount account, TootStatus status ){
|
boolean setBusyBoost( SavedAccount account, @NonNull TootStatusLike status ){
|
||||||
final String busy_key = account.acct +":" + status.uri;
|
final String key = account.acct +":" + status.status_host + ":" + status.id;
|
||||||
return map_busy_boost.add( busy_key );
|
return map_busy_boost.add( key );
|
||||||
}
|
}
|
||||||
boolean resetBusyBoost( SavedAccount account, TootStatus status ){
|
boolean resetBusyBoost( SavedAccount account, @NonNull TootStatusLike status ){
|
||||||
final String busy_key = account.acct +":" + status.uri;
|
final String key = account.acct +":" + status.status_host + ":" + status.id;
|
||||||
return map_busy_boost.remove( busy_key );
|
return map_busy_boost.remove( key );
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ import jp.juggler.subwaytooter.api.entity.TootReport;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootResults;
|
import jp.juggler.subwaytooter.api.entity.TootResults;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootTag;
|
import jp.juggler.subwaytooter.api.entity.TootTag;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.MSPApiResult;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.MSPClient;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.entity.MSPToot;
|
||||||
import jp.juggler.subwaytooter.table.AcctColor;
|
import jp.juggler.subwaytooter.table.AcctColor;
|
||||||
import jp.juggler.subwaytooter.table.AcctSet;
|
import jp.juggler.subwaytooter.table.AcctSet;
|
||||||
import jp.juggler.subwaytooter.table.MutedApp;
|
import jp.juggler.subwaytooter.table.MutedApp;
|
||||||
|
@ -162,6 +165,7 @@ class Column implements StreamReader.Callback {
|
||||||
static final int TYPE_BOOSTED_BY = 14;
|
static final int TYPE_BOOSTED_BY = 14;
|
||||||
static final int TYPE_FAVOURITED_BY = 15;
|
static final int TYPE_FAVOURITED_BY = 15;
|
||||||
static final int TYPE_DOMAIN_BLOCKS = 16;
|
static final int TYPE_DOMAIN_BLOCKS = 16;
|
||||||
|
static final int TYPE_SEARCH_PORTAL = 17;
|
||||||
|
|
||||||
@NonNull final Context context;
|
@NonNull final Context context;
|
||||||
@NonNull private final AppState app_state;
|
@NonNull private final AppState app_state;
|
||||||
|
@ -229,7 +233,10 @@ class Column implements StreamReader.Callback {
|
||||||
this.search_query = (String) getParamAt( params, 0 );
|
this.search_query = (String) getParamAt( params, 0 );
|
||||||
this.search_resolve = (Boolean) getParamAt( params, 1 );
|
this.search_resolve = (Boolean) getParamAt( params, 1 );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
this.search_query = (String) getParamAt( params, 0 );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -271,6 +278,9 @@ class Column implements StreamReader.Callback {
|
||||||
item.put( KEY_SEARCH_QUERY, search_query );
|
item.put( KEY_SEARCH_QUERY, search_query );
|
||||||
item.put( KEY_SEARCH_RESOLVE, search_resolve );
|
item.put( KEY_SEARCH_RESOLVE, search_resolve );
|
||||||
break;
|
break;
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
item.put( KEY_SEARCH_QUERY, search_query );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 以下は保存には必要ないが、カラムリスト画面で使う
|
// 以下は保存には必要ないが、カラムリスト画面で使う
|
||||||
|
@ -286,9 +296,15 @@ class Column implements StreamReader.Callback {
|
||||||
this.app_state = app_state;
|
this.app_state = app_state;
|
||||||
this.context = app_state.context;
|
this.context = app_state.context;
|
||||||
|
|
||||||
SavedAccount ac = SavedAccount.loadAccount( log, src.optLong( KEY_ACCOUNT_ROW_ID ) );
|
long account_db_id = src.optLong( KEY_ACCOUNT_ROW_ID );
|
||||||
if( ac == null ) throw new RuntimeException( "missing account" );
|
if( account_db_id >= 0 ){
|
||||||
this.access_info = ac;
|
SavedAccount ac = SavedAccount.loadAccount( log, account_db_id );
|
||||||
|
if( ac == null ) throw new RuntimeException( "missing account" );
|
||||||
|
this.access_info = ac;
|
||||||
|
}else{
|
||||||
|
this.access_info = SavedAccount.getNA();
|
||||||
|
}
|
||||||
|
|
||||||
this.column_type = src.optInt( KEY_TYPE );
|
this.column_type = src.optInt( KEY_TYPE );
|
||||||
this.dont_close = src.optBoolean( KEY_DONT_CLOSE );
|
this.dont_close = src.optBoolean( KEY_DONT_CLOSE );
|
||||||
this.with_attachment = src.optBoolean( KEY_WITH_ATTACHMENT );
|
this.with_attachment = src.optBoolean( KEY_WITH_ATTACHMENT );
|
||||||
|
@ -328,7 +344,9 @@ class Column implements StreamReader.Callback {
|
||||||
this.search_query = src.optString( KEY_SEARCH_QUERY );
|
this.search_query = src.optString( KEY_SEARCH_QUERY );
|
||||||
this.search_resolve = src.optBoolean( KEY_SEARCH_RESOLVE, false );
|
this.search_resolve = src.optBoolean( KEY_SEARCH_RESOLVE, false );
|
||||||
break;
|
break;
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
this.search_query = src.optString( KEY_SEARCH_QUERY );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -375,7 +393,13 @@ class Column implements StreamReader.Callback {
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
try{
|
||||||
|
String q = (String) getParamAt( params, 0 );
|
||||||
|
return Utils.equalsNullable( q, this.search_query );
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +441,13 @@ class Column implements StreamReader.Callback {
|
||||||
return getColumnTypeName( context, column_type );
|
return getColumnTypeName( context, column_type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
if( bLong ){
|
||||||
|
return context.getString( R.string.toot_search_of, search_query );
|
||||||
|
}else{
|
||||||
|
return getColumnTypeName( context, column_type );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,6 +502,9 @@ class Column implements StreamReader.Callback {
|
||||||
case TYPE_SEARCH:
|
case TYPE_SEARCH:
|
||||||
return context.getString( R.string.search );
|
return context.getString( R.string.search );
|
||||||
|
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
return context.getString( R.string.toot_search );
|
||||||
|
|
||||||
case TYPE_FOLLOW_REQUESTS:
|
case TYPE_FOLLOW_REQUESTS:
|
||||||
return context.getString( R.string.follow_requests );
|
return context.getString( R.string.follow_requests );
|
||||||
}
|
}
|
||||||
|
@ -525,6 +559,9 @@ class Column implements StreamReader.Callback {
|
||||||
case TYPE_SEARCH:
|
case TYPE_SEARCH:
|
||||||
return R.attr.ic_search;
|
return R.attr.ic_search;
|
||||||
|
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
return R.attr.ic_search;
|
||||||
|
|
||||||
case TYPE_FOLLOW_REQUESTS:
|
case TYPE_FOLLOW_REQUESTS:
|
||||||
return R.attr.ic_account_add;
|
return R.attr.ic_account_add;
|
||||||
}
|
}
|
||||||
|
@ -580,7 +617,7 @@ class Column implements StreamReader.Callback {
|
||||||
for( Object o : list_data ){
|
for( Object o : list_data ){
|
||||||
if( o instanceof TootStatus ){
|
if( o instanceof TootStatus ){
|
||||||
TootStatus item = (TootStatus) o;
|
TootStatus item = (TootStatus) o;
|
||||||
if( (item.account != null && item.account.id == who_id)
|
if( ( item.account != null && item.account.id == who_id )
|
||||||
|| ( item.reblog != null && item.reblog.account != null && item.reblog.account.id == who_id )
|
|| ( item.reblog != null && item.reblog.account != null && item.reblog.account.id == who_id )
|
||||||
){
|
){
|
||||||
continue;
|
continue;
|
||||||
|
@ -590,7 +627,8 @@ class Column implements StreamReader.Callback {
|
||||||
TootNotification item = (TootNotification) o;
|
TootNotification item = (TootNotification) o;
|
||||||
if( item.account.id == who_id ) continue;
|
if( item.account.id == who_id ) continue;
|
||||||
if( item.status != null ){
|
if( item.status != null ){
|
||||||
if( (item.status.account != null && item.status.account.id == who_id) ) continue;
|
if( ( item.status.account != null && item.status.account.id == who_id ) )
|
||||||
|
continue;
|
||||||
if( item.status.reblog != null && item.status.reblog.account != null && item.status.reblog.account.id == who_id )
|
if( item.status.reblog != null && item.status.reblog.account != null && item.status.reblog.account.id == who_id )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -739,8 +777,9 @@ class Column implements StreamReader.Callback {
|
||||||
for( Object o : list_data ){
|
for( Object o : list_data ){
|
||||||
if( o instanceof TootStatus ){
|
if( o instanceof TootStatus ){
|
||||||
TootStatus item = (TootStatus) o;
|
TootStatus item = (TootStatus) o;
|
||||||
if( item.account != null && reDomain.matcher( item.account.acct ).find() ) continue;
|
if( item.account != null && reDomain.matcher( item.account.acct ).find() )
|
||||||
if( item.reblog != null && item.reblog.account !=null && reDomain.matcher( item.reblog.account.acct ).find() )
|
continue;
|
||||||
|
if( item.reblog != null && item.reblog.account != null && reDomain.matcher( item.reblog.account.acct ).find() )
|
||||||
continue;
|
continue;
|
||||||
}else if( o instanceof TootNotification ){
|
}else if( o instanceof TootNotification ){
|
||||||
TootNotification item = (TootNotification) o;
|
TootNotification item = (TootNotification) o;
|
||||||
|
@ -748,8 +787,9 @@ class Column implements StreamReader.Callback {
|
||||||
if( reDomain.matcher( item.account.acct ).find() ) continue;
|
if( reDomain.matcher( item.account.acct ).find() ) continue;
|
||||||
}
|
}
|
||||||
if( item.status != null ){
|
if( item.status != null ){
|
||||||
if( item.status.account != null && reDomain.matcher( item.status.account.acct ).find() ) continue;
|
if( item.status.account != null && reDomain.matcher( item.status.account.acct ).find() )
|
||||||
if( item.status.reblog != null && item.status.reblog.account !=null && reDomain.matcher( item.status.reblog.account.acct ).find() )
|
continue;
|
||||||
|
if( item.status.reblog != null && item.status.reblog.account != null && reDomain.matcher( item.status.reblog.account.acct ).find() )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1022,7 +1062,7 @@ class Column implements StreamReader.Callback {
|
||||||
if( result != null && result.array != null ){
|
if( result != null && result.array != null ){
|
||||||
saveRange( result, true, true );
|
saveRange( result, true, true );
|
||||||
//
|
//
|
||||||
TootStatus.List src = TootStatus.parseList( log, access_info, result.array );
|
TootStatus.List src = TootStatus.parseList( log, access_info, access_info.host,result.array );
|
||||||
list_tmp = new ArrayList<>( src.size() );
|
list_tmp = new ArrayList<>( src.size() );
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
//
|
//
|
||||||
|
@ -1059,7 +1099,7 @@ class Column implements StreamReader.Callback {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
src = TootStatus.parseList( log, access_info, result2.array );
|
src = TootStatus.parseList( log, access_info, access_info.host,result2.array );
|
||||||
|
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
|
|
||||||
|
@ -1106,7 +1146,7 @@ class Column implements StreamReader.Callback {
|
||||||
TootApiResult result = client.request( path_base );
|
TootApiResult result = client.request( path_base );
|
||||||
if( result != null ){
|
if( result != null ){
|
||||||
saveRange( result, true, true );
|
saveRange( result, true, true );
|
||||||
TootNotification.List src = TootNotification.parseList( log, access_info, result.array );
|
TootNotification.List src = TootNotification.parseList( log, access_info, access_info.host, result.array );
|
||||||
|
|
||||||
list_tmp = new ArrayList<>();
|
list_tmp = new ArrayList<>();
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
|
@ -1223,7 +1263,7 @@ class Column implements StreamReader.Callback {
|
||||||
result = client.request(
|
result = client.request(
|
||||||
String.format( Locale.JAPAN, PATH_STATUSES, status_id ) );
|
String.format( Locale.JAPAN, PATH_STATUSES, status_id ) );
|
||||||
if( result == null || result.object == null ) return result;
|
if( result == null || result.object == null ) return result;
|
||||||
TootStatus target_status = TootStatus.parse( log, access_info, result.object );
|
TootStatus target_status = TootStatus.parse( log, access_info, access_info.host,result.object );
|
||||||
target_status.conversation_main = true;
|
target_status.conversation_main = true;
|
||||||
|
|
||||||
// 前後の会話
|
// 前後の会話
|
||||||
|
@ -1232,13 +1272,13 @@ class Column implements StreamReader.Callback {
|
||||||
if( result == null || result.object == null ) return result;
|
if( result == null || result.object == null ) return result;
|
||||||
|
|
||||||
// 一つのリストにまとめる
|
// 一つのリストにまとめる
|
||||||
TootContext context = TootContext.parse( log, access_info, result.object );
|
TootContext conversation_context = TootContext.parse( log, access_info, access_info.host,result.object );
|
||||||
list_tmp = new ArrayList<>( 1 + context.ancestors.size() + context.descendants.size() );
|
list_tmp = new ArrayList<>( 1 + conversation_context.ancestors.size() + conversation_context.descendants.size() );
|
||||||
if( context.ancestors != null )
|
if( conversation_context.ancestors != null )
|
||||||
addWithFilter( list_tmp, context.ancestors );
|
addWithFilter( list_tmp, conversation_context.ancestors );
|
||||||
list_tmp.add( target_status );
|
list_tmp.add( target_status );
|
||||||
if( context.descendants != null )
|
if( conversation_context.descendants != null )
|
||||||
addWithFilter( list_tmp, context.descendants );
|
addWithFilter( list_tmp, conversation_context.descendants );
|
||||||
|
|
||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
|
@ -1250,7 +1290,7 @@ class Column implements StreamReader.Callback {
|
||||||
result = client.request( path );
|
result = client.request( path );
|
||||||
if( result == null || result.object == null ) return result;
|
if( result == null || result.object == null ) return result;
|
||||||
|
|
||||||
TootResults tmp = TootResults.parse( log, access_info, result.object );
|
TootResults tmp = TootResults.parse( log, access_info, access_info.host,result.object );
|
||||||
if( tmp != null ){
|
if( tmp != null ){
|
||||||
list_tmp = new ArrayList<>();
|
list_tmp = new ArrayList<>();
|
||||||
list_tmp.addAll( tmp.hashtags );
|
list_tmp.addAll( tmp.hashtags );
|
||||||
|
@ -1258,7 +1298,45 @@ class Column implements StreamReader.Callback {
|
||||||
list_tmp.addAll( tmp.statuses );
|
list_tmp.addAll( tmp.statuses );
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
|
||||||
|
max_id = "";
|
||||||
|
String q = search_query.trim();
|
||||||
|
if( q.length() <= 0 ){
|
||||||
|
list_tmp = new ArrayList<>();
|
||||||
|
result = new TootApiResult( context.getString( R.string.list_empty ) );
|
||||||
|
}else{
|
||||||
|
result = MSPClient.search( context, search_query, max_id, new MSPClient.Callback() {
|
||||||
|
@Override
|
||||||
|
public boolean isApiCancelled(){
|
||||||
|
return isCancelled() || is_dispose.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publishApiProgress( final String s ){
|
||||||
|
Utils.runOnMainThread( new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run(){
|
||||||
|
if( isCancelled() ) return;
|
||||||
|
task_progress = s;
|
||||||
|
fireShowContent();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
if( result != null && result.array != null ){
|
||||||
|
// max_id の更新
|
||||||
|
max_id = MSPClient.getMaxId( result.array, max_id );
|
||||||
|
// リストデータの用意
|
||||||
|
MSPToot.List search_result = MSPToot.parseList( log, access_info, result.array );
|
||||||
|
if( search_result != null ){
|
||||||
|
list_tmp = new ArrayList<>();
|
||||||
|
list_tmp.addAll( search_result );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
try{
|
try{
|
||||||
|
@ -1749,7 +1827,7 @@ class Column implements StreamReader.Callback {
|
||||||
if( result != null && result.array != null ){
|
if( result != null && result.array != null ){
|
||||||
saveRange( result, bBottom, ! bBottom );
|
saveRange( result, bBottom, ! bBottom );
|
||||||
list_tmp = new ArrayList<>();
|
list_tmp = new ArrayList<>();
|
||||||
TootNotification.List src = TootNotification.parseList( log, access_info, result.array );
|
TootNotification.List src = TootNotification.parseList( log, access_info,access_info.host, result.array );
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
|
|
||||||
if( ! src.isEmpty() ){
|
if( ! src.isEmpty() ){
|
||||||
|
@ -1793,7 +1871,7 @@ class Column implements StreamReader.Callback {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
src = TootNotification.parseList( log, access_info, result2.array );
|
src = TootNotification.parseList( log, access_info, access_info.host,result2.array );
|
||||||
if( ! src.isEmpty() ){
|
if( ! src.isEmpty() ){
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
AlarmService.injectData( context, access_info.db_id, src );
|
AlarmService.injectData( context, access_info.db_id, src );
|
||||||
|
@ -1815,7 +1893,7 @@ class Column implements StreamReader.Callback {
|
||||||
TootApiResult result = client.request( addRange( bBottom, path_base ) );
|
TootApiResult result = client.request( addRange( bBottom, path_base ) );
|
||||||
if( result != null && result.array != null ){
|
if( result != null && result.array != null ){
|
||||||
saveRange( result, bBottom, ! bBottom );
|
saveRange( result, bBottom, ! bBottom );
|
||||||
TootStatus.List src = TootStatus.parseList( log, access_info, result.array );
|
TootStatus.List src = TootStatus.parseList( log, access_info, access_info.host,result.array );
|
||||||
list_tmp = new ArrayList<>();
|
list_tmp = new ArrayList<>();
|
||||||
|
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
|
@ -1859,7 +1937,7 @@ class Column implements StreamReader.Callback {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
src = TootStatus.parseList( log, access_info, result2.array );
|
src = TootStatus.parseList( log, access_info, access_info.host,result2.array );
|
||||||
|
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
|
|
||||||
|
@ -1915,7 +1993,7 @@ class Column implements StreamReader.Callback {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
src = TootStatus.parseList( log, access_info, result2.array );
|
src = TootStatus.parseList( log, access_info, access_info.host,result2.array );
|
||||||
addWithFilter( list_tmp, src );
|
addWithFilter( list_tmp, src );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2016,6 +2094,49 @@ class Column implements StreamReader.Callback {
|
||||||
case TYPE_HASHTAG:
|
case TYPE_HASHTAG:
|
||||||
return getStatusList( client,
|
return getStatusList( client,
|
||||||
String.format( Locale.JAPAN, PATH_HASHTAG, Uri.encode( hashtag ) ) );
|
String.format( Locale.JAPAN, PATH_HASHTAG, Uri.encode( hashtag ) ) );
|
||||||
|
|
||||||
|
case TYPE_SEARCH_PORTAL:
|
||||||
|
|
||||||
|
if(!bBottom){
|
||||||
|
return new TootApiResult( "head of list.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TootApiResult result;
|
||||||
|
String q = search_query.trim();
|
||||||
|
if( q.length() <= 0 ){
|
||||||
|
list_tmp = new ArrayList<>();
|
||||||
|
result = new TootApiResult( context.getString( R.string.list_empty ) );
|
||||||
|
}else{
|
||||||
|
result = MSPClient.search( context, search_query, max_id, new MSPClient.Callback() {
|
||||||
|
@Override
|
||||||
|
public boolean isApiCancelled(){
|
||||||
|
return isCancelled() || is_dispose.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publishApiProgress( final String s ){
|
||||||
|
Utils.runOnMainThread( new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run(){
|
||||||
|
if( isCancelled() ) return;
|
||||||
|
task_progress = s;
|
||||||
|
fireShowContent();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
if( result != null && result.array != null ){
|
||||||
|
// max_id の更新
|
||||||
|
max_id = MSPClient.getMaxId( result.array, max_id );
|
||||||
|
// リストデータの用意
|
||||||
|
MSPToot.List search_result = MSPToot.parseList( log, access_info, result.array );
|
||||||
|
if( search_result != null ){
|
||||||
|
list_tmp = new ArrayList<>();
|
||||||
|
list_tmp.addAll( search_result );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
try{
|
try{
|
||||||
|
@ -2271,7 +2392,7 @@ class Column implements StreamReader.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
result = r2;
|
result = r2;
|
||||||
TootNotification.List src = TootNotification.parseList( log, access_info, r2.array );
|
TootNotification.List src = TootNotification.parseList( log, access_info, access_info.host,r2.array );
|
||||||
|
|
||||||
if( src.isEmpty() ){
|
if( src.isEmpty() ){
|
||||||
log.d( "gap-notification: empty." );
|
log.d( "gap-notification: empty." );
|
||||||
|
@ -2327,7 +2448,7 @@ class Column implements StreamReader.Callback {
|
||||||
// 成功した場合はそれを返したい
|
// 成功した場合はそれを返したい
|
||||||
result = r2;
|
result = r2;
|
||||||
|
|
||||||
TootStatus.List src = TootStatus.parseList( log, access_info, r2.array );
|
TootStatus.List src = TootStatus.parseList( log, access_info,access_info.host, r2.array );
|
||||||
if( src.size() == 0 ){
|
if( src.size() == 0 ){
|
||||||
// 直前の取得でカラのデータが帰ってきたら終了
|
// 直前の取得でカラのデータが帰ってきたら終了
|
||||||
log.d( "gap-statuses: empty." );
|
log.d( "gap-statuses: empty." );
|
||||||
|
@ -2698,7 +2819,8 @@ class Column implements StreamReader.Callback {
|
||||||
}else if( o instanceof TootStatus ){
|
}else if( o instanceof TootStatus ){
|
||||||
TootStatus status = (TootStatus) o;
|
TootStatus status = (TootStatus) o;
|
||||||
if( column_type == TYPE_NOTIFICATIONS ) return;
|
if( column_type == TYPE_NOTIFICATIONS ) return;
|
||||||
if( column_type == TYPE_LOCAL && status.account != null && status.account.acct.indexOf( '@' ) != - 1 ) return;
|
if( column_type == TYPE_LOCAL && status.account != null && status.account.acct.indexOf( '@' ) != - 1 )
|
||||||
|
return;
|
||||||
if( isFiltered( status ) ) return;
|
if( isFiltered( status ) ) return;
|
||||||
|
|
||||||
if( this.enable_speech ){
|
if( this.enable_speech ){
|
||||||
|
@ -2788,6 +2910,9 @@ class Column implements StreamReader.Callback {
|
||||||
// リフレッシュしてからストリーミング開始
|
// リフレッシュしてからストリーミング開始
|
||||||
log.d( "onResume: start auto refresh." );
|
log.d( "onResume: start auto refresh." );
|
||||||
startRefresh( true, false, - 1L, - 1 );
|
startRefresh( true, false, - 1L, - 1 );
|
||||||
|
}else if( column_type == TYPE_SEARCH || column_type == TYPE_SEARCH_PORTAL ){
|
||||||
|
// 検索カラムはリフレッシュもストリーミングもないが、resumeのタイミングでリストの再描画を行いたい
|
||||||
|
fireShowContent();
|
||||||
}else{
|
}else{
|
||||||
// ギャップつきでストリーミング開始
|
// ギャップつきでストリーミング開始
|
||||||
log.d( "onResume: start streaming with gap." );
|
log.d( "onResume: start streaming with gap." );
|
||||||
|
|
|
@ -9,6 +9,8 @@ import android.support.v4.view.ViewCompat;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.text.method.MovementMethod;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
@ -27,7 +29,9 @@ import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirec
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.table.AcctColor;
|
import jp.juggler.subwaytooter.table.AcctColor;
|
||||||
|
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
import jp.juggler.subwaytooter.view.MyLinkMovementMethod;
|
||||||
import jp.juggler.subwaytooter.view.MyListView;
|
import jp.juggler.subwaytooter.view.MyListView;
|
||||||
import jp.juggler.subwaytooter.util.ScrollPosition;
|
import jp.juggler.subwaytooter.util.ScrollPosition;
|
||||||
import jp.juggler.subwaytooter.util.Utils;
|
import jp.juggler.subwaytooter.util.Utils;
|
||||||
|
@ -81,6 +85,8 @@ class ColumnViewHolder
|
||||||
private final View llRegexFilter;
|
private final View llRegexFilter;
|
||||||
private final Button btnDeleteNotification;
|
private final Button btnDeleteNotification;
|
||||||
|
|
||||||
|
private final TextView tvSearchDesc;
|
||||||
|
|
||||||
ColumnViewHolder( ActMain arg_activity, View root ){
|
ColumnViewHolder( ActMain arg_activity, View root ){
|
||||||
this.activity = arg_activity;
|
this.activity = arg_activity;
|
||||||
|
|
||||||
|
@ -137,8 +143,8 @@ class ColumnViewHolder
|
||||||
etRegexFilter = (EditText) root.findViewById( R.id.etRegexFilter );
|
etRegexFilter = (EditText) root.findViewById( R.id.etRegexFilter );
|
||||||
llRegexFilter = root.findViewById( R.id.llRegexFilter );
|
llRegexFilter = root.findViewById( R.id.llRegexFilter );
|
||||||
tvRegexFilterError = (TextView) root.findViewById( R.id.tvRegexFilterError );
|
tvRegexFilterError = (TextView) root.findViewById( R.id.tvRegexFilterError );
|
||||||
|
|
||||||
|
|
||||||
|
tvSearchDesc = (TextView) root.findViewById( R.id.tvSearchDesc );
|
||||||
|
|
||||||
btnDeleteNotification = (Button) root.findViewById( R.id.btnDeleteNotification );
|
btnDeleteNotification = (Button) root.findViewById( R.id.btnDeleteNotification );
|
||||||
|
|
||||||
|
@ -223,7 +229,7 @@ class ColumnViewHolder
|
||||||
|
|
||||||
private boolean loading_busy;
|
private boolean loading_busy;
|
||||||
|
|
||||||
void onPageCreate( Column column, int page_idx, int page_count ){
|
void onPageCreate( @NonNull Column column, int page_idx, int page_count ){
|
||||||
loading_busy = true;
|
loading_busy = true;
|
||||||
try{
|
try{
|
||||||
this.column = column;
|
this.column = column;
|
||||||
|
@ -250,6 +256,7 @@ class ColumnViewHolder
|
||||||
bAllowFilter = true;
|
bAllowFilter = true;
|
||||||
break;
|
break;
|
||||||
case Column.TYPE_SEARCH:
|
case Column.TYPE_SEARCH:
|
||||||
|
case Column.TYPE_SEARCH_PORTAL:
|
||||||
case Column.TYPE_CONVERSATION:
|
case Column.TYPE_CONVERSATION:
|
||||||
case Column.TYPE_REPORTS:
|
case Column.TYPE_REPORTS:
|
||||||
case Column.TYPE_BLOCKS:
|
case Column.TYPE_BLOCKS:
|
||||||
|
@ -299,7 +306,8 @@ class ColumnViewHolder
|
||||||
vg( llRegexFilter, bAllowFilter );
|
vg( llRegexFilter, bAllowFilter );
|
||||||
|
|
||||||
vg( btnDeleteNotification, column.column_type == Column.TYPE_NOTIFICATIONS );
|
vg( btnDeleteNotification, column.column_type == Column.TYPE_NOTIFICATIONS );
|
||||||
vg( llSearch, column.column_type == Column.TYPE_SEARCH );
|
vg( llSearch, (column.column_type == Column.TYPE_SEARCH || column.column_type == Column.TYPE_SEARCH_PORTAL ) );
|
||||||
|
vg( cbResolve, (column.column_type == Column.TYPE_SEARCH ) );
|
||||||
|
|
||||||
// tvRegexFilterErrorの表示を更新
|
// tvRegexFilterErrorの表示を更新
|
||||||
if( bAllowFilter ){
|
if( bAllowFilter ){
|
||||||
|
@ -307,12 +315,32 @@ class ColumnViewHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( column.column_type ){
|
switch( column.column_type ){
|
||||||
|
default:
|
||||||
|
swipyRefreshLayout.setEnabled( true );
|
||||||
|
swipyRefreshLayout.setDirection( SwipyRefreshLayoutDirection.BOTH );
|
||||||
|
break;
|
||||||
|
|
||||||
case Column.TYPE_CONVERSATION:
|
case Column.TYPE_CONVERSATION:
|
||||||
case Column.TYPE_SEARCH:
|
case Column.TYPE_SEARCH:
|
||||||
swipyRefreshLayout.setEnabled( false );
|
swipyRefreshLayout.setEnabled( false );
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
|
case Column.TYPE_SEARCH_PORTAL:
|
||||||
swipyRefreshLayout.setEnabled( true );
|
swipyRefreshLayout.setEnabled( true );
|
||||||
|
swipyRefreshLayout.setDirection( SwipyRefreshLayoutDirection.BOTTOM );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( column.column_type ){
|
||||||
|
default:
|
||||||
|
tvSearchDesc.setVisibility( View.GONE );
|
||||||
|
break;
|
||||||
|
case Column.TYPE_SEARCH:
|
||||||
|
showSearchDesc( activity.getString( R.string.search_desc_mastodon_api ) );
|
||||||
|
break;
|
||||||
|
case Column.TYPE_SEARCH_PORTAL:
|
||||||
|
showSearchDesc( getSearchDescPortal() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,6 +359,27 @@ class ColumnViewHolder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getSearchDescPortal(){
|
||||||
|
String language_code = activity.getString( R.string.language_code );
|
||||||
|
int res_id;
|
||||||
|
if( "ja".equals( language_code ) ){
|
||||||
|
res_id = R.raw.search_desc_portal_ja;
|
||||||
|
}else{
|
||||||
|
res_id = R.raw.search_desc_portal_en;
|
||||||
|
}
|
||||||
|
byte[] data = Utils.loadRawResource(activity,res_id);
|
||||||
|
return data == null ? null : Utils.decodeUTF8( data );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSearchDesc( String html ){
|
||||||
|
if( column==null) return;
|
||||||
|
log.d("showSearchDesc: html=%s",html);
|
||||||
|
tvSearchDesc.setVisibility( View.VISIBLE );
|
||||||
|
tvSearchDesc.setMovementMethod( MyLinkMovementMethod.getInstance() );
|
||||||
|
CharSequence sv = HTMLDecoder.decodeHTML( column.access_info, html, false, null );
|
||||||
|
tvSearchDesc.setText( sv );
|
||||||
|
}
|
||||||
|
|
||||||
void showColumnColor(){
|
void showColumnColor(){
|
||||||
if( column == null ) return;
|
if( column == null ) return;
|
||||||
|
|
||||||
|
@ -595,7 +644,7 @@ class ColumnViewHolder
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnColumnReload:
|
case R.id.btnColumnReload:
|
||||||
if( column.column_type == Column.TYPE_SEARCH ){
|
if( column.column_type == Column.TYPE_SEARCH || column.column_type == Column.TYPE_SEARCH_PORTAL ){
|
||||||
Utils.hideKeyboard( activity, etSearch );
|
Utils.hideKeyboard( activity, etSearch );
|
||||||
etSearch.setText( column.search_query );
|
etSearch.setText( column.search_query );
|
||||||
cbResolve.setChecked( column.search_resolve );
|
cbResolve.setChecked( column.search_resolve );
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.util.ArrayList;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
import jp.juggler.subwaytooter.dialog.DlgQRCode;
|
import jp.juggler.subwaytooter.dialog.DlgQRCode;
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.table.UserRelation;
|
import jp.juggler.subwaytooter.table.UserRelation;
|
||||||
|
@ -30,7 +31,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
||||||
@NonNull final ActMain activity;
|
@NonNull final ActMain activity;
|
||||||
@NonNull private final SavedAccount access_info;
|
@NonNull private final SavedAccount access_info;
|
||||||
@Nullable private final TootAccount who;
|
@Nullable private final TootAccount who;
|
||||||
@Nullable private final TootStatus status;
|
@Nullable private final TootStatusLike status;
|
||||||
@NonNull private final UserRelation relation;
|
@NonNull private final UserRelation relation;
|
||||||
@NonNull private final Column column;
|
@NonNull private final Column column;
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
||||||
@NonNull ActMain activity
|
@NonNull ActMain activity
|
||||||
, @NonNull Column column
|
, @NonNull Column column
|
||||||
, @Nullable TootAccount who
|
, @Nullable TootAccount who
|
||||||
, @Nullable TootStatus status
|
, @Nullable TootStatusLike status
|
||||||
){
|
){
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
this.column = column;
|
this.column = column;
|
||||||
|
@ -123,11 +124,11 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
||||||
}else{
|
}else{
|
||||||
btnDelete.setVisibility( View.GONE );
|
btnDelete.setVisibility( View.GONE );
|
||||||
btnReport.setOnClickListener( this );
|
btnReport.setOnClickListener( this );
|
||||||
if( status.application == null || TextUtils.isEmpty( status.application.name ) ){
|
if( status.application != null && !TextUtils.isEmpty( status.application.name ) ){
|
||||||
btnMuteApp.setVisibility( View.GONE );
|
|
||||||
}else{
|
|
||||||
btnMuteApp.setText( activity.getString( R.string.mute_app_of, status.application.name ) );
|
btnMuteApp.setText( activity.getString( R.string.mute_app_of, status.application.name ) );
|
||||||
btnMuteApp.setOnClickListener( this );
|
btnMuteApp.setOnClickListener( this );
|
||||||
|
}else{
|
||||||
|
btnMuteApp.setVisibility( View.GONE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,11 +226,20 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
||||||
v = viewRoot.findViewById( R.id.btnCancel );
|
v = viewRoot.findViewById( R.id.btnCancel );
|
||||||
v.setOnClickListener( this );
|
v.setOnClickListener( this );
|
||||||
|
|
||||||
v = viewRoot.findViewById( R.id.btnBoostedBy );
|
if( access_info.isNA() ){
|
||||||
v.setOnClickListener( this );
|
v = viewRoot.findViewById( R.id.btnBoostedBy );
|
||||||
|
v.setVisibility( View.GONE);
|
||||||
v = viewRoot.findViewById( R.id.btnFavouritedBy );
|
|
||||||
v.setOnClickListener( this );
|
v = viewRoot.findViewById( R.id.btnFavouritedBy );
|
||||||
|
v.setVisibility( View.GONE);
|
||||||
|
}else{
|
||||||
|
v = viewRoot.findViewById( R.id.btnBoostedBy );
|
||||||
|
v.setOnClickListener( this );
|
||||||
|
|
||||||
|
v = viewRoot.findViewById( R.id.btnFavouritedBy );
|
||||||
|
v.setOnClickListener( this );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
v = viewRoot.findViewById( R.id.btnAccountQrCode );
|
v = viewRoot.findViewById( R.id.btnAccountQrCode );
|
||||||
v.setOnClickListener( this );
|
v.setOnClickListener( this );
|
||||||
|
@ -275,7 +285,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnReplyAnotherAccount:
|
case R.id.btnReplyAnotherAccount:
|
||||||
activity.openReplyFromAnotherAccount( access_info, status );
|
activity.openReplyFromAnotherAccount( status );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnDelete:
|
case R.id.btnDelete:
|
||||||
|
@ -293,8 +303,8 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnReport:
|
case R.id.btnReport:
|
||||||
if( status != null && who != null ){
|
if( who != null && status instanceof TootStatus ){
|
||||||
activity.openReportForm( access_info, who, status );
|
activity.openReportForm( access_info, who, (TootStatus)status );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ class ItemListAdapter extends BaseAdapter implements AdapterView.OnItemClickList
|
||||||
}else{
|
}else{
|
||||||
holder = (ItemViewHolder) view.getTag();
|
holder = (ItemViewHolder) view.getTag();
|
||||||
}
|
}
|
||||||
holder.bind( o, position );
|
holder.bind( o );
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ import jp.juggler.subwaytooter.api.entity.TootDomainBlock;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootGap;
|
import jp.juggler.subwaytooter.api.entity.TootGap;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootNotification;
|
import jp.juggler.subwaytooter.api.entity.TootNotification;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.entity.MSPToot;
|
||||||
import jp.juggler.subwaytooter.table.AcctColor;
|
import jp.juggler.subwaytooter.table.AcctColor;
|
||||||
import jp.juggler.subwaytooter.table.ContentWarning;
|
import jp.juggler.subwaytooter.table.ContentWarning;
|
||||||
import jp.juggler.subwaytooter.table.MediaShown;
|
import jp.juggler.subwaytooter.table.MediaShown;
|
||||||
|
@ -79,18 +81,17 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
private final TextView tvApplication;
|
private final TextView tvApplication;
|
||||||
|
|
||||||
private TootStatus status;
|
private TootStatusLike status;
|
||||||
private TootAccount account_thumbnail;
|
private TootAccount account_thumbnail;
|
||||||
private TootAccount account_boost;
|
private TootAccount account_boost;
|
||||||
private TootAccount account_follow;
|
private TootAccount account_follow;
|
||||||
private String search_tag;
|
private String search_tag;
|
||||||
private TootGap gap;
|
private TootGap gap;
|
||||||
private TootDomainBlock domain_block;
|
private TootDomainBlock domain_block;
|
||||||
private int position;
|
|
||||||
|
|
||||||
private final boolean bSimpleList;
|
private final boolean bSimpleList;
|
||||||
|
|
||||||
ItemViewHolder( ActMain arg_activity, Column column, ItemListAdapter list_adapter, View view ,boolean bSimpleList ){
|
ItemViewHolder( ActMain arg_activity, Column column, ItemListAdapter list_adapter, View view, boolean bSimpleList ){
|
||||||
this.activity = arg_activity;
|
this.activity = arg_activity;
|
||||||
this.column = column;
|
this.column = column;
|
||||||
this.access_info = column.access_info;
|
this.access_info = column.access_info;
|
||||||
|
@ -101,7 +102,6 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
this.tvFollowerName = (TextView) view.findViewById( R.id.tvFollowerName );
|
this.tvFollowerName = (TextView) view.findViewById( R.id.tvFollowerName );
|
||||||
this.tvBoosted = (TextView) view.findViewById( R.id.tvBoosted );
|
this.tvBoosted = (TextView) view.findViewById( R.id.tvBoosted );
|
||||||
|
|
||||||
|
|
||||||
if( activity.timeline_font != null ){
|
if( activity.timeline_font != null ){
|
||||||
Utils.scanView( view, new Utils.ScanViewCallback() {
|
Utils.scanView( view, new Utils.ScanViewCallback() {
|
||||||
@Override public void onScanView( View v ){
|
@Override public void onScanView( View v ){
|
||||||
|
@ -111,7 +111,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
}else if( v instanceof TextView ){
|
}else if( v instanceof TextView ){
|
||||||
( (TextView) v ).setTypeface( activity.timeline_font );
|
( (TextView) v ).setTypeface( activity.timeline_font );
|
||||||
}
|
}
|
||||||
}catch(Throwable ex){
|
}catch( Throwable ex ){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
this.tvContent = (MyTextView) view.findViewById( R.id.tvContent );
|
this.tvContent = (MyTextView) view.findViewById( R.id.tvContent );
|
||||||
this.tvMentions = (MyTextView) view.findViewById( R.id.tvMentions );
|
this.tvMentions = (MyTextView) view.findViewById( R.id.tvMentions );
|
||||||
|
|
||||||
this.buttons_for_status = bSimpleList ? null : new StatusButtons( activity, column, view , false );
|
this.buttons_for_status = bSimpleList ? null : new StatusButtons( activity, column, view, false );
|
||||||
|
|
||||||
this.flMedia = view.findViewById( R.id.flMedia );
|
this.flMedia = view.findViewById( R.id.flMedia );
|
||||||
this.btnShowMedia = view.findViewById( R.id.btnShowMedia );
|
this.btnShowMedia = view.findViewById( R.id.btnShowMedia );
|
||||||
|
@ -193,8 +193,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
lp.height = activity.app_state.media_thumb_height;
|
lp.height = activity.app_state.media_thumb_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind( Object item, int position ){
|
void bind( Object item ){
|
||||||
this.position = position;
|
|
||||||
this.status = null;
|
this.status = null;
|
||||||
this.account_thumbnail = null;
|
this.account_thumbnail = null;
|
||||||
this.account_boost = null;
|
this.account_boost = null;
|
||||||
|
@ -210,7 +209,9 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
if( item == null ) return;
|
if( item == null ) return;
|
||||||
|
|
||||||
if( item instanceof String ){
|
if( item instanceof MSPToot ){
|
||||||
|
showStatus( activity, (MSPToot) item );
|
||||||
|
}else if( item instanceof String ){
|
||||||
showSearchTag( (String) item );
|
showSearchTag( (String) item );
|
||||||
}else if( item instanceof TootAccount ){
|
}else if( item instanceof TootAccount ){
|
||||||
showFollow( (TootAccount) item );
|
showFollow( (TootAccount) item );
|
||||||
|
@ -270,7 +271,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
}else if( item instanceof TootGap ){
|
}else if( item instanceof TootGap ){
|
||||||
showGap( (TootGap) item );
|
showGap( (TootGap) item );
|
||||||
}else if( item instanceof TootDomainBlock ){
|
}else if( item instanceof TootDomainBlock ){
|
||||||
showDomainBlock( (TootDomainBlock)item );
|
showDomainBlock( (TootDomainBlock) item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,24 +317,30 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
Styler.setFollowIcon( activity, btnFollow, ivFollowedBy, relation );
|
Styler.setFollowIcon( activity, btnFollow, ivFollowedBy, relation );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showStatus( @NonNull ActMain activity, @NonNull TootStatus status ){
|
private void showStatus( @NonNull ActMain activity, @NonNull TootStatusLike status ){
|
||||||
this.status = status;
|
this.status = status;
|
||||||
llStatus.setVisibility( View.VISIBLE );
|
llStatus.setVisibility( View.VISIBLE );
|
||||||
|
|
||||||
tvTime.setText( TootStatus.formatTime( status.time_created_at ) );
|
if( status instanceof TootStatus ){
|
||||||
|
tvTime.setText( TootStatus.formatTime( ( (TootStatus) status ).time_created_at ) );
|
||||||
|
|
||||||
|
}else if( status instanceof MSPToot ){
|
||||||
|
tvTime.setText( ( (MSPToot) status ).created_at );
|
||||||
|
|
||||||
|
}
|
||||||
ivThumbnail.setCornerRadius( activity.pref, 16f );
|
ivThumbnail.setCornerRadius( activity.pref, 16f );
|
||||||
|
|
||||||
account_thumbnail = status.account;
|
account_thumbnail = status.account;
|
||||||
setAcct( tvAcct, access_info.getFullAcct( status.account ), R.attr.colorAcctSmall );
|
setAcct( tvAcct, access_info.getFullAcct( status.account ), R.attr.colorAcctSmall );
|
||||||
|
|
||||||
if(status.account == null ){
|
if( status.account == null ){
|
||||||
tvName.setText( "?" );
|
tvName.setText( "?" );
|
||||||
ivThumbnail.setImageUrl(null,null);
|
ivThumbnail.setImageUrl( null, null );
|
||||||
}else{
|
}else{
|
||||||
tvName.setText( status.account.display_name );
|
tvName.setText( status.account.display_name );
|
||||||
ivThumbnail.setImageUrl(
|
ivThumbnail.setImageUrl(
|
||||||
access_info.supplyBaseUrl( status.account.avatar_static )
|
access_info.supplyBaseUrl( status.account.avatar_static )
|
||||||
,access_info.supplyBaseUrl( status.account.avatar )
|
, access_info.supplyBaseUrl( status.account.avatar )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
tvContent.setText( status.decoded_content );
|
tvContent.setText( status.decoded_content );
|
||||||
|
@ -345,11 +352,16 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
// tvTags.setText( status.decoded_tags );
|
// tvTags.setText( status.decoded_tags );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if( status.decoded_mentions == null ){
|
if( status instanceof TootStatus ){
|
||||||
tvMentions.setVisibility( View.GONE );
|
TootStatus ts = (TootStatus) status;
|
||||||
|
if( ts.decoded_mentions == null ){
|
||||||
|
tvMentions.setVisibility( View.GONE );
|
||||||
|
}else{
|
||||||
|
tvMentions.setVisibility( View.VISIBLE );
|
||||||
|
tvMentions.setText( ts.decoded_mentions );
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
tvMentions.setVisibility( View.VISIBLE );
|
tvMentions.setVisibility( View.GONE );
|
||||||
tvMentions.setText( status.decoded_mentions );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content warning
|
// Content warning
|
||||||
|
@ -359,28 +371,52 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
}else{
|
}else{
|
||||||
llContentWarning.setVisibility( View.VISIBLE );
|
llContentWarning.setVisibility( View.VISIBLE );
|
||||||
tvContentWarning.setText( status.decoded_spoiler_text );
|
tvContentWarning.setText( status.decoded_spoiler_text );
|
||||||
boolean cw_shown = ContentWarning.isShown( access_info.host, status.id, false );
|
boolean cw_shown = ContentWarning.isShown( status, false );
|
||||||
showContent( cw_shown );
|
showContent( cw_shown );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( status.media_attachments == null || status.media_attachments.isEmpty() ){
|
if( status instanceof TootStatus ){
|
||||||
flMedia.setVisibility( View.GONE );
|
TootStatus ts = (TootStatus) status;
|
||||||
}else{
|
if( ts.media_attachments == null || ts.media_attachments.isEmpty() ){
|
||||||
flMedia.setVisibility( View.VISIBLE );
|
flMedia.setVisibility( View.GONE );
|
||||||
setMedia( ivMedia1, status, 0 );
|
}else{
|
||||||
setMedia( ivMedia2, status, 1 );
|
flMedia.setVisibility( View.VISIBLE );
|
||||||
setMedia( ivMedia3, status, 2 );
|
setMedia( ivMedia1, ts, 0 );
|
||||||
setMedia( ivMedia4, status, 3 );
|
setMedia( ivMedia2, ts, 1 );
|
||||||
|
setMedia( ivMedia3, ts, 2 );
|
||||||
@SuppressWarnings("SimplifiableConditionalExpression")
|
setMedia( ivMedia4, ts, 3 );
|
||||||
boolean default_shown =
|
|
||||||
column.hide_media_default ? false :
|
@SuppressWarnings("SimplifiableConditionalExpression")
|
||||||
access_info.dont_hide_nsfw ? true :
|
boolean default_shown =
|
||||||
! status.sensitive;
|
column.hide_media_default ? false :
|
||||||
|
access_info.dont_hide_nsfw ? true :
|
||||||
// hide sensitive media
|
! status.sensitive;
|
||||||
boolean is_shown = MediaShown.isShown( access_info.host, status.id, default_shown );
|
|
||||||
btnShowMedia.setVisibility( ! is_shown ? View.VISIBLE : View.GONE );
|
// hide sensitive media
|
||||||
|
boolean is_shown = MediaShown.isShown( status, default_shown );
|
||||||
|
btnShowMedia.setVisibility( ! is_shown ? View.VISIBLE : View.GONE );
|
||||||
|
}
|
||||||
|
}else if( status instanceof MSPToot ){
|
||||||
|
MSPToot ts = (MSPToot) status;
|
||||||
|
if( ts.media_attachments == null || ts.media_attachments.isEmpty() ){
|
||||||
|
flMedia.setVisibility( View.GONE );
|
||||||
|
}else{
|
||||||
|
flMedia.setVisibility( View.VISIBLE );
|
||||||
|
setMedia( ivMedia1, ts, 0 );
|
||||||
|
setMedia( ivMedia2, ts, 1 );
|
||||||
|
setMedia( ivMedia3, ts, 2 );
|
||||||
|
setMedia( ivMedia4, ts, 3 );
|
||||||
|
|
||||||
|
@SuppressWarnings("SimplifiableConditionalExpression")
|
||||||
|
boolean default_shown =
|
||||||
|
column.hide_media_default ? false :
|
||||||
|
access_info.dont_hide_nsfw ? true :
|
||||||
|
! status.sensitive;
|
||||||
|
|
||||||
|
// hide sensitive media
|
||||||
|
boolean is_shown = MediaShown.isShown( status, default_shown );
|
||||||
|
btnShowMedia.setVisibility( ! is_shown ? View.VISIBLE : View.GONE );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( buttons_for_status != null ){
|
if( buttons_for_status != null ){
|
||||||
|
@ -432,11 +468,11 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
}else{
|
}else{
|
||||||
iv.setVisibility( View.VISIBLE );
|
iv.setVisibility( View.VISIBLE );
|
||||||
iv.setScaleType( activity.dont_crop_media_thumbnail ? ImageView.ScaleType.FIT_CENTER : ImageView.ScaleType.CENTER_CROP );
|
iv.setScaleType( activity.dont_crop_media_thumbnail ? ImageView.ScaleType.FIT_CENTER : ImageView.ScaleType.CENTER_CROP );
|
||||||
|
|
||||||
TootAttachment ta = status.media_attachments.get( idx );
|
TootAttachment ta = status.media_attachments.get( idx );
|
||||||
|
|
||||||
if( TextUtils.isEmpty( ta.type )){
|
if( TextUtils.isEmpty( ta.type ) ){
|
||||||
iv.setMediaType(0);
|
iv.setMediaType( 0 );
|
||||||
}else{
|
}else{
|
||||||
switch( ta.type ){
|
switch( ta.type ){
|
||||||
default:
|
default:
|
||||||
|
@ -463,22 +499,36 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
url = ta.url;
|
url = ta.url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iv.setCornerRadius( activity.pref,0f ); // 正方形じゃないせいか、うまく動かない activity.density * 4f );
|
iv.setCornerRadius( activity.pref, 0f ); // 正方形じゃないせいか、うまく動かない activity.density * 4f );
|
||||||
|
iv.setImageUrl( access_info.supplyBaseUrl( url ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMedia( MyNetworkImageView iv, MSPToot msp_toot, int idx ){
|
||||||
|
if( idx >= msp_toot.media_attachments.size() ){
|
||||||
|
iv.setVisibility( View.GONE );
|
||||||
|
}else{
|
||||||
|
iv.setVisibility( View.VISIBLE );
|
||||||
|
iv.setScaleType( activity.dont_crop_media_thumbnail ? ImageView.ScaleType.FIT_CENTER : ImageView.ScaleType.CENTER_CROP );
|
||||||
|
|
||||||
|
String url = msp_toot.media_attachments.get( idx );
|
||||||
|
iv.setMediaType( 0 );
|
||||||
|
iv.setCornerRadius( activity.pref, 0f ); // 正方形じゃないせいか、うまく動かない activity.density * 4f );
|
||||||
iv.setImageUrl( access_info.supplyBaseUrl( url ) );
|
iv.setImageUrl( access_info.supplyBaseUrl( url ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onClick( View v ){
|
@Override public void onClick( View v ){
|
||||||
|
|
||||||
int pos = activity.nextPosition( column ) ;
|
int pos = activity.nextPosition( column );
|
||||||
|
|
||||||
switch( v.getId() ){
|
switch( v.getId() ){
|
||||||
case R.id.btnHideMedia:
|
case R.id.btnHideMedia:
|
||||||
MediaShown.save( access_info.host, status.id, false );
|
MediaShown.save( status, false );
|
||||||
btnShowMedia.setVisibility( View.VISIBLE );
|
btnShowMedia.setVisibility( View.VISIBLE );
|
||||||
break;
|
break;
|
||||||
case R.id.btnShowMedia:
|
case R.id.btnShowMedia:
|
||||||
MediaShown.save( access_info.host, status.id, true );
|
MediaShown.save( status, true );
|
||||||
btnShowMedia.setVisibility( View.GONE );
|
btnShowMedia.setVisibility( View.GONE );
|
||||||
break;
|
break;
|
||||||
case R.id.ivMedia1:
|
case R.id.ivMedia1:
|
||||||
|
@ -495,7 +545,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
break;
|
break;
|
||||||
case R.id.btnContentWarning:{
|
case R.id.btnContentWarning:{
|
||||||
boolean new_shown = ( llContents.getVisibility() == View.GONE );
|
boolean new_shown = ( llContents.getVisibility() == View.GONE );
|
||||||
ContentWarning.save( access_info.host, status.id, new_shown );
|
ContentWarning.save( status, new_shown );
|
||||||
list_adapter.notifyDataSetChanged();
|
list_adapter.notifyDataSetChanged();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -504,7 +554,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
if( access_info.isPseudo() ){
|
if( access_info.isPseudo() ){
|
||||||
new DlgContextMenu( activity, column, account_thumbnail, null ).show();
|
new DlgContextMenu( activity, column, account_thumbnail, null ).show();
|
||||||
}else{
|
}else{
|
||||||
activity.openProfile( pos,access_info, account_thumbnail );
|
activity.openProfile( pos, access_info, account_thumbnail );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -512,14 +562,14 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
if( access_info.isPseudo() ){
|
if( access_info.isPseudo() ){
|
||||||
new DlgContextMenu( activity, column, account_boost, null ).show();
|
new DlgContextMenu( activity, column, account_boost, null ).show();
|
||||||
}else{
|
}else{
|
||||||
activity.openProfile( pos,access_info, account_boost );
|
activity.openProfile( pos, access_info, account_boost );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.llFollow:
|
case R.id.llFollow:
|
||||||
if( access_info.isPseudo() ){
|
if( access_info.isPseudo() ){
|
||||||
new DlgContextMenu( activity, column, account_follow, null ).show();
|
new DlgContextMenu( activity, column, account_follow, null ).show();
|
||||||
}else{
|
}else{
|
||||||
activity.openProfile( pos,access_info, account_follow );
|
activity.openProfile( pos, access_info, account_follow );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.btnFollow:
|
case R.id.btnFollow:
|
||||||
|
@ -528,13 +578,13 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
case R.id.btnSearchTag:
|
case R.id.btnSearchTag:
|
||||||
if( search_tag != null ){
|
if( search_tag != null ){
|
||||||
activity.openHashTag( activity.nextPosition( column ),access_info, search_tag );
|
activity.openHashTag( activity.nextPosition( column ), access_info, search_tag );
|
||||||
}else if( gap != null ){
|
}else if( gap != null ){
|
||||||
column.startGap( gap );
|
column.startGap( gap );
|
||||||
}else if( domain_block != null ){
|
}else if( domain_block != null ){
|
||||||
final String domain = domain_block.domain;
|
final String domain = domain_block.domain;
|
||||||
new AlertDialog.Builder( activity )
|
new AlertDialog.Builder( activity )
|
||||||
.setMessage( activity.getString( R.string.confirm_unblock_domain, domain) )
|
.setMessage( activity.getString( R.string.confirm_unblock_domain, domain ) )
|
||||||
.setNegativeButton( R.string.cancel, null )
|
.setNegativeButton( R.string.cancel, null )
|
||||||
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {
|
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
@Override public void onClick( DialogInterface dialog, int which ){
|
@Override public void onClick( DialogInterface dialog, int which ){
|
||||||
|
@ -544,7 +594,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,22 +616,28 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
private void clickMedia( int i ){
|
private void clickMedia( int i ){
|
||||||
try{
|
try{
|
||||||
TootAttachment a = status.media_attachments.get( i );
|
if( status instanceof MSPToot ){
|
||||||
|
activity.openStatus( activity.nextPosition( column ), access_info, status );
|
||||||
String sv;
|
}else if( status instanceof TootStatus ){
|
||||||
if( Pref.pref( activity ).getBoolean( Pref.KEY_PRIOR_LOCAL_URL, false ) ){
|
TootStatus ts = (TootStatus) status;
|
||||||
sv = a.url;
|
|
||||||
if( TextUtils.isEmpty( sv ) ){
|
TootAttachment a = ts.media_attachments.get( i );
|
||||||
sv = a.remote_url;
|
|
||||||
}
|
String sv;
|
||||||
}else{
|
if( Pref.pref( activity ).getBoolean( Pref.KEY_PRIOR_LOCAL_URL, false ) ){
|
||||||
sv = a.remote_url;
|
|
||||||
if( TextUtils.isEmpty( sv ) ){
|
|
||||||
sv = a.url;
|
sv = a.url;
|
||||||
|
if( TextUtils.isEmpty( sv ) ){
|
||||||
|
sv = a.remote_url;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
sv = a.remote_url;
|
||||||
|
if( TextUtils.isEmpty( sv ) ){
|
||||||
|
sv = a.url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
int pos = activity.nextPosition( column );
|
||||||
|
activity.openChromeTab( pos, access_info, sv, false );
|
||||||
}
|
}
|
||||||
int pos = activity.nextPosition( column ) ;
|
|
||||||
activity.openChromeTab(pos, access_info, sv, false );
|
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -590,11 +646,9 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||||
// 簡略ビューの時だけ呼ばれる
|
// 簡略ビューの時だけ呼ばれる
|
||||||
// StatusButtonsPopupを表示する
|
// StatusButtonsPopupを表示する
|
||||||
void onItemClick( MyListView listView, View anchor ){
|
void onItemClick( MyListView listView, View anchor ){
|
||||||
if( status != null ){
|
activity.closeListItemPopup();
|
||||||
activity.closeListItemPopup();
|
activity.list_item_popup = new StatusButtonsPopup( activity, column, bSimpleList );
|
||||||
activity.list_item_popup = new StatusButtonsPopup( activity, column ,bSimpleList);
|
activity.list_item_popup.show( listView, anchor, status );
|
||||||
activity.list_item_popup.show( listView, anchor, status );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ import android.preference.PreferenceManager;
|
||||||
|
|
||||||
public class Pref {
|
public class Pref {
|
||||||
|
|
||||||
static SharedPreferences pref( Context context ){
|
|
||||||
|
public static SharedPreferences pref( Context context ){
|
||||||
return PreferenceManager.getDefaultSharedPreferences( context );
|
return PreferenceManager.getDefaultSharedPreferences( context );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +61,8 @@ public class Pref {
|
||||||
|
|
||||||
static final String KEY_CLIENT_NAME = "client_name";
|
static final String KEY_CLIENT_NAME = "client_name";
|
||||||
|
|
||||||
|
public static final String KEY_MASTODON_SEARCH_PORTAL_USER_TOKEN = "mastodon_search_portal_user_token";
|
||||||
|
|
||||||
|
|
||||||
// 項目を追加したらAppDataExporter#importPref のswitch文も更新すること
|
// 項目を追加したらAppDataExporter#importPref のswitch文も更新すること
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ public class PrefDevice {
|
||||||
|
|
||||||
private static String file_name = "device";
|
private static String file_name = "device";
|
||||||
|
|
||||||
static SharedPreferences prefDevice( Context context ){
|
public static SharedPreferences prefDevice( Context context ){
|
||||||
return context.getSharedPreferences( file_name, Context.MODE_PRIVATE );
|
return context.getSharedPreferences( file_name, Context.MODE_PRIVATE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import android.widget.ImageView;
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.entity.MSPToot;
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.table.UserRelation;
|
import jp.juggler.subwaytooter.table.UserRelation;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
@ -27,7 +29,7 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
||||||
private final ImageView ivFollowedBy2;
|
private final ImageView ivFollowedBy2;
|
||||||
private final View llFollow2;
|
private final View llFollow2;
|
||||||
|
|
||||||
final boolean bSimpleList;
|
private final boolean bSimpleList;
|
||||||
|
|
||||||
StatusButtons( @NonNull ActMain activity, @NonNull Column column, @NonNull View viewRoot ,boolean bSimpleList){
|
StatusButtons( @NonNull ActMain activity, @NonNull Column column, @NonNull View viewRoot ,boolean bSimpleList){
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
|
@ -63,32 +65,40 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TootStatus status;
|
|
||||||
private UserRelation relation;
|
private UserRelation relation;
|
||||||
|
private TootStatusLike status;
|
||||||
|
|
||||||
void bind( @NonNull TootStatus status ){
|
void bind( @NonNull TootStatusLike status ){
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
|
||||||
int color_normal = Styler.getAttributeColor( activity, R.attr.colorImageButton );
|
int color_normal = Styler.getAttributeColor( activity, R.attr.colorImageButton );
|
||||||
int color_accent = Styler.getAttributeColor( activity, R.attr.colorImageButtonAccent );
|
int color_accent = Styler.getAttributeColor( activity, R.attr.colorImageButtonAccent );
|
||||||
|
|
||||||
if( TootStatus.VISIBILITY_DIRECT.equals( status.visibility ) ){
|
if( status instanceof MSPToot ){
|
||||||
setButton( btnBoost, false, color_accent, R.attr.ic_mail, "" );
|
setButton( btnBoost, true, color_normal, R.attr.btn_boost, "" );
|
||||||
}else if( TootStatus.VISIBILITY_PRIVATE.equals( status.visibility ) ){
|
setButton( btnFavourite, true, color_normal, R.attr.btn_favourite, "");
|
||||||
setButton( btnBoost, false, color_accent, R.attr.ic_lock, "" );
|
}else if( status instanceof TootStatus ){
|
||||||
}else if( activity.app_state.isBusyBoost( access_info, status ) ){
|
TootStatus ts = (TootStatus)status;
|
||||||
setButton( btnBoost, false, color_normal, R.attr.btn_refresh, "?" );
|
|
||||||
}else{
|
if( TootStatus.VISIBILITY_DIRECT.equals( ts.visibility ) ){
|
||||||
int color = ( status.reblogged ? color_accent : color_normal );
|
setButton( btnBoost, false, color_accent, R.attr.ic_mail, "" );
|
||||||
setButton( btnBoost, true, color, R.attr.btn_boost, Long.toString( status.reblogs_count ) );
|
}else if( TootStatus.VISIBILITY_PRIVATE.equals( ts.visibility ) ){
|
||||||
|
setButton( btnBoost, false, color_accent, R.attr.ic_lock, "" );
|
||||||
|
}else if( activity.app_state.isBusyBoost( access_info, status ) ){
|
||||||
|
setButton( btnBoost, false, color_normal, R.attr.btn_refresh, "?" );
|
||||||
|
}else{
|
||||||
|
int color = ( ts.reblogged ? color_accent : color_normal );
|
||||||
|
setButton( btnBoost, true, color, R.attr.btn_boost, Long.toString( ts.reblogs_count ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( activity.app_state.isBusyFav( access_info, status ) ){
|
||||||
|
setButton( btnFavourite, false, color_normal, R.attr.btn_refresh, "?" );
|
||||||
|
}else{
|
||||||
|
int color = ( ts.favourited ? color_accent : color_normal );
|
||||||
|
setButton( btnFavourite, true, color, R.attr.btn_favourite, Long.toString( ts.favourites_count ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( activity.app_state.isBusyFav( access_info, status ) ){
|
|
||||||
setButton( btnFavourite, false, color_normal, R.attr.btn_refresh, "?" );
|
|
||||||
}else{
|
|
||||||
int color = ( status.favourited ? color_accent : color_normal );
|
|
||||||
setButton( btnFavourite, true, color, R.attr.btn_favourite, Long.toString( status.favourites_count ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( status.account == null || ! activity.pref.getBoolean( Pref.KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR, false ) ){
|
if( status.account == null || ! activity.pref.getBoolean( Pref.KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR, false ) ){
|
||||||
llFollow2.setVisibility( View.GONE );
|
llFollow2.setVisibility( View.GONE );
|
||||||
|
@ -101,6 +111,7 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setButton( Button b, boolean enabled, int color, int icon_attr, String text ){
|
private void setButton( Button b, boolean enabled, int color, int icon_attr, String text ){
|
||||||
Drawable d = Styler.getAttributeDrawable( activity, icon_attr ).mutate();
|
Drawable d = Styler.getAttributeDrawable( activity, icon_attr ).mutate();
|
||||||
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
|
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
|
||||||
|
@ -119,12 +130,13 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
||||||
activity.openStatus( activity.nextPosition( column ), access_info, status );
|
activity.openStatus( activity.nextPosition( column ), access_info, status );
|
||||||
break;
|
break;
|
||||||
case R.id.btnReply:
|
case R.id.btnReply:
|
||||||
if( access_info.isPseudo() ){
|
if( status instanceof TootStatus && !access_info.isPseudo() ){
|
||||||
activity.openReplyFromAnotherAccount( access_info, status );
|
activity.performReply( access_info, (TootStatus)status );
|
||||||
}else{
|
}else{
|
||||||
activity.performReply( access_info, status ,false);
|
activity.openReplyFromAnotherAccount( status );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnBoost:
|
case R.id.btnBoost:
|
||||||
if( access_info.isPseudo() ){
|
if( access_info.isPseudo() ){
|
||||||
activity.openBoostFromAnotherAccount( access_info, status );
|
activity.openBoostFromAnotherAccount( access_info, status );
|
||||||
|
@ -159,8 +171,10 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnFollow2:
|
case R.id.btnFollow2:
|
||||||
if( access_info.isPseudo() ){
|
if( status == null || status.account == null ){
|
||||||
activity.openFollowFromAnotherAccount( access_info, status );
|
// 何もしない
|
||||||
|
}else if( access_info.isPseudo() ){
|
||||||
|
activity.openFollowFromAnotherAccount( access_info, status.account );
|
||||||
}else if( relation.blocking || relation.muting ){
|
}else if( relation.blocking || relation.muting ){
|
||||||
// 何もしない
|
// 何もしない
|
||||||
}else if( relation.following || relation.requested ){
|
}else if( relation.following || relation.requested ){
|
||||||
|
@ -184,11 +198,13 @@ class StatusButtons implements View.OnClickListener, View.OnLongClickListener {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnFollow2:
|
case R.id.btnFollow2:
|
||||||
activity.openFollowFromAnotherAccount( access_info, status );
|
if( status != null && status.account != null ){
|
||||||
|
activity.openFollowFromAnotherAccount( access_info, status.account );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.btnReply:
|
case R.id.btnReply:
|
||||||
activity.openReplyFromAnotherAccount( access_info, status );
|
activity.openReplyFromAnotherAccount( status );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@ import android.view.Gravity;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
|
import jp.juggler.subwaytooter.api_msp.entity.MSPToot;
|
||||||
import jp.juggler.subwaytooter.view.MyListView;
|
import jp.juggler.subwaytooter.view.MyListView;
|
||||||
|
|
||||||
class StatusButtonsPopup {
|
class StatusButtonsPopup {
|
||||||
|
@ -34,7 +35,7 @@ class StatusButtonsPopup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void show( final MyListView listView, View anchor, TootStatus status ){
|
void show( final MyListView listView, View anchor, TootStatusLike status ){
|
||||||
|
|
||||||
//
|
//
|
||||||
window = new PopupWindow( activity );
|
window = new PopupWindow( activity );
|
||||||
|
|
|
@ -119,9 +119,9 @@ class StreamReader {
|
||||||
private Object parsePayload( String event, JSONObject obj ){
|
private Object parsePayload( String event, JSONObject obj ){
|
||||||
try{
|
try{
|
||||||
if( "update".equals( event ) ){
|
if( "update".equals( event ) ){
|
||||||
return TootStatus.parse( log, access_info, new JSONObject( obj.optString( "payload" ) ) );
|
return TootStatus.parse( log, access_info, access_info.host,new JSONObject( obj.optString( "payload" ) ) );
|
||||||
}else if( "notification".equals( event ) ){
|
}else if( "notification".equals( event ) ){
|
||||||
return TootNotification.parse( log, access_info, new JSONObject( obj.optString( "payload" ) ) );
|
return TootNotification.parse( log, access_info, access_info.host,new JSONObject( obj.optString( "payload" ) ) );
|
||||||
}else if( "delete".equals( event ) ){
|
}else if( "delete".equals( event ) ){
|
||||||
return obj.optLong( "payload", - 1L );
|
return obj.optLong( "payload", - 1L );
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ public class TootAccount {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CharSequence filterDisplayName( String sv ){
|
public static CharSequence filterDisplayName( String sv ){
|
||||||
|
|
||||||
// decode HTML entity
|
// decode HTML entity
|
||||||
sv = HTMLDecoder.decodeEntity(sv );
|
sv = HTMLDecoder.decodeEntity(sv );
|
||||||
|
@ -155,4 +155,14 @@ public class TootAccount {
|
||||||
return Emojione.decodeEmoji( sv ) ;
|
return Emojione.decodeEmoji( sv ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAcctHost(){
|
||||||
|
try{
|
||||||
|
int pos = acct.indexOf( '@' );
|
||||||
|
if( pos != - 1 ) return acct.substring( pos + 1 );
|
||||||
|
}catch(Throwable ignored){
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,12 @@ public class TootContext {
|
||||||
// descendants The descendants of the status in the conversation, as a list of Statuses
|
// descendants The descendants of the status in the conversation, as a list of Statuses
|
||||||
public TootStatus.List descendants;
|
public TootStatus.List descendants;
|
||||||
|
|
||||||
public static TootContext parse( LogCategory log, LinkClickContext account,JSONObject src ){
|
public static TootContext parse( LogCategory log, LinkClickContext lcc,String status_host,JSONObject src ){
|
||||||
if( src==null) return null;
|
if( src==null) return null;
|
||||||
try{
|
try{
|
||||||
TootContext dst = new TootContext();
|
TootContext dst = new TootContext();
|
||||||
dst.ancestors = TootStatus.parseList( log, account,src.optJSONArray( "ancestors" ) );
|
dst.ancestors = TootStatus.parseList( log, lcc,status_host,src.optJSONArray( "ancestors" ) );
|
||||||
dst.descendants = TootStatus.parseList(log, account, src.optJSONArray( "descendants" ) );
|
dst.descendants = TootStatus.parseList(log, lcc, status_host,src.optJSONArray( "descendants" ) );
|
||||||
return dst;
|
return dst;
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class TootNotification extends TootId {
|
||||||
|
|
||||||
public JSONObject json;
|
public JSONObject json;
|
||||||
|
|
||||||
public static TootNotification parse( LogCategory log, LinkClickContext accopunt, JSONObject src ){
|
public static TootNotification parse( LogCategory log, LinkClickContext lcc,String status_host, JSONObject src ){
|
||||||
if( src == null ) return null;
|
if( src == null ) return null;
|
||||||
try{
|
try{
|
||||||
TootNotification dst = new TootNotification();
|
TootNotification dst = new TootNotification();
|
||||||
|
@ -45,8 +45,8 @@ public class TootNotification extends TootId {
|
||||||
dst.id = src.optLong( "id" );
|
dst.id = src.optLong( "id" );
|
||||||
dst.type = Utils.optStringX( src, "type" );
|
dst.type = Utils.optStringX( src, "type" );
|
||||||
dst.created_at = Utils.optStringX( src, "created_at" );
|
dst.created_at = Utils.optStringX( src, "created_at" );
|
||||||
dst.account = TootAccount.parse( log, accopunt, src.optJSONObject( "account" ) );
|
dst.account = TootAccount.parse( log, lcc, src.optJSONObject( "account" ) );
|
||||||
dst.status = TootStatus.parse( log, accopunt, src.optJSONObject( "status" ) );
|
dst.status = TootStatus.parse( log, lcc, status_host,src.optJSONObject( "status" ) );
|
||||||
|
|
||||||
dst.time_created_at = TootStatus.parseTime( log, dst.created_at );
|
dst.time_created_at = TootStatus.parseTime( log, dst.created_at );
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ public class TootNotification extends TootId {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static List parseList( LogCategory log, LinkClickContext account, JSONArray array ){
|
public static List parseList( LogCategory log, LinkClickContext lcc,String status_host, JSONArray array ){
|
||||||
List result = new List();
|
List result = new List();
|
||||||
if( array != null ){
|
if( array != null ){
|
||||||
int array_size = array.length();
|
int array_size = array.length();
|
||||||
|
@ -77,7 +77,7 @@ public class TootNotification extends TootId {
|
||||||
for( int i = 0 ; i < array_size ; ++ i ){
|
for( int i = 0 ; i < array_size ; ++ i ){
|
||||||
JSONObject src = array.optJSONObject( i );
|
JSONObject src = array.optJSONObject( i );
|
||||||
if( src == null ) continue;
|
if( src == null ) continue;
|
||||||
TootNotification item = parse( log, account, src );
|
TootNotification item = parse( log, lcc,status_host, src );
|
||||||
if( item != null ) result.add( item );
|
if( item != null ) result.add( item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,12 @@ public class TootResults {
|
||||||
// An array of matched hashtags, as strings
|
// An array of matched hashtags, as strings
|
||||||
public ArrayList< String > hashtags;
|
public ArrayList< String > hashtags;
|
||||||
|
|
||||||
public static TootResults parse( LogCategory log, LinkClickContext account, JSONObject src ){
|
public static TootResults parse( LogCategory log, LinkClickContext lcc,String status_host, JSONObject src ){
|
||||||
try{
|
try{
|
||||||
if( src == null ) return null;
|
if( src == null ) return null;
|
||||||
TootResults dst = new TootResults();
|
TootResults dst = new TootResults();
|
||||||
dst.accounts = TootAccount.parseList( log, account, src.optJSONArray( "accounts" ) );
|
dst.accounts = TootAccount.parseList( log, lcc, src.optJSONArray( "accounts" ) );
|
||||||
dst.statuses = TootStatus.parseList( log, account, src.optJSONArray( "statuses" ) );
|
dst.statuses = TootStatus.parseList( log, lcc, status_host,src.optJSONArray( "statuses" ) );
|
||||||
dst.hashtags = Utils.parseStringArray( log, src.optJSONArray( "hashtags" ) );
|
dst.hashtags = Utils.parseStringArray( log, src.optJSONArray( "hashtags" ) );
|
||||||
return dst;
|
return dst;
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
|
|
|
@ -2,6 +2,7 @@ package jp.juggler.subwaytooter.api.entity;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.NavigationView;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
@ -19,13 +20,14 @@ import java.util.TimeZone;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||||
import jp.juggler.subwaytooter.util.LinkClickContext;
|
import jp.juggler.subwaytooter.util.LinkClickContext;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
import jp.juggler.subwaytooter.util.Utils;
|
import jp.juggler.subwaytooter.util.Utils;
|
||||||
import jp.juggler.subwaytooter.util.WordTrieTree;
|
import jp.juggler.subwaytooter.util.WordTrieTree;
|
||||||
|
|
||||||
public class TootStatus extends TootId {
|
public class TootStatus extends TootStatusLike {
|
||||||
|
|
||||||
public static class List extends ArrayList< TootStatus > {
|
public static class List extends ArrayList< TootStatus > {
|
||||||
|
|
||||||
|
@ -44,12 +46,9 @@ public class TootStatus extends TootId {
|
||||||
// A Fediverse-unique resource ID
|
// A Fediverse-unique resource ID
|
||||||
public String uri;
|
public String uri;
|
||||||
|
|
||||||
//URL to the status page (can be remote)
|
|
||||||
public String url;
|
|
||||||
|
|
||||||
// The TootAccount which posted the status
|
|
||||||
@Nullable public TootAccount account;
|
|
||||||
|
|
||||||
|
|
||||||
// null or the ID of the status it replies to
|
// null or the ID of the status it replies to
|
||||||
public String in_reply_to_id;
|
public String in_reply_to_id;
|
||||||
|
|
||||||
|
@ -58,31 +57,12 @@ public class TootStatus extends TootId {
|
||||||
|
|
||||||
// null or the reblogged Status
|
// null or the reblogged Status
|
||||||
public TootStatus reblog;
|
public TootStatus reblog;
|
||||||
|
|
||||||
// Body of the status; this will contain HTML (remote HTML already sanitized)
|
|
||||||
public String content;
|
|
||||||
|
|
||||||
// The time the status was created
|
// The time the status was created
|
||||||
public String created_at;
|
public String created_at;
|
||||||
|
|
||||||
//The number of reblogs for the status
|
|
||||||
public long reblogs_count;
|
|
||||||
|
|
||||||
//The number of favourites for the status
|
|
||||||
public long favourites_count;
|
|
||||||
|
|
||||||
// Whether the authenticated user has reblogged the status
|
|
||||||
public boolean reblogged;
|
|
||||||
|
|
||||||
// Whether the authenticated user has favourited the status
|
|
||||||
public boolean favourited;
|
|
||||||
|
|
||||||
//Whether media attachments should be hidden by default
|
|
||||||
public boolean sensitive;
|
|
||||||
|
|
||||||
//If not empty, warning text that should be displayed before the actual content
|
|
||||||
public String spoiler_text;
|
|
||||||
|
|
||||||
//One of: public, unlisted, private, direct
|
//One of: public, unlisted, private, direct
|
||||||
public String visibility;
|
public String visibility;
|
||||||
public static final String VISIBILITY_PUBLIC = "public";
|
public static final String VISIBILITY_PUBLIC = "public";
|
||||||
|
@ -99,13 +79,9 @@ public class TootStatus extends TootId {
|
||||||
//An array of Tags
|
//An array of Tags
|
||||||
public TootTag.List tags;
|
public TootTag.List tags;
|
||||||
|
|
||||||
//Application from which the status was posted
|
|
||||||
public TootApplication application;
|
|
||||||
|
|
||||||
public long time_created_at;
|
public long time_created_at;
|
||||||
|
|
||||||
public Spannable decoded_content;
|
|
||||||
public Spannable decoded_spoiler_text;
|
|
||||||
// public Spannable decoded_tags;
|
// public Spannable decoded_tags;
|
||||||
public Spannable decoded_mentions;
|
public Spannable decoded_mentions;
|
||||||
|
|
||||||
|
@ -113,7 +89,7 @@ public class TootStatus extends TootId {
|
||||||
|
|
||||||
public boolean conversation_main;
|
public boolean conversation_main;
|
||||||
|
|
||||||
public static TootStatus parse( LogCategory log, LinkClickContext account, JSONObject src ){
|
public static TootStatus parse( @NonNull LogCategory log, @NonNull LinkClickContext lcc, @NonNull String status_host, JSONObject src ){
|
||||||
|
|
||||||
if( src == null ) return null;
|
if( src == null ) return null;
|
||||||
|
|
||||||
|
@ -122,12 +98,13 @@ public class TootStatus extends TootId {
|
||||||
status.json = src;
|
status.json = src;
|
||||||
// log.d( "parse: %s", src.toString() );
|
// log.d( "parse: %s", src.toString() );
|
||||||
status.id = src.optLong( "id" );
|
status.id = src.optLong( "id" );
|
||||||
|
status.status_host = status_host;
|
||||||
status.uri = Utils.optStringX( src, "uri" );
|
status.uri = Utils.optStringX( src, "uri" );
|
||||||
status.url = Utils.optStringX( src, "url" );
|
status.url = Utils.optStringX( src, "url" );
|
||||||
status.account = TootAccount.parse( log, account, src.optJSONObject( "account" ) );
|
status.account = TootAccount.parse( log, lcc, src.optJSONObject( "account" ) );
|
||||||
status.in_reply_to_id = Utils.optStringX( src, "in_reply_to_id" ); // null
|
status.in_reply_to_id = Utils.optStringX( src, "in_reply_to_id" ); // null
|
||||||
status.in_reply_to_account_id = Utils.optStringX( src, "in_reply_to_account_id" ); // null
|
status.in_reply_to_account_id = Utils.optStringX( src, "in_reply_to_account_id" ); // null
|
||||||
status.reblog = TootStatus.parse( log, account, src.optJSONObject( "reblog" ) );
|
status.reblog = TootStatus.parse( log, lcc,status_host, src.optJSONObject( "reblog" ) );
|
||||||
status.content = Utils.optStringX( src, "content" );
|
status.content = Utils.optStringX( src, "content" );
|
||||||
status.created_at = Utils.optStringX( src, "created_at" ); // "2017-04-16T09:37:14.000Z"
|
status.created_at = Utils.optStringX( src, "created_at" ); // "2017-04-16T09:37:14.000Z"
|
||||||
status.reblogs_count = src.optLong( "reblogs_count" );
|
status.reblogs_count = src.optLong( "reblogs_count" );
|
||||||
|
@ -143,12 +120,12 @@ public class TootStatus extends TootId {
|
||||||
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.time_created_at = parseTime( log, status.created_at );
|
||||||
status.decoded_content = HTMLDecoder.decodeHTML( account, status.content ,true,status.media_attachments );
|
status.decoded_content = HTMLDecoder.decodeHTML( lcc, status.content ,true,status.media_attachments );
|
||||||
// status.decoded_tags = HTMLDecoder.decodeTags( account,status.tags );
|
// status.decoded_tags = HTMLDecoder.decodeTags( account,status.tags );
|
||||||
status.decoded_mentions = HTMLDecoder.decodeMentions( account, status.mentions );
|
status.decoded_mentions = HTMLDecoder.decodeMentions( lcc, status.mentions );
|
||||||
|
|
||||||
if( ! TextUtils.isEmpty( status.spoiler_text ) ){
|
if( ! TextUtils.isEmpty( status.spoiler_text ) ){
|
||||||
status.decoded_spoiler_text = HTMLDecoder.decodeHTML( account, status.spoiler_text ,true,status.media_attachments);
|
status.decoded_spoiler_text = HTMLDecoder.decodeHTML( lcc, status.spoiler_text ,true,status.media_attachments);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
|
@ -159,7 +136,7 @@ public class TootStatus extends TootId {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static List parseList( LogCategory log, LinkClickContext account, JSONArray array ){
|
public static List parseList( @NonNull LogCategory log, @NonNull LinkClickContext lcc, @NonNull String status_host, JSONArray array ){
|
||||||
List result = new List();
|
List result = new List();
|
||||||
if( array != null ){
|
if( array != null ){
|
||||||
int array_size = array.length();
|
int array_size = array.length();
|
||||||
|
@ -167,7 +144,7 @@ public class TootStatus extends TootId {
|
||||||
for( int i = 0 ; i < array_size ; ++ i ){
|
for( int i = 0 ; i < array_size ; ++ i ){
|
||||||
JSONObject src = array.optJSONObject( i );
|
JSONObject src = array.optJSONObject( i );
|
||||||
if( src == null ) continue;
|
if( src == null ) continue;
|
||||||
TootStatus item = parse( log, account, src );
|
TootStatus item = parse( log, lcc,status_host, src );
|
||||||
if( item != null ) result.add( item );
|
if( item != null ) result.add( item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package jp.juggler.subwaytooter.api.entity;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.Spannable;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class TootStatusLike extends TootId{
|
||||||
|
|
||||||
|
//URL to the status page (can be remote)
|
||||||
|
public String url;
|
||||||
|
|
||||||
|
public String status_host;
|
||||||
|
|
||||||
|
// The TootAccount which posted the status
|
||||||
|
@Nullable public TootAccount account;
|
||||||
|
|
||||||
|
|
||||||
|
//The number of reblogs for the status
|
||||||
|
public long reblogs_count;
|
||||||
|
|
||||||
|
//The number of favourites for the status
|
||||||
|
public long favourites_count;
|
||||||
|
|
||||||
|
// Whether the authenticated user has reblogged the status
|
||||||
|
public boolean reblogged;
|
||||||
|
|
||||||
|
// Whether the authenticated user has favourited the status
|
||||||
|
public boolean favourited;
|
||||||
|
|
||||||
|
//Whether media attachments should be hidden by default
|
||||||
|
public boolean sensitive;
|
||||||
|
|
||||||
|
//If not empty, warning text that should be displayed before the actual content
|
||||||
|
public String spoiler_text;
|
||||||
|
public Spannable decoded_spoiler_text;
|
||||||
|
|
||||||
|
// Body of the status; this will contain HTML (remote HTML already sanitized)
|
||||||
|
public String content;
|
||||||
|
public Spannable decoded_content;
|
||||||
|
|
||||||
|
//Application from which the status was posted
|
||||||
|
public TootApplication application;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package jp.juggler.subwaytooter.api_msp;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.api.TootApiResult;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
|
||||||
|
public class MSPApiResult extends TootApiResult {
|
||||||
|
|
||||||
|
MSPApiResult( String error ){
|
||||||
|
super( error );
|
||||||
|
}
|
||||||
|
|
||||||
|
MSPApiResult( Response response, String json, JSONArray array ){
|
||||||
|
super(null);
|
||||||
|
this.json = json;
|
||||||
|
this.array = array;
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
package jp.juggler.subwaytooter.api_msp;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.App1;
|
||||||
|
import jp.juggler.subwaytooter.Pref;
|
||||||
|
import jp.juggler.subwaytooter.R;
|
||||||
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
import jp.juggler.subwaytooter.util.Utils;
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class MSPClient {
|
||||||
|
static final LogCategory log = new LogCategory("MSPClient");
|
||||||
|
|
||||||
|
private static final String url_token = "http://mastodonsearch.jp/api/v1.0.1/utoken";
|
||||||
|
private static final String url_search = "http://mastodonsearch.jp/api/v1.0.1/cross";
|
||||||
|
private static final String api_key = "e53de7f66130208f62d1808672bf6320523dcd0873dc69bc";
|
||||||
|
|
||||||
|
private static final OkHttpClient ok_http_client = App1.ok_http_client;
|
||||||
|
|
||||||
|
|
||||||
|
public interface Callback {
|
||||||
|
boolean isApiCancelled();
|
||||||
|
|
||||||
|
void publishApiProgress( String s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MSPApiResult search( @NonNull Context context, @NonNull String query, @NonNull String max_id ,@NonNull Callback callback ){
|
||||||
|
// ユーザトークンを読む
|
||||||
|
SharedPreferences pref = Pref.pref(context);
|
||||||
|
String user_token = pref.getString(Pref.KEY_MASTODON_SEARCH_PORTAL_USER_TOKEN,null);
|
||||||
|
|
||||||
|
Response response;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
// ユーザトークンがなければ取得する
|
||||||
|
if( TextUtils.isEmpty( user_token ) ){
|
||||||
|
|
||||||
|
callback.publishApiProgress( "get MSP user token..." );
|
||||||
|
|
||||||
|
String url = url_token + "?apikey=" + Uri.encode( api_key );
|
||||||
|
|
||||||
|
try{
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url( url )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Call call = ok_http_client.newCall( request );
|
||||||
|
response = call.execute();
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
return new MSPApiResult( Utils.formatError( ex, context.getResources(), R.string.network_error ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( callback.isApiCancelled() ) return null;
|
||||||
|
|
||||||
|
if( ! response.isSuccessful() ){
|
||||||
|
if( response.code() >= 400 ){
|
||||||
|
try{
|
||||||
|
String json = response.body().string();
|
||||||
|
JSONObject object = new JSONObject( json );
|
||||||
|
JSONObject error = object.getJSONObject( "error" );
|
||||||
|
return new MSPApiResult( String.format( "API returns error. %s: %s"
|
||||||
|
, error.optString( "type" )
|
||||||
|
, error.optString( "detail" )
|
||||||
|
) );
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
return new MSPApiResult( Utils.formatError( ex, "API returns error response %s, but can't parse response body.", response.code() ) );
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return new MSPApiResult( context.getString( R.string.network_error_arg, response ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
String json = response.body().string();
|
||||||
|
JSONObject object = new JSONObject( json );
|
||||||
|
user_token = object.getJSONObject( "result" ).getString( "token" );
|
||||||
|
if( TextUtils.isEmpty( user_token ) ){
|
||||||
|
return new MSPApiResult( String.format( "Can't get MSP user token. response=%s", json ) );
|
||||||
|
}else{
|
||||||
|
pref.edit().putString( Pref.KEY_MASTODON_SEARCH_PORTAL_USER_TOKEN, user_token ).apply();
|
||||||
|
}
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
return new MSPApiResult( Utils.formatError( ex, "API data error" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ユーザトークンを使って検索APIを呼び出す
|
||||||
|
{
|
||||||
|
callback.publishApiProgress( "waiting search result..." );
|
||||||
|
String url = url_search
|
||||||
|
+ "?apikey=" + Uri.encode( api_key )
|
||||||
|
+ "&utoken=" + Uri.encode( user_token )
|
||||||
|
+ "&max=" + Uri.encode( max_id )
|
||||||
|
+ "&q=" + Uri.encode( query );
|
||||||
|
|
||||||
|
try{
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url( url )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Call call = ok_http_client.newCall( request );
|
||||||
|
response = call.execute();
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
return new MSPApiResult( Utils.formatError( ex, context.getResources(), R.string.network_error ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( callback.isApiCancelled() ) return null;
|
||||||
|
|
||||||
|
if( ! response.isSuccessful() ){
|
||||||
|
if( response.code() >= 400 ){
|
||||||
|
try{
|
||||||
|
String json = response.body().string();
|
||||||
|
JSONObject object = new JSONObject( json );
|
||||||
|
JSONObject error = object.getJSONObject( "error" );
|
||||||
|
// ユーザトークンがダメなら生成しなおす
|
||||||
|
if( "utoken".equals( error.optString( "detail" ) ) ){
|
||||||
|
user_token = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return new MSPApiResult( String.format( "API returns error. %s: %s"
|
||||||
|
, error.optString( "type" )
|
||||||
|
, error.optString( "detail" )
|
||||||
|
) );
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
return new MSPApiResult( Utils.formatError( ex, "API returns error response %s, but can't parse response body.", response.code() ) );
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return new MSPApiResult( context.getString( R.string.network_error_arg, response ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
String json = response.body().string();
|
||||||
|
JSONArray array = new JSONArray( json );
|
||||||
|
return new MSPApiResult( response, json, array );
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
return new MSPApiResult( Utils.formatError( ex, "API data error" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMaxId( JSONArray array, String max_id ){
|
||||||
|
// max_id の更新
|
||||||
|
int size = array.length();
|
||||||
|
if( size > 0 ){
|
||||||
|
JSONObject item = array.optJSONObject( size - 1 );
|
||||||
|
if( item != null ){
|
||||||
|
String sv = item.optString( "msp_id" );
|
||||||
|
if( ! TextUtils.isEmpty( sv ) ){
|
||||||
|
return sv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
package jp.juggler.subwaytooter.api_msp.entity;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
|
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||||
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
import jp.juggler.subwaytooter.util.Utils;
|
||||||
|
|
||||||
|
public class MSPToot extends TootStatusLike {
|
||||||
|
|
||||||
|
public static class List extends ArrayList<MSPToot> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern reAccountUrl = Pattern.compile("\\Ahttps://([^/#?]+)/@([^/#?]+)\\z");
|
||||||
|
|
||||||
|
|
||||||
|
private static TootAccount parseAccount( LogCategory log, SavedAccount access_info, JSONObject src ){
|
||||||
|
|
||||||
|
if( src == null ) return null;
|
||||||
|
|
||||||
|
TootAccount dst = new TootAccount();
|
||||||
|
dst.url = Utils.optStringX( src, "url" );
|
||||||
|
dst.username = Utils.optStringX( src, "username" );
|
||||||
|
dst.avatar = dst.avatar_static = Utils.optStringX( src, "avatar" );
|
||||||
|
|
||||||
|
String sv = Utils.optStringX( src, "display_name" );
|
||||||
|
if( TextUtils.isEmpty( sv ) ){
|
||||||
|
dst.display_name = dst.username;
|
||||||
|
}else{
|
||||||
|
dst.display_name = TootAccount.filterDisplayName( sv );
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.id = src.optLong( "id" );
|
||||||
|
dst.note = HTMLDecoder.decodeHTML( access_info, Utils.optStringX( src, "note" ), true, null );
|
||||||
|
|
||||||
|
if( TextUtils.isEmpty( dst.url ) ){
|
||||||
|
log.e( "parseAccount: missing url" );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Matcher m = reAccountUrl.matcher( dst.url );
|
||||||
|
if( ! m.find() ){
|
||||||
|
log.e( "parseAccount: not account url: %s", dst.url );
|
||||||
|
return null;
|
||||||
|
}else{
|
||||||
|
dst.acct = dst.username + "@" + m.group( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private static final Pattern reTime = Pattern.compile( "\\A(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)" );
|
||||||
|
//
|
||||||
|
// private static final TimeZone tz_tokyo = TimeZone.getTimeZone( "Asia/Tokyo" );
|
||||||
|
//
|
||||||
|
// private static long parseMSPTime( LogCategory log, String strTime ){
|
||||||
|
// if( ! TextUtils.isEmpty( strTime ) ){
|
||||||
|
// try{
|
||||||
|
// Matcher m = reTime.matcher( strTime );
|
||||||
|
// if( ! m.find() ){
|
||||||
|
// log.d( "!!invalid time format: %s", strTime );
|
||||||
|
// }else{
|
||||||
|
// GregorianCalendar g = new GregorianCalendar( tz_tokyo );
|
||||||
|
// 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, 0 );
|
||||||
|
// return g.getTimeInMillis();
|
||||||
|
// }
|
||||||
|
// }catch( Throwable ex ){// ParseException, ArrayIndexOutOfBoundsException
|
||||||
|
// ex.printStackTrace();
|
||||||
|
// log.e( ex, "parseMSPTime failed. src=%s", strTime );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return 0L;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public String created_at;
|
||||||
|
public ArrayList<String> media_attachments;
|
||||||
|
public long msp_id;
|
||||||
|
|
||||||
|
private static MSPToot parse( LogCategory log, SavedAccount access_info,JSONObject src ){
|
||||||
|
if( src == null ) return null;
|
||||||
|
MSPToot dst = new MSPToot();
|
||||||
|
|
||||||
|
dst.account =parseAccount( log, access_info, src.optJSONObject( "account" ));
|
||||||
|
if( dst.account == null ){
|
||||||
|
log.e("missing status account");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.url = Utils.optStringX( src, "url" );
|
||||||
|
dst.status_host = dst.account.getAcctHost();
|
||||||
|
dst.id = src.optLong( "id" ,-1L );
|
||||||
|
|
||||||
|
if( TextUtils.isEmpty( dst.url ) || TextUtils.isEmpty( dst.status_host ) || dst.id == -1L ){
|
||||||
|
log.e("missing status url or host or id");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.created_at = Utils.optStringX( src, "created_at" );
|
||||||
|
|
||||||
|
JSONArray a = src.optJSONArray( "media_attachments" );
|
||||||
|
if( a != null && a.length() > 0 ){
|
||||||
|
dst.media_attachments = new ArrayList<>();
|
||||||
|
for(int i=0,ie=a.length();i<ie;++i){
|
||||||
|
String sv = Utils.optStringX( a,i );
|
||||||
|
if(!TextUtils.isEmpty( sv )){
|
||||||
|
dst.media_attachments.add( sv );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.msp_id = src.optLong("msp_id");
|
||||||
|
dst.sensitive = (src.optInt( "sensitive" ,0) != 0);
|
||||||
|
|
||||||
|
dst.spoiler_text = Utils.optStringX( src, "spoiler_text" );
|
||||||
|
if( ! TextUtils.isEmpty( dst.spoiler_text ) ){
|
||||||
|
dst.decoded_spoiler_text = HTMLDecoder.decodeHTML( access_info, dst.spoiler_text ,true,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.content = Utils.optStringX( src, "content" );
|
||||||
|
dst.decoded_content = HTMLDecoder.decodeHTML( access_info, dst.content ,true,null );
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List parseList( LogCategory log, SavedAccount access_info,JSONArray array ){
|
||||||
|
List list = new List();
|
||||||
|
for(int i=0,ie=array.length();i<ie;++i){
|
||||||
|
JSONObject src = array.optJSONObject( i );
|
||||||
|
if( src == null ) continue;
|
||||||
|
MSPToot item = parse( log, access_info,src );
|
||||||
|
if( item == null ) continue;
|
||||||
|
list.add( item );
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -3,8 +3,10 @@ package jp.juggler.subwaytooter.table;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.App1;
|
import jp.juggler.subwaytooter.App1;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
|
||||||
public class ContentWarning {
|
public class ContentWarning {
|
||||||
|
@ -40,9 +42,9 @@ public class ContentWarning {
|
||||||
}
|
}
|
||||||
private static final String[] projection_shown = new String[]{COL_SHOWN};
|
private static final String[] projection_shown = new String[]{COL_SHOWN};
|
||||||
|
|
||||||
public static boolean isShown( String host,long status_id ,boolean default_value ){
|
public static boolean isShown( @NonNull TootStatusLike status , boolean default_value ){
|
||||||
try{
|
try{
|
||||||
Cursor cursor = App1.getDB().query( table, projection_shown, "h=? and si=?", new String[]{host, Long.toString(status_id) }, null, null, null );
|
Cursor cursor = App1.getDB().query( table, projection_shown, "h=? and si=?", new String[]{status.status_host, Long.toString(status.id) }, null, null, null );
|
||||||
try{
|
try{
|
||||||
if( cursor.moveToFirst() ){
|
if( cursor.moveToFirst() ){
|
||||||
int iv = cursor.getInt( cursor.getColumnIndex( COL_SHOWN ) );
|
int iv = cursor.getInt( cursor.getColumnIndex( COL_SHOWN ) );
|
||||||
|
@ -57,13 +59,13 @@ public class ContentWarning {
|
||||||
return default_value ;
|
return default_value ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save( String host,long status_id ,boolean is_shown ){
|
public static void save( @NonNull TootStatusLike status ,boolean is_shown ){
|
||||||
try{
|
try{
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
ContentValues cv = new ContentValues();
|
ContentValues cv = new ContentValues();
|
||||||
cv.put( COL_HOST, host );
|
cv.put( COL_HOST, status.status_host );
|
||||||
cv.put( COL_STATUS_ID, status_id );
|
cv.put( COL_STATUS_ID, status.id );
|
||||||
cv.put( COL_SHOWN, is_shown ? 1:0 );
|
cv.put( COL_SHOWN, is_shown ? 1:0 );
|
||||||
cv.put( COL_TIME_SAVE, now );
|
cv.put( COL_TIME_SAVE, now );
|
||||||
App1.getDB().replace( table, null, cv );
|
App1.getDB().replace( table, null, cv );
|
||||||
|
|
|
@ -3,8 +3,10 @@ package jp.juggler.subwaytooter.table;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.App1;
|
import jp.juggler.subwaytooter.App1;
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
|
||||||
public class MediaShown {
|
public class MediaShown {
|
||||||
|
@ -41,9 +43,9 @@ public class MediaShown {
|
||||||
|
|
||||||
private static final String[] projection_shown = new String[]{COL_SHOWN};
|
private static final String[] projection_shown = new String[]{COL_SHOWN};
|
||||||
|
|
||||||
public static boolean isShown( String host,long status_id ,boolean default_value ){
|
public static boolean isShown( @NonNull TootStatusLike status , boolean default_value ){
|
||||||
try{
|
try{
|
||||||
Cursor cursor = App1.getDB().query( table, projection_shown, "h=? and si=?", new String[]{host, Long.toString(status_id) }, null, null, null );
|
Cursor cursor = App1.getDB().query( table, projection_shown, "h=? and si=?", new String[]{ status.status_host, Long.toString(status.id) }, null, null, null );
|
||||||
try{
|
try{
|
||||||
if( cursor.moveToFirst() ){
|
if( cursor.moveToFirst() ){
|
||||||
return ( 0 != cursor.getInt( cursor.getColumnIndex( COL_SHOWN ) ) );
|
return ( 0 != cursor.getInt( cursor.getColumnIndex( COL_SHOWN ) ) );
|
||||||
|
@ -57,13 +59,13 @@ public class MediaShown {
|
||||||
return default_value ;
|
return default_value ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save( String host,long status_id ,boolean is_shown ){
|
public static void save( @NonNull TootStatusLike status ,boolean is_shown ){
|
||||||
try{
|
try{
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
ContentValues cv = new ContentValues();
|
ContentValues cv = new ContentValues();
|
||||||
cv.put( COL_HOST, host );
|
cv.put( COL_HOST, status.status_host );
|
||||||
cv.put( COL_STATUS_ID, status_id );
|
cv.put( COL_STATUS_ID, status.id );
|
||||||
cv.put( COL_SHOWN, is_shown ? 1:0 );
|
cv.put( COL_SHOWN, is_shown ? 1:0 );
|
||||||
cv.put( COL_TIME_SAVE, now );
|
cv.put( COL_TIME_SAVE, now );
|
||||||
App1.getDB().replace( table, null, cv );
|
App1.getDB().replace( table, null, cv );
|
||||||
|
|
|
@ -191,6 +191,30 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||||
|
|
||||||
private SavedAccount(){
|
private SavedAccount(){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 横断検索用の、何とも紐ついていないアカウント
|
||||||
|
// 保存しない。
|
||||||
|
private static SavedAccount na_account;
|
||||||
|
public static SavedAccount getNA(){
|
||||||
|
if( na_account == null ){
|
||||||
|
SavedAccount dst = new SavedAccount();
|
||||||
|
dst.db_id = - 1L;
|
||||||
|
dst.username = "?";
|
||||||
|
dst.acct = "?@?";
|
||||||
|
dst.host = "?";
|
||||||
|
dst.notification_follow = false;
|
||||||
|
dst.notification_favourite = false;
|
||||||
|
dst.notification_boost = false;
|
||||||
|
dst.notification_mention = false;
|
||||||
|
na_account = dst;
|
||||||
|
}
|
||||||
|
return na_account;
|
||||||
|
}
|
||||||
|
public boolean isNA(){
|
||||||
|
return acct.equals( "?@?" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static SavedAccount parse( Cursor cursor ) throws JSONException{
|
private static SavedAccount parse( Cursor cursor ) throws JSONException{
|
||||||
JSONObject src = new JSONObject( cursor.getString( cursor.getColumnIndex( COL_ACCOUNT ) ) );
|
JSONObject src = new JSONObject( cursor.getString( cursor.getColumnIndex( COL_ACCOUNT ) ) );
|
||||||
|
@ -475,4 +499,5 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ public class UserRelation {
|
||||||
public boolean muting;
|
public boolean muting;
|
||||||
public boolean requested;
|
public boolean requested;
|
||||||
|
|
||||||
private UserRelation(){
|
public UserRelation(){
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final LruCache< String, UserRelation > mMemoryCache = new LruCache<>( 2048 );
|
private static final LruCache< String, UserRelation > mMemoryCache = new LruCache<>( 2048 );
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -1107,4 +1108,23 @@ public class Utils {
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] loadRawResource(Context context,int res_id){
|
||||||
|
try{
|
||||||
|
InputStream is = context.getResources().openRawResource( res_id );
|
||||||
|
try{
|
||||||
|
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||||
|
IOUtils.copy( is, bao );
|
||||||
|
|
||||||
|
return bao.toByteArray();
|
||||||
|
|
||||||
|
}finally{
|
||||||
|
IOUtils.closeQuietly( is );
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,6 +244,17 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</jp.juggler.subwaytooter.view.MaxHeightScrollView>
|
</jp.juggler.subwaytooter.view.MaxHeightScrollView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="0dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:background="?attr/colorSearchFormBackground"
|
||||||
|
android:id="@+id/tvSearchDesc"
|
||||||
|
/>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/llSearch"
|
android:id="@+id/llSearch"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -92,6 +92,16 @@
|
||||||
<!--android:title="Tools"/>-->
|
<!--android:title="Tools"/>-->
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
<item android:title="@string/toot_search">
|
||||||
|
<menu>
|
||||||
|
<item
|
||||||
|
android:id="@+id/mastodon_search_portal"
|
||||||
|
android:icon="?attr/ic_search"
|
||||||
|
android:title="@string/mastodon_search_portal"/>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item android:title="@string/setting">
|
<item android:title="@string/setting">
|
||||||
<menu>
|
<menu>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Toot search Powered by <a href="http://mastodonsearch.jp/">Mastodon Search Portal</a>, it indexes instances in Japan.<br/>If you want to remove your toot from search result, please contact to <a href="https://mstdn.jp/@mastodonsearch">@mastodonsearch@mstdn.jp</a>.
|
|
@ -0,0 +1 @@
|
||||||
|
powered by <a href="http://mastodonsearch.jp/">マストドン検索ポータル</a><br/>検索結果からあなたのトゥートを除外したい場合、<a href="https://mstdn.jp/@mastodonsearch">@mastodonsearch@mstdn.jp</a>に連絡してください。
|
|
@ -366,8 +366,13 @@
|
||||||
<string name="text_to_speech_shutdown">TextToSpeech shutdown…</string>
|
<string name="text_to_speech_shutdown">TextToSpeech shutdown…</string>
|
||||||
<string name="show_post_button_bar_top">Show buttons bar at the top of posting screen</string>
|
<string name="show_post_button_bar_top">Show buttons bar at the top of posting screen</string>
|
||||||
<string name="client_name">Client name (access token update required)</string>
|
<string name="client_name">Client name (access token update required)</string>
|
||||||
|
<string name="toot_search">Toot search</string>
|
||||||
|
<string name="mastodon_search_portal">Mastodon Search Portal(JP)</string>
|
||||||
|
<string name="search_desc_mastodon_api">Account/Hashtag search using Mastodon API.</string>
|
||||||
|
<string name="toot_search_of">Toot Rechercher \"%1$s\"</string>
|
||||||
|
<string name="progress_synchronize_toot">Syncing Toot…</string>
|
||||||
|
|
||||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
<!--<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_description_format">%1$s, %2$s</string>-->
|
||||||
<!--<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>-->
|
<!--<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>-->
|
||||||
<!--<string name="abc_action_bar_up_description">Revenir en haut de la page</string>-->
|
<!--<string name="abc_action_bar_up_description">Revenir en haut de la page</string>-->
|
||||||
|
|
|
@ -653,5 +653,10 @@
|
||||||
<string name="text_to_speech_shutdown">TextToSpeechの後処理…</string>
|
<string name="text_to_speech_shutdown">TextToSpeechの後処理…</string>
|
||||||
<string name="show_post_button_bar_top">投稿画面のボタンバーを上端に表示</string>
|
<string name="show_post_button_bar_top">投稿画面のボタンバーを上端に表示</string>
|
||||||
<string name="client_name">クライアント名(アクセストークンの更新が必要)</string>
|
<string name="client_name">クライアント名(アクセストークンの更新が必要)</string>
|
||||||
|
<string name="toot_search">トゥート検索</string>
|
||||||
|
<string name="mastodon_search_portal">マストドン検索ポータル(JP)</string>
|
||||||
|
<string name="search_desc_mastodon_api">アカウントやハッシュタグをマストドンのAPIで検索します。</string>
|
||||||
|
<string name="toot_search_of">トゥート検索:%1$s</string>
|
||||||
|
<string name="progress_synchronize_toot">トゥートを同期してます…</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -361,4 +361,10 @@
|
||||||
<string name="text_to_speech_shutdown">TextToSpeech shutdown…</string>
|
<string name="text_to_speech_shutdown">TextToSpeech shutdown…</string>
|
||||||
<string name="show_post_button_bar_top">Show buttons bar at the top of posting screen</string>
|
<string name="show_post_button_bar_top">Show buttons bar at the top of posting screen</string>
|
||||||
<string name="client_name">Client name (access token update required)</string>
|
<string name="client_name">Client name (access token update required)</string>
|
||||||
|
<string name="toot_search">Toot search</string>
|
||||||
|
<string name="mastodon_search_portal">Mastodon Search Portal(JP)</string>
|
||||||
|
<string name="search_desc_mastodon_api">Account/Hashtag search using Mastodon API.</string>
|
||||||
|
<string name="toot_search_of">Toot search \"%1$s\"</string>
|
||||||
|
<string name="progress_synchronize_toot">Syncing Toot…</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue