リファクタ
This commit is contained in:
parent
63aa33c02d
commit
276d4fd4c5
1
.idea/dictionaries/tateisu.xml
generated
1
.idea/dictionaries/tateisu.xml
generated
@ -16,6 +16,7 @@
|
||||
<w>firebase</w>
|
||||
<w>foregrounder</w>
|
||||
<w>gifv</w>
|
||||
<w>github</w>
|
||||
<w>hashtag</w>
|
||||
<w>hashtags</w>
|
||||
<w>hohoemi</w>
|
||||
|
@ -57,8 +57,6 @@ dependencies {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
|
||||
// SDKのソースの27が提供されたタイミングで依存関係をまとめて上げる。
|
||||
// 現在特に問題を抱えていないし、それまでは依存関係のバージョンを上げない
|
||||
|
||||
compile 'com.android.support:support-v4:26.1.0'
|
||||
compile 'com.android.support:appcompat-v7:26.1.0'
|
||||
@ -69,7 +67,7 @@ dependencies {
|
||||
compile 'com.google.firebase:firebase-messaging:11.6.2'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'commons-io:commons-io:2.6'
|
||||
compile 'commons-io:commons-io:2.4' // 2.6にすると closeQuietly のかわりに try-with-resourceを使えと煩い
|
||||
compile 'uk.co.chrisjenx:calligraphy:2.3.0'
|
||||
compile 'com.github.woxthebox:draglistview:1.5.1'
|
||||
compile 'com.github.omadahealth:swipy:1.2.3@aar'
|
||||
@ -78,6 +76,9 @@ dependencies {
|
||||
compile project(':exif')
|
||||
|
||||
compile 'com.squareup.okhttp3:okhttp:3.9.1'
|
||||
|
||||
// com.github.bumptech.glide 4.x はサポートライブラリ27に依存してる
|
||||
// SDKのソースの27が提供されたら上げる
|
||||
compile 'com.github.bumptech.glide:glide:3.8.0'
|
||||
compile 'com.github.bumptech.glide:okhttp3-integration:1.5.0'
|
||||
|
||||
|
@ -319,6 +319,7 @@ public class ActColumnList extends AppCompatActivity {
|
||||
|
||||
private class MyListAdapter extends DragItemAdapter< MyItem, MyViewHolder > {
|
||||
|
||||
|
||||
MyListAdapter(){
|
||||
super();
|
||||
setHasStableIds( true );
|
||||
@ -337,10 +338,10 @@ public class ActColumnList extends AppCompatActivity {
|
||||
holder.bind( getItemList().get( position ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId( int position ){
|
||||
@Override public long getUniqueItemId( int position ){
|
||||
MyItem item = mItemList.get( position ); // mItemList は親クラスのメンバ変数
|
||||
return item.id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import android.content.ComponentName;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Typeface;
|
||||
@ -16,7 +15,6 @@ import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
@ -1774,8 +1772,8 @@ public class ActMain extends AppCompatActivity
|
||||
}
|
||||
|
||||
static final Pattern reUrlHashTag = Pattern.compile( "\\Ahttps://([^/]+)/tags/([^?#]+)(?:\\z|[?#])" );
|
||||
static final Pattern reUserPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/@]+)(?:\\z|[?#])" );
|
||||
static final Pattern reStatusPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/@]+)/(\\d+)(?:\\z|[?#])" );
|
||||
static final Pattern reUserPage = Pattern.compile( "\\Ahttps://([^/]+)/@([A-Za-z0-9_]+)(?:\\z|[?#])" );
|
||||
static final Pattern reStatusPage = Pattern.compile( "\\Ahttps://([^/]+)/@([A-Za-z0-9_]+)/(\\d+)(?:\\z|[?#])" );
|
||||
|
||||
public void openChromeTab( final int pos, @Nullable final SavedAccount access_info, final String url, boolean noIntercept ){
|
||||
try{
|
||||
@ -2589,15 +2587,6 @@ public class ActMain extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
// OStatus
|
||||
static final Pattern reTootUriOS = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE );
|
||||
// ActivityPub 1
|
||||
static final Pattern reTootUriAP1 = Pattern.compile( "https?://([^/]+)/users/[^/]+/statuses/(\\d+)" );
|
||||
// ActivityPub 2
|
||||
static final Pattern reTootUriAP2 = Pattern.compile( "https?://([^/]+)/@[^/]+/(\\d+)" );
|
||||
|
||||
// static final Pattern reUriActivityPubToot = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE );
|
||||
|
||||
public void openStatusOtherInstance( int pos, @NonNull SavedAccount access_info, @Nullable TootStatusLike status ){
|
||||
// アカウント情報がないと出来ないことがある
|
||||
if( status == null || status.account == null ) return;
|
||||
@ -2609,13 +2598,16 @@ public class ActMain extends AppCompatActivity
|
||||
);
|
||||
}else if( status instanceof TSToot ){
|
||||
// Tootsearch ではステータスのアクセス元ホストは分からない
|
||||
// ステータスの投稿元ホストでのIDも分からない
|
||||
|
||||
// uri から投稿元タンスでのステータスIDを調べる
|
||||
long status_id_original = TootStatusLike.parseStatusId( status );
|
||||
|
||||
openStatusOtherInstance( pos, access_info, status.url
|
||||
, - 1L
|
||||
, status_id_original
|
||||
, null, - 1L
|
||||
);
|
||||
|
||||
}else if( status instanceof TootStatus ){
|
||||
TootStatus ts = (TootStatus) status;
|
||||
if( status.host_original.equals( status.host_access ) ){
|
||||
// TLアカウントのホストとトゥートのアカウントのホストが同じ場合
|
||||
openStatusOtherInstance( pos, access_info, status.url
|
||||
@ -2624,28 +2616,8 @@ public class ActMain extends AppCompatActivity
|
||||
);
|
||||
}else{
|
||||
// TLアカウントのホストとトゥートのアカウントのホストが異なる場合
|
||||
|
||||
long status_id_original = - 1L;
|
||||
|
||||
try{
|
||||
// UriにステータスIDが含まれている場合がある
|
||||
Matcher m = reTootUriOS.matcher( ts.uri );
|
||||
if( m.find() ){
|
||||
status_id_original = Long.parseLong( m.group( 2 ), 10 );
|
||||
}else{
|
||||
m = reTootUriAP1.matcher( ts.uri );
|
||||
if( m.find() ){
|
||||
status_id_original = Long.parseLong( m.group( 2 ), 10 );
|
||||
}else{
|
||||
m = reTootUriAP2.matcher( ts.uri );
|
||||
if( m.find() ){
|
||||
status_id_original = Long.parseLong( m.group( 2 ), 10 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "openStatusOtherInstance: cant parse tag: %s", ts.uri );
|
||||
}
|
||||
// uri から投稿元タンスでのステータスIDを調べる
|
||||
long status_id_original = TootStatusLike.parseStatusId( status );
|
||||
|
||||
openStatusOtherInstance( pos, access_info, status.url
|
||||
, status_id_original
|
||||
@ -2673,12 +2645,20 @@ public class ActMain extends AppCompatActivity
|
||||
}
|
||||
} );
|
||||
|
||||
// トゥートの投稿元タンスにあるアカウント
|
||||
ArrayList< SavedAccount > local_account_list = new ArrayList<>();
|
||||
|
||||
// TLを読んだタンスにあるアカウント
|
||||
ArrayList< SavedAccount > access_account_list = new ArrayList<>();
|
||||
|
||||
// その他のタンスにあるアカウント
|
||||
ArrayList< SavedAccount > other_account_list = new ArrayList<>();
|
||||
|
||||
for( SavedAccount a : SavedAccount.loadAccountList( ActMain.this, log ) ){
|
||||
|
||||
// 疑似アカウントは後でまとめて処理する
|
||||
if( a.isPseudo() ) continue;
|
||||
|
||||
if( status_id_original >= 0L && host_original.equalsIgnoreCase( a.host ) ){
|
||||
// アクセス情報+ステータスID でアクセスできるなら
|
||||
// 同タンスのアカウントならステータスIDの変換なしに表示できる
|
||||
@ -2800,8 +2780,7 @@ public class ActMain extends AppCompatActivity
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleResult( TootApiResult result ){
|
||||
@Override protected void handleResult( TootApiResult result ){
|
||||
|
||||
if( result == null ){
|
||||
// cancelled.
|
||||
|
@ -111,10 +111,12 @@ public class ActMutedApp extends AppCompatActivity {
|
||||
Cursor cursor = MutedApp.createCursor();
|
||||
if( cursor != null ){
|
||||
try{
|
||||
int idx_id = cursor.getColumnIndex( MutedApp.COL_ID );
|
||||
int idx_name = cursor.getColumnIndex( MutedApp.COL_NAME );
|
||||
while( cursor.moveToNext() ){
|
||||
long id = cursor.getLong( idx_id );
|
||||
String name = cursor.getString( idx_name );
|
||||
MyItem item = new MyItem( name );
|
||||
MyItem item = new MyItem( id, name );
|
||||
tmp_list.add( item );
|
||||
}
|
||||
|
||||
@ -130,9 +132,11 @@ public class ActMutedApp extends AppCompatActivity {
|
||||
|
||||
// リスト要素のデータ
|
||||
static class MyItem {
|
||||
final long id;
|
||||
final String name;
|
||||
|
||||
MyItem( String name ){
|
||||
MyItem( long id,String name ){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@ -212,10 +216,9 @@ public class ActMutedApp extends AppCompatActivity {
|
||||
holder.bind( getItemList().get( position ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId( int position ){
|
||||
@Override public long getUniqueItemId( int position ){
|
||||
MyItem item = mItemList.get( position ); // mItemList は親クラスのメンバ変数
|
||||
return item.name.hashCode();
|
||||
return item.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,10 +111,12 @@ public class ActMutedWord extends AppCompatActivity {
|
||||
Cursor cursor = MutedWord.createCursor();
|
||||
if( cursor != null ){
|
||||
try{
|
||||
int idx_id = cursor.getColumnIndex( MutedWord.COL_ID );
|
||||
int idx_name = cursor.getColumnIndex( MutedWord.COL_NAME );
|
||||
while( cursor.moveToNext() ){
|
||||
long id = cursor.getLong( idx_id );
|
||||
String name = cursor.getString( idx_name );
|
||||
MyItem item = new MyItem( name );
|
||||
MyItem item = new MyItem( id, name );
|
||||
tmp_list.add( item );
|
||||
}
|
||||
|
||||
@ -130,9 +132,11 @@ public class ActMutedWord extends AppCompatActivity {
|
||||
|
||||
// リスト要素のデータ
|
||||
static class MyItem {
|
||||
final long id;
|
||||
final String name;
|
||||
|
||||
MyItem( String name ){
|
||||
MyItem( long id,String name ){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@ -213,9 +217,9 @@ public class ActMutedWord extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId( int position ){
|
||||
public long getUniqueItemId( int position ){
|
||||
MyItem item = mItemList.get( position ); // mItemList は親クラスのメンバ変数
|
||||
return item.name.hashCode();
|
||||
return item.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||
import jp.juggler.subwaytooter.api.entity.TootTag;
|
||||
import jp.juggler.subwaytooter.api_msp.MSPClient;
|
||||
import jp.juggler.subwaytooter.api_msp.entity.MSPToot;
|
||||
import jp.juggler.subwaytooter.api_tootsearch.TootsearchClient;
|
||||
import jp.juggler.subwaytooter.api_tootsearch.TSClient;
|
||||
import jp.juggler.subwaytooter.api_tootsearch.entity.TSToot;
|
||||
import jp.juggler.subwaytooter.table.AcctColor;
|
||||
import jp.juggler.subwaytooter.table.AcctSet;
|
||||
@ -1851,7 +1851,7 @@ import jp.juggler.subwaytooter.util.Utils;
|
||||
list_tmp = new ArrayList<>();
|
||||
result = new TootApiResult();
|
||||
}else{
|
||||
result = TootsearchClient.search( context, search_query, max_id, new TootsearchClient.Callback() {
|
||||
result = TSClient.search( context, search_query, max_id, new TSClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return isCancelled() || is_dispose.get();
|
||||
}
|
||||
@ -1869,7 +1869,7 @@ import jp.juggler.subwaytooter.util.Utils;
|
||||
if( result != null ){
|
||||
if( result.object != null ){
|
||||
// max_id の更新
|
||||
max_id = TootsearchClient.getMaxId( result.object, max_id );
|
||||
max_id = TSClient.getMaxId( result.object, max_id );
|
||||
// リストデータの用意
|
||||
TSToot.List search_result = TSToot.parseList( context, access_info, result.object );
|
||||
list_tmp = new ArrayList<>();
|
||||
@ -2801,7 +2801,7 @@ import jp.juggler.subwaytooter.util.Utils;
|
||||
list_tmp = new ArrayList<>();
|
||||
result = new TootApiResult( context.getString( R.string.end_of_list ) );
|
||||
}else{
|
||||
result = TootsearchClient.search( context, search_query, max_id, new TootsearchClient.Callback() {
|
||||
result = TSClient.search( context, search_query, max_id, new TSClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return isCancelled() || is_dispose.get();
|
||||
}
|
||||
@ -2818,15 +2818,13 @@ import jp.juggler.subwaytooter.util.Utils;
|
||||
} );
|
||||
if( result != null && result.object != null ){
|
||||
// max_id の更新
|
||||
max_id = TootsearchClient.getMaxId( result.object, max_id );
|
||||
max_id = TSClient.getMaxId( result.object, max_id );
|
||||
// リストデータの用意
|
||||
TSToot.List search_result = TSToot.parseList( context, access_info, result.object );
|
||||
if( search_result != null ){
|
||||
list_tmp = new ArrayList<>();
|
||||
addWithFilter( list_tmp, search_result );
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -828,7 +828,8 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||
|
||||
case R.id.btnSearchTag:
|
||||
if( search_tag != null ){
|
||||
activity.openHashTag( activity.nextPosition( column ), access_info, search_tag.substring( 1 ) );
|
||||
// search_tag は#を含まない
|
||||
activity.openHashTag( activity.nextPosition( column ), access_info, search_tag );
|
||||
}else if( gap != null ){
|
||||
column.startGap( gap );
|
||||
}else if( domain_block != null ){
|
||||
|
@ -13,7 +13,6 @@ import android.widget.PopupWindow;
|
||||
import jp.juggler.subwaytooter.api.entity.TootNotification;
|
||||
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.UserRelation;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
|
@ -21,6 +21,8 @@ import jp.juggler.subwaytooter.util.Utils;
|
||||
public class TootAccount {
|
||||
private static final LogCategory log = new LogCategory( "TootAccount" );
|
||||
|
||||
public static final Pattern reAccountUrl = Pattern.compile( "\\Ahttps://([A-Za-z0-9.-]+)/@([A-Za-z0-9_]+)(?:\\z|[?#])" );
|
||||
|
||||
public static class List extends ArrayList< TootAccount > {
|
||||
|
||||
}
|
||||
@ -28,7 +30,7 @@ public class TootAccount {
|
||||
// The ID of the account
|
||||
public long id;
|
||||
|
||||
// The username of the account
|
||||
// The username of the account /[A-Za-z0-9_]{1,30}/
|
||||
public String username;
|
||||
|
||||
// Equals username for local users, includes @domain for remote ones
|
||||
@ -108,13 +110,12 @@ public class TootAccount {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public static TootAccount parse( Context context, LinkClickContext account, JSONObject src ){
|
||||
public static TootAccount parse( @NonNull Context context, @NonNull LinkClickContext account, @Nullable JSONObject src ){
|
||||
return parse( context, account, src, new TootAccount() );
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public static TootAccount parse( Context context, LinkClickContext account, JSONObject src, TootAccount dst ){
|
||||
public static TootAccount parse( @NonNull Context context, @NonNull LinkClickContext account, @Nullable JSONObject src, @NonNull TootAccount dst ){
|
||||
if( src == null ) return null;
|
||||
try{
|
||||
dst.id = Utils.optLongX( src, "id", - 1L );
|
||||
@ -178,8 +179,6 @@ public class TootAccount {
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NonNull
|
||||
public static List parseList( Context context, LinkClickContext account, JSONArray array ){
|
||||
List result = new List();
|
||||
@ -198,7 +197,6 @@ public class TootAccount {
|
||||
|
||||
private static final Pattern reWhitespace = Pattern.compile( "[\\s\\t\\x0d\\x0a]+" );
|
||||
|
||||
|
||||
public Spannable decodeDisplayName( Context context ){
|
||||
|
||||
// remove white spaces
|
||||
|
@ -1,6 +1,7 @@
|
||||
package jp.juggler.subwaytooter.api.entity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
@ -8,14 +9,19 @@ import android.text.TextUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.api_tootsearch.entity.TSToot;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
public abstract class TootStatusLike extends TootId {
|
||||
|
||||
static final LogCategory log = new LogCategory("TootStatusLike");
|
||||
|
||||
//URL to the status page (can be remote)
|
||||
public String url;
|
||||
|
||||
@ -115,4 +121,54 @@ public abstract class TootStatusLike extends TootId {
|
||||
public int originalLineCount;
|
||||
}
|
||||
public AutoCW auto_cw;
|
||||
|
||||
|
||||
// OStatus
|
||||
static final Pattern reTootUriOS = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE );
|
||||
// ActivityPub 1
|
||||
static final Pattern reTootUriAP1 = Pattern.compile( "https?://([^/]+)/users/[A-Za-z0-9_]+/statuses/(\\d+)" );
|
||||
// ActivityPub 2
|
||||
static final Pattern reTootUriAP2 = Pattern.compile( "https?://([^/]+)/@[A-Za-z0-9_]+/(\\d+)" );
|
||||
|
||||
public static long parseStatusId( @NonNull TootStatusLike status ){
|
||||
|
||||
String uri;
|
||||
if( status instanceof TootStatus ){
|
||||
uri = ( (TootStatus) status ).uri;
|
||||
}else if( status instanceof TSToot ){
|
||||
uri = ( (TSToot) status ).uri;
|
||||
}else{
|
||||
log.d( "parseStatusId: unsupported status type: %s", status.getClass().getSimpleName() );
|
||||
return - 1L;
|
||||
}
|
||||
|
||||
try{
|
||||
Matcher m;
|
||||
|
||||
// https://friends.nico/users/(who)/statuses/(status_id)
|
||||
m = reTootUriAP1.matcher( uri );
|
||||
if( m.find() ){
|
||||
return Long.parseLong( m.group( 2 ), 10 );
|
||||
}
|
||||
|
||||
// tag:mstdn.osaka,2017-12-19:objectId=5672321:objectType=Status
|
||||
m = reTootUriOS.matcher( uri );
|
||||
if( m.find() ){
|
||||
return Long.parseLong( m.group( 2 ), 10 );
|
||||
}
|
||||
|
||||
//
|
||||
m = reTootUriAP2.matcher( uri );
|
||||
if( m.find() ){
|
||||
return Long.parseLong( m.group( 2 ), 10 );
|
||||
}
|
||||
|
||||
log.d( "parseStatusId: unsupported status uri: %s", uri );
|
||||
|
||||
}catch( Throwable ex ){
|
||||
log.e( ex, "parseStatusId: cant parse tag: %s", uri );
|
||||
}
|
||||
|
||||
return - 1L;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import android.text.TextUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
@ -19,10 +18,8 @@ import jp.juggler.subwaytooter.util.Utils;
|
||||
public class MSPAccount extends TootAccount {
|
||||
private static final LogCategory log = new LogCategory( "MSPAccount" );
|
||||
|
||||
private static final Pattern reAccountUrl = Pattern.compile( "\\Ahttps://([^/#?]+)/@([^/#?]+)\\z" );
|
||||
|
||||
@Nullable
|
||||
static TootAccount parseAccount( @NonNull Context context, SavedAccount access_info, JSONObject src ){
|
||||
static TootAccount parseAccount( @NonNull Context context, @NonNull SavedAccount access_info, @Nullable JSONObject src ){
|
||||
|
||||
if( src == null ) return null;
|
||||
|
||||
|
@ -1,19 +1,15 @@
|
||||
package jp.juggler.subwaytooter.api_tootsearch;
|
||||
|
||||
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.api.TootApiResult;
|
||||
import jp.juggler.subwaytooter.api_msp.MSPApiResult;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
import okhttp3.Call;
|
||||
@ -21,17 +17,14 @@ import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class TootsearchClient {
|
||||
private 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";
|
||||
public class TSClient {
|
||||
private static final LogCategory log = new LogCategory( "TSClient" );
|
||||
|
||||
private static final OkHttpClient ok_http_client = App1.ok_http_client;
|
||||
|
||||
public interface Callback {
|
||||
boolean isApiCancelled();
|
||||
|
||||
void publishApiProgress( String s );
|
||||
}
|
||||
|
||||
@ -41,22 +34,18 @@ public class TootsearchClient {
|
||||
, @NonNull String max_id // 空文字列、もしくはfromに指定するパラメータ
|
||||
, @NonNull Callback callback
|
||||
){
|
||||
SharedPreferences pref = Pref.pref( context );
|
||||
String url = "https://tootsearch.chotto.moe/api/v1/search"
|
||||
+ "?sort=" + Uri.encode( "created_at:desc" )
|
||||
+ "&from=" + max_id
|
||||
+ "&q=" + Uri.encode( query );
|
||||
|
||||
Response response;
|
||||
|
||||
callback.publishApiProgress( "waiting search result..." );
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("https://tootsearch.chotto.moe/api/v1/search?sort=created_at%3Adesc");
|
||||
sb.append( "&from=").append(max_id );
|
||||
sb.append( "&q=").append( Uri.encode( query ) );
|
||||
String url = sb.toString();
|
||||
|
||||
try{
|
||||
Request request = new Request.Builder()
|
||||
.url( url )
|
||||
.build();
|
||||
|
||||
callback.publishApiProgress( "waiting search result..." );
|
||||
Call call = ok_http_client.newCall( request );
|
||||
response = call.execute();
|
||||
}catch( Throwable ex ){
|
||||
@ -70,6 +59,7 @@ public class TootsearchClient {
|
||||
log.d( "response failed." );
|
||||
return new TootApiResult( Utils.formatResponse( response, url ) );
|
||||
}
|
||||
|
||||
try{
|
||||
//noinspection ConstantConditions
|
||||
String json = response.body().string();
|
@ -1,98 +0,0 @@
|
||||
package jp.juggler.subwaytooter.api_tootsearch.entity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.NicoProfileEmoji;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
public class TSAccount extends TootAccount {
|
||||
private static final LogCategory log = new LogCategory( "TSAccount" );
|
||||
|
||||
private static final Pattern reAccountUrl = Pattern.compile( "\\Ahttps://([^/#?]+)/@([^/#?]+)\\z" );
|
||||
|
||||
@Nullable
|
||||
static TootAccount parseAccount( @NonNull Context context, SavedAccount access_info, JSONObject src ){
|
||||
|
||||
if( src == null ) return null;
|
||||
|
||||
TSAccount dst = new TSAccount();
|
||||
|
||||
dst.url = Utils.optStringX( src, "url" );
|
||||
if( TextUtils.isEmpty( dst.url ) ){
|
||||
log.e( "parseAccount: missing url" );
|
||||
return null;
|
||||
}
|
||||
|
||||
// tootsearch のアカウントのIDはどのタンス上のものか分からない
|
||||
////// dst.id = Utils.optLongX( src, "id" );
|
||||
dst.id = -1L;
|
||||
dst.username = Utils.optStringX( src, "username" );
|
||||
|
||||
dst.id = Utils.optLongX( src, "id", - 1L );
|
||||
dst.username = Utils.optStringX( src, "username" );
|
||||
|
||||
dst.acct = Utils.optStringX( src, "acct" );
|
||||
if( dst.acct == null ){
|
||||
dst.acct = "?@?";
|
||||
}else if( -1 == dst.acct.indexOf( '@' ) ){
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
// 絵文字データは先に読んでおく
|
||||
dst.profile_emojis = NicoProfileEmoji.parseMap( src.optJSONArray( "profile_emojis" ) );
|
||||
|
||||
String sv = Utils.optStringX( src, "display_name" );
|
||||
dst.setDisplayName( context, dst.username, sv );
|
||||
|
||||
dst.locked = src.optBoolean( "locked" );
|
||||
dst.created_at = Utils.optStringX( src, "created_at" );
|
||||
dst.followers_count = Utils.optLongX( src, "followers_count" );
|
||||
dst.following_count = Utils.optLongX( src, "following_count" );
|
||||
dst.statuses_count = Utils.optLongX( src, "statuses_count" );
|
||||
|
||||
dst.note = Utils.optStringX( src, "note" );
|
||||
dst.decoded_note = new DecodeOptions()
|
||||
.setShort( true )
|
||||
.setDecodeEmoji( true )
|
||||
.setProfileEmojis( dst.profile_emojis )
|
||||
.decodeHTML( context, access_info, dst.note );
|
||||
|
||||
dst.avatar = Utils.optStringX( src, "avatar" ); // "https:\/\/mastodon.juggler.jp\/system\/accounts\/avatars\/000\/000\/148\/original\/0a468974fac5a448.PNG?1492081886",
|
||||
dst.avatar_static = Utils.optStringX( src, "avatar_static" ); // "https:\/\/mastodon.juggler.jp\/system\/accounts\/avatars\/000\/000\/148\/original\/0a468974fac5a448.PNG?1492081886",
|
||||
dst.header = Utils.optStringX( src, "header" ); // "https:\/\/mastodon.juggler.jp\/headers\/original\/missing.png"
|
||||
dst.header_static = Utils.optStringX( src, "header_static" ); // "https:\/\/mastodon.juggler.jp\/headers\/original\/missing.png"}
|
||||
|
||||
// ,"nico_url":null
|
||||
|
||||
dst.time_created_at = TootStatus.parseTime( dst.created_at );
|
||||
|
||||
dst.source = parseSource( src.optJSONObject( "source" ) );
|
||||
|
||||
// JSONObject o = src.optJSONObject( "moved" );
|
||||
// if( o != null ){
|
||||
// dst.moved = TootAccount.parse( context, account, o);
|
||||
// }
|
||||
|
||||
return dst;
|
||||
|
||||
}
|
||||
}
|
@ -10,13 +10,15 @@ import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.CustomEmoji;
|
||||
import jp.juggler.subwaytooter.api.entity.NicoProfileEmoji;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAttachment;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||
import jp.juggler.subwaytooter.api_tootsearch.TootsearchClient;
|
||||
import jp.juggler.subwaytooter.api_tootsearch.TSClient;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.DecodeOptions;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
@ -39,7 +41,7 @@ public class TSToot extends TootStatusLike {
|
||||
if( src == null ) return null;
|
||||
TSToot dst = new TSToot();
|
||||
|
||||
dst.account = TSAccount.parseAccount( context, access_info, src.optJSONObject( "account" ) );
|
||||
dst.account = parseAccount( context, access_info, src.optJSONObject( "account" ) );
|
||||
if( dst.account == null ){
|
||||
log.e( "missing status account" );
|
||||
return null;
|
||||
@ -47,7 +49,6 @@ public class TSToot extends TootStatusLike {
|
||||
|
||||
dst.json = src;
|
||||
|
||||
|
||||
// 絵文字マップは割と最初の方で読み込んでおきたい
|
||||
dst.custom_emojis = CustomEmoji.parseMap( src.optJSONArray( "emojis" ), access_info.host );
|
||||
dst.profile_emojis = NicoProfileEmoji.parseMap( src.optJSONArray( "profile_emojis" ) );
|
||||
@ -87,9 +88,10 @@ public class TSToot extends TootStatusLike {
|
||||
public static class List extends ArrayList< TSToot > {
|
||||
}
|
||||
|
||||
@NonNull public static TSToot.List parseList( @NonNull Context context, SavedAccount access_info, @NonNull JSONObject root ){
|
||||
@NonNull
|
||||
public static TSToot.List parseList( @NonNull Context context, SavedAccount access_info, @NonNull JSONObject root ){
|
||||
TSToot.List list = new TSToot.List();
|
||||
JSONArray array = TootsearchClient.getHits( root );
|
||||
JSONArray array = TSClient.getHits( root );
|
||||
if( array != null ){
|
||||
for( int i = 0, ie = array.length() ; i < ie ; ++ i ){
|
||||
JSONObject src = array.optJSONObject( i );
|
||||
@ -128,4 +130,34 @@ public class TSToot extends TootStatusLike {
|
||||
@Override public boolean canPin( SavedAccount access_info ){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TootAccount parseAccount( @NonNull Context context, @NonNull SavedAccount access_info, @Nullable JSONObject src ){
|
||||
|
||||
TootAccount dst = TootAccount.parse( context, access_info, src );
|
||||
if( dst != null ){
|
||||
|
||||
// tootsearch のアカウントのIDはどのタンス上のものか分からない
|
||||
dst.id = - 1L;
|
||||
|
||||
// この後の処理でURLを使うので、URLがないならパースエラーとする
|
||||
if( TextUtils.isEmpty( dst.url ) ){
|
||||
log.e( "parseAccount: missing url" );
|
||||
return null;
|
||||
}
|
||||
|
||||
if( - 1 == dst.acct.indexOf( '@' ) ){
|
||||
Matcher m = TootAccount.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;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,8 @@ public class AcctColor {
|
||||
|
||||
private static final char CHAR_REPLACE = 0x328A;
|
||||
|
||||
@NonNull public static CharSequence getStringWithNickname( @NonNull Context context, int string_id , @NonNull String acct ){
|
||||
@NonNull
|
||||
public static CharSequence getStringWithNickname( @NonNull Context context, int string_id, @NonNull String acct ){
|
||||
AcctColor ac = load( acct );
|
||||
String name = ! TextUtils.isEmpty( ac.nickname ) ? Utils.sanitizeBDI( ac.nickname ) : acct;
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder( context.getString( string_id, new String( new char[]{ CHAR_REPLACE } ) ) );
|
||||
|
@ -14,6 +14,7 @@ public class MutedApp {
|
||||
private static final LogCategory log = new LogCategory( "MutedApp" );
|
||||
|
||||
public static final String table = "app_mute";
|
||||
public static final String COL_ID = "_id";
|
||||
public static final String COL_NAME = "name";
|
||||
private static final String COL_TIME_SAVE = "time_save";
|
||||
|
||||
|
@ -13,6 +13,7 @@ public class MutedWord {
|
||||
private static final LogCategory log = new LogCategory( "MutedWord" );
|
||||
|
||||
public static final String table = "word_mute";
|
||||
public static final String COL_ID = "_id";
|
||||
public static final String COL_NAME = "name";
|
||||
private static final String COL_TIME_SAVE = "time_save";
|
||||
|
||||
|
@ -87,12 +87,10 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
public boolean confirm_unfollow;
|
||||
public boolean confirm_post;
|
||||
|
||||
|
||||
public String notification_tag;
|
||||
public String register_key;
|
||||
public long register_time;
|
||||
|
||||
|
||||
private final AtomicReference< TootInstance > refInstance = new AtomicReference<>( null );
|
||||
private static final long INSTANCE_INFORMATION_EXPIRE = 60000L * 5;
|
||||
|
||||
@ -104,11 +102,11 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setInstance( @NonNull TootInstance instance ){
|
||||
refInstance.set( instance );
|
||||
}
|
||||
|
||||
|
||||
// アプリデータのインポート時に呼ばれる
|
||||
public static void onDBDelete( SQLiteDatabase db ){
|
||||
try{
|
||||
@ -268,7 +266,8 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
return acct.equals( "?@?" );
|
||||
}
|
||||
|
||||
private static @Nullable SavedAccount parse( Context context, Cursor cursor ) throws JSONException{
|
||||
private static @Nullable
|
||||
SavedAccount parse( Context context, Cursor cursor ) throws JSONException{
|
||||
JSONObject src = new JSONObject( cursor.getString( cursor.getColumnIndex( COL_ACCOUNT ) ) );
|
||||
SavedAccount dst = new SavedAccount();
|
||||
dst = (SavedAccount) parse( context, dst, src, dst );
|
||||
@ -519,7 +518,6 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public @NonNull String getAccountHost( @Nullable String acct ){
|
||||
if( acct != null ){
|
||||
@ -607,14 +605,6 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
return "?".equals( username );
|
||||
}
|
||||
|
||||
private static final Pattern reAcctUrl = Pattern.compile( "\\Ahttps://([A-Za-z0-9.-]+)/@([A-Za-z0-9_]+)\\z" );
|
||||
|
||||
@Override public AcctColor findAcctColor( String url ){
|
||||
Matcher m = reAcctUrl.matcher( url );
|
||||
if( m.find() ) return AcctColor.load( m.group( 2 ) + "@" + m.group( 1 ) );
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long getCount(){
|
||||
try{
|
||||
Cursor cursor = App1.getDB().query( table, new String[]{ "count(*)" }, null, null, null, null, null );
|
||||
@ -709,4 +699,14 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
String host = who.getAcctHost();
|
||||
return host != null ? host : this.host;
|
||||
}
|
||||
|
||||
// implements LinkClickContext
|
||||
@Override @Nullable public AcctColor findAcctColor( @Nullable String url ){
|
||||
if( url != null ){
|
||||
Matcher m = TootAccount.reAccountUrl.matcher( url );
|
||||
if( m.find() ) return AcctColor.load( m.group( 2 ) + "@" + m.group( 1 ) );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import java.util.regex.Pattern;
|
||||
import jp.juggler.subwaytooter.App1;
|
||||
import jp.juggler.subwaytooter.Pref;
|
||||
import jp.juggler.subwaytooter.R;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAttachment;
|
||||
import jp.juggler.subwaytooter.api.entity.TootMention;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
@ -99,12 +100,11 @@ public class HTMLDecoder {
|
||||
|
||||
private static final boolean DEBUG_HTML_PARSER = false;
|
||||
|
||||
static final Pattern reUserPage = Pattern.compile( "\\Ahttps://([^/]+)/@([^?#/]+)(?:\\z|\\?)" );
|
||||
|
||||
static HashSet< String > block_tag;
|
||||
|
||||
private static void prepareTagInformation(){
|
||||
synchronized( reUserPage ){
|
||||
synchronized( log ){
|
||||
if( block_tag == null ){
|
||||
block_tag = new HashSet<>();
|
||||
block_tag.add( "div" );
|
||||
@ -273,7 +273,7 @@ public class HTMLDecoder {
|
||||
if( ! display_url.startsWith( "http" ) ){
|
||||
if( display_url.startsWith( "@" ) && href != null && App1.pref.getBoolean( Pref.KEY_MENTION_FULL_ACCT, false ) ){
|
||||
// メンションをfull acct にする
|
||||
Matcher m = reUserPage.matcher( href );
|
||||
Matcher m = TootAccount.reAccountUrl.matcher( href );
|
||||
if( m.find() ){
|
||||
return "@" + m.group( 2 ) + "@" + m.group( 1 );
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package jp.juggler.subwaytooter.util;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import jp.juggler.subwaytooter.table.AcctColor;
|
||||
|
||||
public interface LinkClickContext {
|
||||
|
||||
AcctColor findAcctColor( String url );
|
||||
@Nullable AcctColor findAcctColor( @Nullable String url );
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class MyClickableSpan extends ClickableSpan {
|
||||
@NonNull LinkClickContext lcc
|
||||
, @NonNull String text
|
||||
, @NonNull String url
|
||||
, AcctColor ac
|
||||
, @Nullable AcctColor ac
|
||||
, @Nullable Object tag
|
||||
){
|
||||
this.lcc = lcc;
|
||||
|
Loading…
x
Reference in New Issue
Block a user