SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/action/Action_User.java

485 lines
15 KiB
Java

package jp.juggler.subwaytooter.action;
import android.app.Dialog;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.json.JSONObject;
import java.util.Locale;
import jp.juggler.subwaytooter.ActMain;
import jp.juggler.subwaytooter.ActPost;
import jp.juggler.subwaytooter.App1;
import jp.juggler.subwaytooter.Column;
import jp.juggler.subwaytooter.R;
import jp.juggler.subwaytooter.api.TootApiClient;
import jp.juggler.subwaytooter.api.TootApiResult;
import jp.juggler.subwaytooter.api.TootTask;
import jp.juggler.subwaytooter.api.TootTaskRunner;
import jp.juggler.subwaytooter.api.entity.TootAccount;
import jp.juggler.subwaytooter.api.entity.TootRelationShip;
import jp.juggler.subwaytooter.api.entity.TootResults;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.api.TootParser;
import jp.juggler.subwaytooter.dialog.AccountPicker;
import jp.juggler.subwaytooter.dialog.ReportForm;
import jp.juggler.subwaytooter.table.AcctColor;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
import jp.juggler.subwaytooter.util.Utils;
import okhttp3.Request;
import okhttp3.RequestBody;
public class Action_User {
// ユーザをミュート/ミュート解除する
public static void mute(
@NonNull final ActMain activity
, @NonNull final SavedAccount access_info
, @NonNull final TootAccount who
, final boolean bMute
, final boolean bMuteNotification
){
if( access_info.isMe( who ) ){
Utils.showToast( activity, false, R.string.it_is_you );
return;
}
new TootTaskRunner( activity, true ).run( access_info, new TootTask() {
@Override public TootApiResult background( @NonNull TootApiClient client ){
Request.Builder request_builder = new Request.Builder().post(
! bMute ? RequestBody.create( TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED, "" )
: bMuteNotification ? RequestBody.create( TootApiClient.MEDIA_TYPE_JSON, "{\"notifications\": true}" )
: RequestBody.create( TootApiClient.MEDIA_TYPE_JSON, "{\"notifications\": false}" )
);
TootApiResult result = client.request( "/api/v1/accounts/" + who.id + ( bMute ? "/mute" : "/unmute" )
, request_builder );
if( result != null && result.object != null ){
relation = ActionUtils.saveUserRelation( access_info, TootRelationShip.parse( result.object ) );
}
return result;
}
UserRelation relation;
@Override public void handleResult( @Nullable TootApiResult result ){
if( result == null ) return; // cancelled.
if( relation != null ){
// 未確認だが、自分をミュートしようとするとリクエストは成功するがレスポンス中のmutingはfalseになるはず
if( bMute && ! relation.muting ){
Utils.showToast( activity, false, R.string.not_muted );
return;
}
if( relation.muting ){
for( Column column : App1.app_state.column_list ){
column.removeAccountInTimeline( access_info, who.id );
}
}else{
for( Column column : App1.app_state.column_list ){
column.removeFromMuteList( access_info, who.id );
}
}
Utils.showToast( activity, false, relation.muting ? R.string.mute_succeeded : R.string.unmute_succeeded );
}else{
Utils.showToast( activity, false, result.error );
}
}
} );
}
// ユーザをブロック/ブロック解除する
public static void block(
@NonNull final ActMain activity
, @NonNull final SavedAccount access_info
, @NonNull final TootAccount who
, final boolean bBlock
){
if( access_info.isMe( who ) ){
Utils.showToast( activity, false, R.string.it_is_you );
return;
}
new TootTaskRunner( activity, true ).run( access_info, new TootTask() {
@Override public TootApiResult background( @NonNull TootApiClient client ){
Request.Builder request_builder = new Request.Builder().post(
RequestBody.create(
TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED
, "" // 空データ
) );
TootApiResult result = client.request(
"/api/v1/accounts/" + who.id + ( bBlock ? "/block" : "/unblock" )
, request_builder
);
if( result != null ){
if( result.object != null ){
relation = ActionUtils.saveUserRelation( access_info, TootRelationShip.parse( result.object ) );
}
}
return result;
}
UserRelation relation;
@Override public void handleResult( @Nullable TootApiResult result ){
if( result == null ) return; // cancelled.
if( relation != null ){
// 自分をブロックしようとすると、blocking==falseで帰ってくる
if( bBlock && ! relation.blocking ){
Utils.showToast( activity, false, R.string.not_blocked );
return;
}
for( Column column : App1.app_state.column_list ){
if( relation.blocking ){
column.removeAccountInTimeline( access_info, who.id );
}else{
column.removeFromBlockList( access_info, who.id );
}
}
Utils.showToast( activity, false, relation.blocking ? R.string.block_succeeded : R.string.unblock_succeeded );
}else{
Utils.showToast( activity, false, result.error );
}
}
} );
}
// アカウントを選んでユーザプロフを開く
public static void profileFromAnotherAccount(
@NonNull final ActMain activity
, final int pos
, @NonNull final SavedAccount access_info
, @Nullable final TootAccount who
){
if( who == null ) return;
String who_host = access_info.getAccountHost( who );
AccountPicker.pick(
activity
, false
, false
, activity.getString( R.string.account_picker_open_user_who, AcctColor.getNickname( who.acct ) )
, ActionUtils.makeAccountListNonPseudo( activity, who_host )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
if( ai.host.equalsIgnoreCase( access_info.host ) ){
activity.addColumn( pos, ai, Column.TYPE_PROFILE, who.id );
}else{
profile( activity, pos, ai, who.url );
}
}
} );
}
// 今のアカウントでユーザプロフを開く
public static void profile(
@NonNull final ActMain activity
, int pos
, @NonNull SavedAccount access_info
, @Nullable TootAccount who
){
if( who == null ){
Utils.showToast( activity, false, "user is null" );
}else if( access_info.isPseudo() ){
profileFromAnotherAccount( activity, pos, access_info, who );
}else{
activity.addColumn( pos, access_info, Column.TYPE_PROFILE, who.id );
}
}
// URLからユーザを検索してプロフを開く
public static void profile(
@NonNull final ActMain activity
, final int pos
, final SavedAccount access_info
, final String who_url
){
new TootTaskRunner( activity, true ).run( access_info, new TootTask() {
@Override public TootApiResult background( @NonNull TootApiClient client ){
// 検索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 = new TootParser( activity, access_info ).results( 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( activity.getString( R.string.user_id_conversion_failed ) );
}
}
return result;
}
TootAccount who_local;
@Override public void handleResult( @Nullable TootApiResult result ){
if( result == null ){
// cancelled.
}else if( who_local != null ){
activity.addColumn( pos, access_info, Column.TYPE_PROFILE, who_local.id );
}else{
Utils.showToast( activity, true, result.error );
// 仕方ないのでchrome tab で開く
App1.openCustomTab( activity, who_url );
}
}
} );
}
// Intent-FilterからUser URL で指定されたユーザのプロフを開く
// openChromeTabからUser URL で指定されたユーザのプロフを開く
public static void profile(
@NonNull final ActMain activity
, 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を探して開いてしまう
ActionUtils.findAccountByName( activity, access_info, host, user, new ActionUtils.FindAccountCallback() {
@Override public void onFindAccount( TootAccount who ){
if( who != null ){
profile( activity, pos, access_info, who );
return;
}
// ダメならchromeで開く
App1.openCustomTab( activity, url );
}
} );
}else{
// 文脈のアカウント異なるインスタンスなら、別アカウントで開く
profile( activity, pos, access_info, url );
}
return;
}
// 文脈がない、もしくは疑似アカウントだった
// 疑似ではないアカウントの一覧
if( ! SavedAccount.hasRealAccount() ){
// 疑似アカウントではユーザ情報APIを呼べないし検索APIも使えない
// chrome tab で開くしかない
App1.openCustomTab( activity, url );
}else{
// アカウントを選択して開く
AccountPicker.pick( activity, false, false
, activity.getString( R.string.account_picker_open_user_who, AcctColor.getNickname( user + "@" + host ) )
, ActionUtils.makeAccountListNonPseudo( activity, host )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
profile( activity, pos, ai, url );
}
}
);
}
}
// 通報フォームを開く
public static void reportForm(
@NonNull final ActMain activity
, @NonNull final SavedAccount account
, @NonNull final TootAccount who
, @NonNull final TootStatus status
){
ReportForm.showReportForm( activity, who, status, new ReportForm.ReportFormCallback() {
@Override public void startReport( final Dialog dialog, String comment ){
report( activity, account, who, status, comment, new ReportCompleteCallback() {
@Override public void onReportComplete( @NonNull TootApiResult result ){
// 成功したらダイアログを閉じる
try{
dialog.dismiss();
}catch( Throwable ignored ){
// IllegalArgumentException がたまに出る
}
}
} );
}
} );
}
interface ReportCompleteCallback {
void onReportComplete( @NonNull TootApiResult result );
}
// 通報する
private static void report(
@NonNull final ActMain activity
, @NonNull final SavedAccount access_info
, @NonNull final TootAccount who
, @NonNull final TootStatus status
, @NonNull final String comment
, @Nullable final ReportCompleteCallback callback
){
if( access_info.isMe( who ) ){
Utils.showToast( activity, false, R.string.it_is_you );
return;
}
new TootTaskRunner( activity, true ).run( access_info, new TootTask() {
@Override public TootApiResult background( @NonNull TootApiClient client ){
String sb = "account_id=" + Long.toString( who.id )
+ "&comment=" + Uri.encode( comment )
+ "&status_ids[]=" + Long.toString( status.id );
Request.Builder request_builder = new Request.Builder().post(
RequestBody.create(
TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED
, sb
) );
return client.request( "/api/v1/reports", request_builder );
}
@Override public void handleResult( @Nullable TootApiResult result ){
if( result == null ) return; // cancelled.
if( result.object != null ){
if( callback != null ) callback.onReportComplete( result );
Utils.showToast( activity, false, R.string.report_completed );
}else{
Utils.showToast( activity, true, result.error );
}
}
} );
}
// show/hide boosts from (following) user
public static void showBoosts(
@NonNull final ActMain activity
, @NonNull final SavedAccount access_info
, @NonNull final TootAccount who
, final boolean bShow
){
if( access_info.isMe( who ) ){
Utils.showToast( activity, false, R.string.it_is_you );
return;
}
new TootTaskRunner( activity, true ).run( access_info, new TootTask() {
@Override public TootApiResult background( @NonNull TootApiClient client ){
JSONObject content = new JSONObject();
try{
content.put( "reblogs", bShow );
}catch( Throwable ex ){
return new TootApiResult( Utils.formatError( ex, "json encoding error" ) );
}
Request.Builder request_builder = new Request.Builder().post(
RequestBody.create(
TootApiClient.MEDIA_TYPE_JSON
, content.toString()
) );
TootApiResult result = client.request( "/api/v1/accounts/" + who.id + "/follow", request_builder );
if( result != null && result.object != null ){
relation = TootRelationShip.parse( result.object );
}
return result;
}
TootRelationShip relation;
@Override public void handleResult( @Nullable TootApiResult result ){
if( result == null ) return; // cancelled.
if( relation != null ){
ActionUtils.saveUserRelation( access_info, relation );
Utils.showToast( activity, true, R.string.operation_succeeded );
}else{
Utils.showToast( activity, true, result.error );
}
}
} );
}
// メンションを含むトゥートを作る
private static void mention(
@NonNull final ActMain activity
, @NonNull final SavedAccount account
, @NonNull final String initial_text
){
ActPost.open(
activity
, ActMain.REQUEST_CODE_POST
, account.db_id
, initial_text
);
}
// メンションを含むトゥートを作る
public static void mention(
@NonNull final ActMain activity
, @NonNull final SavedAccount account
, @NonNull final TootAccount who
){
mention( activity, account, "@" + account.getFullAcct( who ) + " " );
}
// メンションを含むトゥートを作る
public static void mentionFromAnotherAccount(
@NonNull final ActMain activity
, @NonNull final SavedAccount access_info
, @Nullable final TootAccount who
){
if( who == null ) return;
String who_host = access_info.getAccountHost( who );
final String initial_text = "@" + access_info.getFullAcct( who ) + " ";
AccountPicker.pick(
activity
, false
, false
, activity.getString( R.string.account_picker_toot )
, ActionUtils.makeAccountListNonPseudo( activity, who_host )
, new AccountPicker.AccountPickerCallback() {
@Override public void onAccountPicked( @NonNull SavedAccount ai ){
mention( activity, ai, initial_text );
}
} );
}
}