「別アカウントでプロフを開く」を同タンスじゃなくてもできるようにした

This commit is contained in:
tateisu 2017-05-19 11:18:00 +09:00
parent 4a4106ebaf
commit a22c431989
10 changed files with 192 additions and 167 deletions

View File

@ -9,8 +9,8 @@ android {
applicationId "jp.juggler.subwaytooter"
minSdkVersion 21
targetSdkVersion 25
versionCode 60
versionName "0.6.0"
versionCode 61
versionName "0.6.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

View File

@ -12,7 +12,6 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.customtabs.CustomTabsIntent;
@ -315,9 +314,9 @@ public class ActMain extends AppCompatActivity
}
// リザルト
static final int RESULT_APP_DATA_IMPORT = RESULT_FIRST_USER ;
// リクエスト
static final int RESULT_APP_DATA_IMPORT = RESULT_FIRST_USER;
// リクエスト
static final int REQUEST_CODE_COLUMN_LIST = 1;
static final int REQUEST_CODE_ACCOUNT_SETTING = 2;
static final int REQUEST_APP_ABOUT = 3;
@ -407,7 +406,6 @@ public class ActMain extends AppCompatActivity
super.onActivityResult( requestCode, resultCode, data );
}
@Override
public void onBackPressed(){
@ -626,22 +624,21 @@ public class ActMain extends AppCompatActivity
static final int COLUMN_WIDTH_MIN_DP = 300;
Typeface timeline_font ;
Typeface timeline_font;
void initUI(){
setContentView( R.layout.act_main );
String sv = pref.getString(Pref.KEY_TIMELINE_FONT,"");
String sv = pref.getString( Pref.KEY_TIMELINE_FONT, "" );
if( ! TextUtils.isEmpty( sv ) ){
try{
timeline_font = Typeface.createFromFile( sv );
}catch(Throwable ex){
}catch( Throwable ex ){
ex.printStackTrace();
}
}
llEmpty = findViewById( R.id.llEmpty );
// // toolbar
@ -1025,49 +1022,7 @@ public class ActMain extends AppCompatActivity
final String host = m.group( 1 );
final String user = Uri.decode( m.group( 2 ) );
// 1: 検索APIは疑似アカウントでは開けない => startFindAccountが使えない
// 2: かりに検索できたとしてもユーザページは疑似アカウントでは開けない
ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( log );
ArrayList< SavedAccount > account_list_filtered = new ArrayList<>();
for( SavedAccount a : account_list ){
if( a.isPseudo() ) continue;
if( host.equalsIgnoreCase( a.host ) ){
account_list_filtered.add( a );
}
}
if( account_list_filtered.isEmpty() ){
for( SavedAccount a : account_list ){
if( a.isPseudo() ) continue;
account_list_filtered.add( a );
}
if( account_list_filtered.isEmpty() ){
// 認証されたアカウントが全くないのでブラウザで開くしかない
openChromeTab( getDefaultInsertPosition(), null, uri.toString(), true );
return;
}
}
AccountPicker.pick( this, false, true
, getString( R.string.account_picker_open_user_who, user + "@" + host )
, account_list_filtered
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull final SavedAccount ai ){
startFindAccount( ai, host, user, new FindAccountCallback() {
@Override public void onFindAccount( TootAccount who ){
if( who != null ){
performOpenUser( getDefaultInsertPosition(), ai, who );
return;
}
openChromeTab( getDefaultInsertPosition(), ai, uri.toString(), true );
}
} );
}
} );
return;
openProfileByHostUser( getDefaultInsertPosition(), null, uri.toString(), host, user );
}
return;
@ -1356,25 +1311,6 @@ public class ActMain extends AppCompatActivity
return col;
}
void performOpenUser( int pos, @NonNull SavedAccount access_info, @NonNull TootAccount user ){
if( access_info.isPseudo() ){
Utils.showToast( this, false, R.string.not_available_for_pseudo_account );
}else{
addColumn( pos, access_info, Column.TYPE_PROFILE, user.id );
}
}
public void performOpenUserFromAnotherAccount( final int pos, final TootAccount who, ArrayList< SavedAccount > account_list_non_pseudo_same_instance ){
AccountPicker.pick( this, false, false
, getString( R.string.account_picker_open_user_who, AcctColor.getNickname( who.acct ) )
, account_list_non_pseudo_same_instance
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
addColumn( pos, ai, Column.TYPE_PROFILE, who.id );
}
} );
}
private void performAddTimeline( final int pos, boolean bAllowPseudo, final int type, final Object... args ){
AccountPicker.pick( this, bAllowPseudo, true
, getString( R.string.account_picker_add_timeline_of, Column.getColumnTypeName( this, type ) )
@ -1406,7 +1342,7 @@ public class ActMain extends AppCompatActivity
interface FindAccountCallback {
// return account information
// if failed, account is null.
void onFindAccount( TootAccount account );
void onFindAccount( @Nullable TootAccount account );
}
void startFindAccount( final SavedAccount access_info, final String host, final String user, final FindAccountCallback callback ){
@ -1528,61 +1464,8 @@ public class ActMain extends AppCompatActivity
// 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 );
if( ! access_info.isPseudo() ){
startFindAccount( access_info, host, user, new FindAccountCallback() {
@Override public void onFindAccount( TootAccount who ){
if( who != null ){
performOpenUser( pos, access_info, who );
return;
}
openChromeTab( pos, access_info, url, true );
}
} );
return;
}
// 1: 検索APIは疑似アカウントでは開けない => startFindAccountが使えない
// 2: かりに検索できたとしてもユーザページは疑似アカウントでは開けない
ArrayList< SavedAccount > account_list = SavedAccount.loadAccountList( log );
ArrayList< SavedAccount > account_list_filtered = new ArrayList<>();
for( SavedAccount a : account_list ){
if( a.isPseudo() ) continue;
if( host.equalsIgnoreCase( a.host ) ){
account_list_filtered.add( a );
}
}
if( account_list_filtered.isEmpty() ){
for( SavedAccount a : account_list ){
if( a.isPseudo() ) continue;
account_list_filtered.add( a );
}
if( account_list_filtered.isEmpty() ){
// 認証されたアカウントが全くないのでブラウザで開くしかない
openChromeTab( getDefaultInsertPosition(), null, url, true );
return;
}
}
AccountPicker.pick( this, false, true
, getString( R.string.account_picker_open_user_who, user + "@" + host )
, account_list_filtered
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull final SavedAccount ai ){
startFindAccount( ai, host, user, new FindAccountCallback() {
@Override public void onFindAccount( TootAccount who ){
if( who != null ){
performOpenUser( getDefaultInsertPosition(), ai, who );
return;
}
openChromeTab( getDefaultInsertPosition(), ai, url, true );
}
} );
}
} );
return;
}
@ -1794,6 +1677,149 @@ public class ActMain extends AppCompatActivity
}
}
/////////////////////////////////////////////////////////////////////////
// open profile
private void openProfileRemote( final int pos, final SavedAccount access_info, final String who_url ){
new AsyncTask< Void, Void, TootApiResult >() {
TootAccount who_local;
@Override protected TootApiResult doInBackground( Void... params ){
TootApiClient client = new TootApiClient( ActMain.this, new TootApiClient.Callback() {
@Override public boolean isApiCancelled(){
return isCancelled();
}
@Override public void publishApiProgress( final String s ){
}
} );
client.setAccount( access_info );
// 検索APIに他タンスのユーザのURLを投げると自タンスのURLを得られる
String path = String.format( Locale.JAPAN, Column.PATH_SEARCH, Uri.encode( who_url ) );
path = path + "&resolve=1";
TootApiResult result = client.request( path );
if( result != null && result.object != null ){
TootResults tmp = TootResults.parse( log, access_info, result.object );
if( tmp != null ){
if( tmp.accounts != null && ! tmp.accounts.isEmpty() ){
who_local = tmp.accounts.get( 0 );
}
}
if( who_local == null ){
return new TootApiResult( getString( R.string.user_id_conversion_failed ) );
}
}
return result;
}
@Override protected void onCancelled( TootApiResult result ){
super.onPostExecute( result );
}
@Override protected void onPostExecute( TootApiResult result ){
if( result == null ){
// cancelled.
}else if( who_local != null ){
addColumn( pos, access_info, Column.TYPE_PROFILE, who_local.id );
}else{
Utils.showToast( ActMain.this, true, result.error );
// 仕方ないのでchrome tab で開く
openChromeTab( pos, access_info, who_url, true );
}
}
}.executeOnExecutor( App1.task_executor );
}
void openProfileFromAnotherAccount( final int pos, @NonNull final SavedAccount access_info, final TootAccount who ){
AccountPicker.pick( this, false, false
, getString( R.string.account_picker_open_user_who, AcctColor.getNickname( who.acct ) )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
if( ai.host.equalsIgnoreCase( access_info.host ) ){
addColumn( pos, ai, Column.TYPE_PROFILE, who.id );
}else{
openProfileRemote( pos, ai, who.url );
}
}
} );
}
void openProfile( int pos, @NonNull SavedAccount access_info, @NonNull TootAccount who ){
if( access_info.isPseudo() ){
openProfileFromAnotherAccount( pos, access_info, who );
}else{
addColumn( pos, access_info, Column.TYPE_PROFILE, who.id );
}
}
// Intent-FilterからUser URL で指定されたユーザのプロフを開く
// openChromeTabからUser URL で指定されたユーザのプロフを開く
private void openProfileByHostUser(
final int pos
, @Nullable final SavedAccount access_info
, @NonNull final String url
, @NonNull final String host
, @NonNull final String user
){
// リンクタップした文脈のアカウントが疑似でないなら
if( access_info != null && ! access_info.isPseudo() ){
if( access_info.host.equalsIgnoreCase( host ) ){
// 文脈のアカウントと同じインスタンスならアカウントIDを探して開いてしまう
startFindAccount( access_info, host, user, new FindAccountCallback() {
@Override public void onFindAccount( TootAccount who ){
if( who != null ){
openProfile( pos, access_info, who );
return;
}
// ダメならchromeで開く
openChromeTab( pos, access_info, url, true );
}
} );
}else{
// 文脈のアカウント異なるインスタンスなら別アカウントで開く
openProfileRemote( pos, access_info, url );
}
return;
}
// 文脈がないもしくは疑似アカウントだった
// 疑似アカウントではユーザ情報APIを呼べないし検索APIも使えない
// 疑似ではないアカウントの一覧
ArrayList< SavedAccount > account_list_filtered = new ArrayList<>();
for( SavedAccount a : SavedAccount.loadAccountList( log ) ){
if( a.isPseudo() ) continue;
account_list_filtered.add( a );
}
if( account_list_filtered.isEmpty() ){
// アカウントがないのでchrome tab で開くしかない
openChromeTab( pos, access_info, url, true );
}else{
// アカウントを選択して開く
AccountPicker.pick( this, false, false
, getString( R.string.account_picker_open_user_who, AcctColor.getNickname( user + "@" + host ) )
, account_list_filtered
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
openProfileRemote( pos, ai, url );
}
} );
}
}
/////////////////////////////////////////////////////////////////////////
// favourite
@ -3233,7 +3259,6 @@ public class ActMain extends AppCompatActivity
//////////////////////////////////////////////////////////////////////////////////////////////
private void importAppData( final Uri uri ){
// remove all columns
{
@ -3253,18 +3278,18 @@ public class ActMain extends AppCompatActivity
final ProgressDialog progress = new ProgressDialog( this );
final AsyncTask< Void, String, ArrayList<Column> > task = new AsyncTask< Void, String, ArrayList<Column> >() {
void setProgressMessage(final String sv){
final AsyncTask< Void, String, ArrayList< Column > > task = new AsyncTask< Void, String, ArrayList< Column > >() {
void setProgressMessage( final String sv ){
Utils.runOnMainThread( new Runnable() {
@Override public void run(){
progress.setMessage(sv);
progress.setMessage( sv );
}
} );
}
@Override protected ArrayList<Column> doInBackground( Void... params ){
@Override protected ArrayList< Column > doInBackground( Void... params ){
try{
setProgressMessage( "import data to local storage..." );
@ -3272,17 +3297,17 @@ public class ActMain extends AppCompatActivity
//noinspection ResultOfMethodCallIgnored
cache_dir.mkdir();
File file = new File( cache_dir, "SubwayTooter." + android.os.Process.myPid() + "." + android.os.Process.myTid() + ".json" );
// ローカルファイルにコピーする
InputStream is = getContentResolver().openInputStream( uri );
if( is == null ){
Utils.showToast( ActMain.this, true,"openInputStream failed.");
Utils.showToast( ActMain.this, true, "openInputStream failed." );
return null;
}
try{
FileOutputStream os = new FileOutputStream( file );
try{
IOUtils.copy( is,os );
IOUtils.copy( is, os );
}finally{
IOUtils.closeQuietly( os );
@ -3291,14 +3316,13 @@ public class ActMain extends AppCompatActivity
IOUtils.closeQuietly( is );
}
// 通知サービスを止める
setProgressMessage( "reset Notification..." );
{
AlarmService.mBusyAppDataImportBefore.set(true);
AlarmService.mBusyAppDataImportAfter.set(true);
AlarmService.mBusyAppDataImportBefore.set( true );
AlarmService.mBusyAppDataImportAfter.set( true );
Intent intent = new Intent(ActMain.this,AlarmService.class);
Intent intent = new Intent( ActMain.this, AlarmService.class );
intent.setAction( AlarmService.ACTION_APP_DATA_IMPORT_BEFORE );
startService( intent );
while( AlarmService.mBusyAppDataImportBefore.get() ){
@ -3308,7 +3332,7 @@ public class ActMain extends AppCompatActivity
// JSONを読みだす
setProgressMessage( "reading app data..." );
Reader r =new InputStreamReader(new FileInputStream(file),"UTF-8");
Reader r = new InputStreamReader( new FileInputStream( file ), "UTF-8" );
try{
JsonReader reader = new JsonReader( r );
return AppDataExporter.decodeAppData( ActMain.this, reader );
@ -3322,16 +3346,16 @@ public class ActMain extends AppCompatActivity
return null;
}
@Override protected void onCancelled( ArrayList<Column> result ){
@Override protected void onCancelled( ArrayList< Column > result ){
super.onCancelled( result );
}
@Override protected void onPostExecute( ArrayList<Column> result ){
@Override protected void onPostExecute( ArrayList< Column > result ){
progress.dismiss();
try{
getWindow().clearFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON );
}catch(Throwable ignored){
}catch( Throwable ignored ){
}
if( isCancelled() || result == null ){
@ -3344,9 +3368,9 @@ public class ActMain extends AppCompatActivity
pager.setAdapter( null );
}
app_state.column_list.clear();
app_state.column_list.addAll(result );
app_state.column_list.addAll( result );
app_state.saveColumnList();
if( pager_adapter != null ){
pager.setAdapter( pager_adapter );
}else{
@ -3356,7 +3380,7 @@ public class ActMain extends AppCompatActivity
// 通知サービスをリスタート
{
Intent intent = new Intent(ActMain.this,AlarmService.class);
Intent intent = new Intent( ActMain.this, AlarmService.class );
intent.setAction( AlarmService.ACTION_APP_DATA_IMPORT_AFTER );
startService( intent );
}
@ -3367,7 +3391,7 @@ public class ActMain extends AppCompatActivity
try{
getWindow().addFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON );
}catch(Throwable ignored){
}catch( Throwable ignored ){
}
progress.setIndeterminate( true );

View File

@ -18,7 +18,6 @@ import java.util.ArrayList;
import jp.juggler.subwaytooter.api.entity.TootAccount;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.dialog.AccountPicker;
import jp.juggler.subwaytooter.dialog.DlgQRCode;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
@ -203,11 +202,8 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
btnSendMessageFromAnotherAccount.setOnClickListener( this );
}
if( account_list_non_pseudo_same_instance.isEmpty() ){
btnOpenProfileFromAnotherAccount.setVisibility( View.GONE );
}else{
btnOpenProfileFromAnotherAccount.setOnClickListener( this );
}
btnOpenProfileFromAnotherAccount.setOnClickListener( this );
View v = viewRoot.findViewById( R.id.btnNickname );
v.setOnClickListener( this );
@ -349,7 +345,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
break;
case R.id.btnProfile:
activity.performOpenUser( pos,access_info, who );
activity.openProfile( pos,access_info, who );
break;
case R.id.btnSendMessage:
@ -377,7 +373,7 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
break;
case R.id.btnOpenProfileFromAnotherAccount:
activity.performOpenUserFromAnotherAccount( pos,who, account_list_non_pseudo_same_instance );
activity.openProfileFromAnotherAccount( pos,access_info,who );
break;
case R.id.btnNickname:

View File

@ -164,7 +164,6 @@ class HeaderViewHolder implements View.OnClickListener, View.OnLongClickListener
new DlgContextMenu( activity, column, who, null ).show();
}
break;
}
}

View File

@ -449,7 +449,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
if( access_info.isPseudo() ){
new DlgContextMenu( activity, column, account_thumbnail, null ).show();
}else{
activity.performOpenUser( pos,access_info, account_thumbnail );
activity.openProfile( pos,access_info, account_thumbnail );
}
break;
@ -457,14 +457,14 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
if( access_info.isPseudo() ){
new DlgContextMenu( activity, column, account_boost, null ).show();
}else{
activity.performOpenUser( pos,access_info, account_boost );
activity.openProfile( pos,access_info, account_boost );
}
break;
case R.id.llFollow:
if( access_info.isPseudo() ){
new DlgContextMenu( activity, column, account_follow, null ).show();
}else{
activity.performOpenUser( pos,access_info, account_follow );
activity.openProfile( pos,access_info, account_follow );
}
break;
case R.id.btnFollow:

View File

@ -27,7 +27,10 @@ public class AccountPicker {
void onAccountPicked( @NonNull SavedAccount ai );
}
public static void pick( @NonNull ActMain activity, boolean bAllowPseudo, boolean bAuto
public static void pick(
@NonNull ActMain activity
, boolean bAllowPseudo
, boolean bAuto
, String message
, @NonNull final AccountPickerCallback callback
){
@ -36,7 +39,10 @@ public class AccountPicker {
pick( activity, bAllowPseudo, bAuto, message, account_list, callback );
}
public static void pick( @NonNull ActMain activity, boolean bAllowPseudo, boolean bAuto
public static void pick(
@NonNull ActMain activity
, boolean bAllowPseudo
, boolean bAuto
, String message
, @NonNull final ArrayList< SavedAccount > account_list
, @NonNull final AccountPickerCallback callback

View File

@ -290,7 +290,6 @@
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnAccountWebPage"
android:layout_width="match_parent"

View File

@ -213,7 +213,7 @@
<string name="open_in_pseudo_account">Ouvrir avec le compte %1$s</string>
<string name="open_instance_website">Ouvrir https://%1$s/</string>
<string name="open_profile">Ouvrir ce profil</string>
<string name="open_profile_from_another_account">Ouvrir ce profil avec un autre compte (même instance)</string>
<string name="open_profile_from_another_account">Ouvrir ce profil avec un autre compte</string>
<string name="open_status_from">Ouvrir le statut depuis</string>
<string name="open_web_on_host">Ouvrir la page web sur %1$s</string>
<string name="open_web_page">Ouvrir la page Web</string>

View File

@ -426,7 +426,7 @@
<!---->
<string name="send_message">メッセージを送る</string>
<!---->
<string name="open_profile_from_another_account">(同タンスの)別アカウントでプロフを開く</string>
<string name="open_profile_from_another_account">別アカウントでプロフを開く</string>
<!---->
<string name="open_profile">プロフを開く</string>
<!---->

View File

@ -218,7 +218,7 @@
<string name="open_profile">Open profile</string>
<string name="send_message">Send message</string>
<string name="send_message_from_another_account">Send message from another account</string>
<string name="open_profile_from_another_account">Open profile from another account (same instance)</string>
<string name="open_profile_from_another_account">Open profile from another account</string>
<string name="confirm_block_user">User \'%1$s\' will be blocked. Are you sure?</string>
<string name="confirm_mute_user">User \'%1$s\' will be muted. Are you sure?</string>
<string name="confirm_delete_status">This toot will be deleted. Are you sure?</string>
@ -323,4 +323,5 @@
<string name="app_data_import">Import app data</string>
<string name="app_data_import_desc">You can export data to any app that can receive data, But maybe you can import data only from device\'s storage or Google drive.\nColumn background image may be not exported/imported over device.\nTimeline font is not exported/imported.</string>
<string name="app_data_import_confirm">existing data ( before import ) will be cleared. Are you sure?</string>
<string name="user_id_conversion_failed">User id conversion failed.</string>
</resources>