- 通信タイムアウトの時間長を調整
- 他人のプロフで固定トゥートのPINアイコンが表示されなかった不具合の修正
- プロフィール編集で文字数を超過した場合に警告を表示する。警告を無視することもできる
- トゥート投稿時の残り文字数表示で、アンケート項目の文字数も数える
- トゥート投稿時の残り文字数表示で、アンケートが有効なら最大文字数を350に変更する
- アプリ設定に「アバターアイコンサイズ」を追加
- アプリ設定に「ローカルユーザのAcctのインスタンス部分を表示しない」を追加
This commit is contained in:
tateisu 2017-09-06 04:07:32 +09:00
parent 0aa599dc09
commit 58bf2f4ac4
20 changed files with 304 additions and 89 deletions

View File

@ -9,8 +9,8 @@ android {
applicationId "jp.juggler.subwaytooter"
minSdkVersion 21
targetSdkVersion 26
versionCode 135
versionName "1.3.5"
versionCode 137
versionName "1.3.7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

View File

@ -424,11 +424,11 @@ public class ActAccountSetting extends AppCompatActivity
break;
case R.id.btnDisplayName:
sendDisplayName();
sendDisplayName(false);
break;
case R.id.btnNote:
sendNote();
sendNote(false);
break;
case R.id.btnNotificationStyleEdit:
@ -576,6 +576,7 @@ public class ActAccountSetting extends AppCompatActivity
///////////////////////////////////////////////////
private void performAccessToken(){
//noinspection deprecation
final ProgressDialog progress = new ProgressDialog( ActAccountSetting.this );
final AsyncTask< Void, String, TootApiResult > task = new AsyncTask< Void, String, TootApiResult >() {
@ -692,6 +693,7 @@ public class ActAccountSetting extends AppCompatActivity
void loadProfile(){
// サーバから情報をロードする
//noinspection deprecation
final ProgressDialog progress = new ProgressDialog( this );
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
@ -772,6 +774,8 @@ public class ActAccountSetting extends AppCompatActivity
}
void updateCredential( final String form_data ){
//noinspection deprecation
final ProgressDialog progress = new ProgressDialog( this );
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
@ -814,7 +818,7 @@ public class ActAccountSetting extends AppCompatActivity
progress.dismiss();
}catch( Throwable ignored ){
}
loadProfile();
if( result == null ){
// cancelled.
}else if( data != null ){
@ -835,12 +839,55 @@ public class ActAccountSetting extends AppCompatActivity
progress.show();
}
private void sendDisplayName(){
updateCredential( "display_name=" + Uri.encode( etDisplayName.getText().toString() ) );
static final int max_length_display_name = 30;
static final int max_length_note = 160;
private void sendDisplayName(boolean bConfirmed){
String sv = etDisplayName.getText().toString();
if( !bConfirmed ){
int length = sv.codePointCount( 0,sv.length() );
if( length > max_length_display_name ){
new AlertDialog.Builder( this )
.setMessage( getString(R.string.length_warning
,getString(R.string.display_name)
,length,max_length_display_name
))
.setNegativeButton( R.string.cancel ,null)
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {
@Override public void onClick( DialogInterface dialogInterface, int i ){
sendDisplayName(true);
}
} )
.setCancelable( true )
.show();
return;
}
}
updateCredential( "display_name=" + Uri.encode(sv ) );
}
private void sendNote(){
updateCredential( "note=" + Uri.encode( etNote.getText().toString() ) );
private void sendNote(boolean bConfirmed){
String sv = etNote.getText().toString();
if( !bConfirmed ){
int length = sv.codePointCount( 0,sv.length() );
if( length > max_length_note ){
new AlertDialog.Builder( this )
.setMessage( getString(R.string.length_warning
,getString(R.string.note)
,length,max_length_note
))
.setNegativeButton( R.string.cancel ,null)
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() {
@Override public void onClick( DialogInterface dialogInterface, int i ){
sendNote(true);
}
} )
.setCancelable( true )
.show();
return;
}
}
updateCredential( "note=" + Uri.encode(sv ) );
}
private static final int PERMISSION_REQUEST_AVATAR = 1;

View File

@ -104,6 +104,7 @@ public class ActAppSetting extends AppCompatActivity
Switch swMentionFullAcct;
Switch swRelativeTimestamp;
Switch swDontUseActionButtonWithQuickTootBar;
Switch swShortAcctLocalUser;
Spinner spBackButtonAction;
Spinner spUITheme;
@ -148,6 +149,7 @@ public class ActAppSetting extends AppCompatActivity
EditText etAcctFontSize;
TextView tvTimelineFontSize;
TextView tvAcctFontSize;
EditText etAvatarIconSize;
static final float default_timeline_font_size = 14f;
static final float default_acct_font_size = 12f;
@ -217,6 +219,9 @@ public class ActAppSetting extends AppCompatActivity
swDontUseActionButtonWithQuickTootBar = findViewById( R.id.swDontUseActionButtonWithQuickTootBar );
swDontUseActionButtonWithQuickTootBar.setOnCheckedChangeListener( this );
swShortAcctLocalUser = findViewById( R.id.swShortAcctLocalUser );
swShortAcctLocalUser.setOnCheckedChangeListener( this );
cbNotificationSound = findViewById( R.id.cbNotificationSound );
cbNotificationVibration = findViewById( R.id.cbNotificationVibration );
cbNotificationLED = findViewById( R.id.cbNotificationLED );
@ -344,6 +349,8 @@ public class ActAppSetting extends AppCompatActivity
etAcctFontSize = findViewById( R.id.etAcctFontSize );
etAcctFontSize.addTextChangedListener( new SizeCheckTextWatcher( tvAcctFontSize, etAcctFontSize, default_acct_font_size ) );
etAvatarIconSize = findViewById( R.id.etAvatarIconSize );
tvTimelineFontUrl = findViewById( R.id.tvTimelineFontUrl );
tvTimelineFontBoldUrl = findViewById( R.id.tvTimelineFontBoldUrl );
@ -372,6 +379,7 @@ public class ActAppSetting extends AppCompatActivity
swMentionFullAcct.setChecked( pref.getBoolean( Pref.KEY_MENTION_FULL_ACCT, false ) );
swRelativeTimestamp.setChecked( pref.getBoolean( Pref.KEY_RELATIVE_TIMESTAMP, false ) );
swDontUseActionButtonWithQuickTootBar.setChecked( pref.getBoolean( Pref.KEY_DONT_USE_ACTION_BUTTON, false ) );
swShortAcctLocalUser.setChecked( pref.getBoolean( Pref.KEY_SHORT_ACCT_LOCAL_USER, false ) );
// Switch with default true
swDisableFastScroller.setChecked( pref.getBoolean( Pref.KEY_DISABLE_FAST_SCROLLER, true ) );
@ -401,6 +409,7 @@ public class ActAppSetting extends AppCompatActivity
etClientName.setText( pref.getString( Pref.KEY_CLIENT_NAME, "" ) );
etQuoteNameFormat.setText( pref.getString( Pref.KEY_QUOTE_NAME_FORMAT, "" ) );
etAutoCWLines.setText( pref.getString( Pref.KEY_AUTO_CW_LINES, "0" ) );
etAvatarIconSize.setText( pref.getString( Pref.KEY_AVATAR_ICON_SIZE, "48" ) );
etTimelineFontSize.setText( formatFontSize( pref.getFloat( Pref.KEY_TIMELINE_FONT_SIZE, Float.NaN ) ) );
etAcctFontSize.setText( formatFontSize( pref.getFloat( Pref.KEY_ACCT_FONT_SIZE, Float.NaN ) ) );
@ -441,6 +450,9 @@ public class ActAppSetting extends AppCompatActivity
.putBoolean( Pref.KEY_MENTION_FULL_ACCT, swMentionFullAcct.isChecked() )
.putBoolean( Pref.KEY_RELATIVE_TIMESTAMP, swRelativeTimestamp.isChecked() )
.putBoolean( Pref.KEY_DONT_USE_ACTION_BUTTON, swDontUseActionButtonWithQuickTootBar.isChecked() )
.putBoolean( Pref.KEY_SHORT_ACCT_LOCAL_USER, swShortAcctLocalUser.isChecked() )
.putBoolean( Pref.KEY_NOTIFICATION_SOUND, cbNotificationSound.isChecked() )
.putBoolean( Pref.KEY_NOTIFICATION_VIBRATION, cbNotificationVibration.isChecked() )
@ -467,6 +479,8 @@ public class ActAppSetting extends AppCompatActivity
.putString( Pref.KEY_CLIENT_NAME, etClientName.getText().toString().trim() )
.putString( Pref.KEY_QUOTE_NAME_FORMAT, etQuoteNameFormat.getText().toString() ) // not trimmed
.putString( Pref.KEY_AUTO_CW_LINES, etAutoCWLines.getText().toString() ) // not trimmed
.putString( Pref.KEY_AVATAR_ICON_SIZE, etAvatarIconSize.getText().toString().trim() )
.putFloat( Pref.KEY_TIMELINE_FONT_SIZE, parseFontSize( etTimelineFontSize.getText().toString().trim() ) )
.putFloat( Pref.KEY_ACCT_FONT_SIZE, parseFontSize( etAcctFontSize.getText().toString().trim() ) )

View File

@ -770,6 +770,8 @@ public class ActMain extends AppCompatActivity
Typeface timeline_font_bold;
boolean dont_crop_media_thumbnail;
boolean mShortAcctLocalUser;
int mAvatarIconSize;
View llQuickTootBar;
MyEditText etQuickToot;
@ -805,6 +807,23 @@ public class ActMain extends AppCompatActivity
}
}
mShortAcctLocalUser = pref.getBoolean( Pref.KEY_SHORT_ACCT_LOCAL_USER ,false);
{
float icon_size_dp = 48f;
try{
sv = pref.getString( Pref.KEY_AVATAR_ICON_SIZE, "48" );
float fv = Float.parseFloat( sv );
if( Float.isNaN( fv ) || Float.isInfinite( fv ) || fv < 1f ){
// error or bad range
}else{
icon_size_dp = fv;
}
}catch(Throwable ex){
log.trace( ex );
}
mAvatarIconSize = (int)(0.5f + icon_size_dp * density );
}
llEmpty = findViewById( R.id.llEmpty );
@ -2669,6 +2688,7 @@ public class ActMain extends AppCompatActivity
}
static final Pattern reUriOStatusToot = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE );
// static final Pattern reUriActivityPubToot = Pattern.compile( "tag:([^,]*),[^:]*:objectId=(\\d+):objectType=Status", Pattern.CASE_INSENSITIVE );
public void openStatusOtherInstance( int pos, @NonNull SavedAccount access_info, @NonNull TootStatusLike status ){
if( status.account == null ){
@ -2699,6 +2719,13 @@ public class ActMain extends AppCompatActivity
if( m.find() ){
status_id_original = Long.parseLong( m.group( 2 ), 10 );
// host_original = m.group( 1 );
}else{
// TODO ActivityPub対応
// m = reUriOStatusToot.matcher( ts.uri );
// if( m.find() ){
// status_id_original = Long.parseLong( m.group( 2 ), 10 );
// // host_original = m.group( 1 );
// }
}
}catch( Throwable ex ){
log.e( ex, "openStatusOtherInstance: cant parse tag: %s", ts.uri );

View File

@ -651,6 +651,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
@Override
public void onCheckedChanged( CompoundButton buttonView, boolean isChecked ){
showEnquete();
updateTextCount();
}
} );
@ -665,27 +666,31 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
}
} );
etContentWarning.addTextChangedListener( new TextWatcher() {
@Override
public void beforeTextChanged( CharSequence s, int start, int count, int after ){
etContentWarning.addTextChangedListener( text_watcher);
for(MyEditText et : list_etChoice ){
et.addTextChangedListener( text_watcher);
}
@Override public void onTextChanged( CharSequence s, int start, int before, int count ){
}
@Override public void afterTextChanged( Editable s ){
updateTextCount();
}
} );
scrollView.getViewTreeObserver().addOnScrollChangedListener( scroll_listener );
View v = findViewById( R.id.btnMore );
v.setOnClickListener( this );
}
final TextWatcher text_watcher = new TextWatcher() {
@Override public void beforeTextChanged( CharSequence charSequence, int i, int i1, int i2 ){
}
@Override public void onTextChanged( CharSequence charSequence, int i, int i1, int i2 ){
}
@Override public void afterTextChanged( Editable editable ){
updateTextCount();
}
};
final ViewTreeObserver.OnScrollChangedListener scroll_listener = new ViewTreeObserver.OnScrollChangedListener() {
@Override public void onScrollChanged(){
post_helper.onScrollChanged();
@ -694,12 +699,26 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener,
};
private void updateTextCount(){
String s = etContent.getText().toString();
int count_content = s.codePointCount( 0, s.length() );
s = cbContentWarning.isChecked() ? etContentWarning.getText().toString() : "";
int count_spoiler = s.codePointCount( 0, s.length() );
int length = 0;
int remain = 500 - count_content - count_spoiler;
String s = etContent.getText().toString();
length += s.codePointCount( 0, s.length() );
s = cbContentWarning.isChecked() ? etContentWarning.getText().toString() : "";
length += s.codePointCount( 0, s.length() );
int max;
if( !cbEnquete.isChecked() ){
max = 500;
}else{
max = 350;
for( MyEditText et : list_etChoice){
s = et.getText().toString();
length += s.codePointCount( 0, s.length() );
}
}
int remain = max - length;
tvCharCount.setText( Integer.toString( remain ) );
int color = Styler.getAttributeColor( this, remain < 0 ? R.attr.colorRegexFilterError : android.R.attr.textColorPrimary );
tvCharCount.setTextColor( color );

View File

@ -285,8 +285,8 @@ public class App1 extends Application {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout( 30, TimeUnit.SECONDS )
.readTimeout( 30, TimeUnit.SECONDS )
.writeTimeout( 30, TimeUnit.SECONDS )
.readTimeout( 60, TimeUnit.SECONDS )
.writeTimeout( 60, TimeUnit.SECONDS )
.pingInterval( 10, TimeUnit.SECONDS )
.connectionSpecs( spec_list );

View File

@ -317,6 +317,7 @@ public class AppDataExporter {
case Pref.KEY_MENTION_FULL_ACCT:
case Pref.KEY_RELATIVE_TIMESTAMP:
case Pref.KEY_DONT_USE_ACTION_BUTTON:
case Pref.KEY_SHORT_ACCT_LOCAL_USER:
boolean bv = reader.nextBoolean();
e.putBoolean( k, bv );
break;
@ -352,6 +353,7 @@ public class AppDataExporter {
case Pref.KEY_MASTODON_SEARCH_PORTAL_USER_TOKEN:
case Pref.KEY_QUOTE_NAME_FORMAT:
case Pref.KEY_AUTO_CW_LINES:
case Pref.KEY_AVATAR_ICON_SIZE:
String sv = reader.nextString();
e.putString( k, sv );
break;

View File

@ -219,6 +219,10 @@ class Column implements StreamReader.Callback {
String instance_uri;
// インスタンス情報カラムに表示するインスタンス情報
// (SavedAccount中のインスタンス情報とは異なるので注意)
TootInstance instance_information;
ScrollPosition scroll_save;
Column( @NonNull AppState app_state, @NonNull SavedAccount access_info, @NonNull Callback callback, int type, Object... params ){
@ -1185,14 +1189,15 @@ class Column implements StreamReader.Callback {
return result;
}
TootInstance instance_tmp;
TootApiResult getInstanceInformation( @NonNull TootApiClient client ,@Nullable String instance_name){
instance_tmp = null;
if( instance_name != null ) client.setInstance( instance_name );
TootApiResult result = client.request( "/api/v1/instance" );
if( result != null && result.object != null ){
TootInstance instance = TootInstance.parse( result.object );
if( instance != null ){
access_info.refInstance.set( instance );
}
instance_tmp = TootInstance.parse( result.object );
}
return result;
}
@ -1202,7 +1207,7 @@ class Column implements StreamReader.Callback {
TootApiResult result = client.request( path_base );
if( result != null && result.array != null ){
//
TootStatus.List src = TootStatus.parseList( context, access_info, result.array );
TootStatus.List src = TootStatus.parseList( context, access_info, result.array ,true);
for(TootStatus status : src ){
log.d("pinned: %s %s",status.id, status.decoded_content);
@ -1248,7 +1253,7 @@ class Column implements StreamReader.Callback {
// break;
// }
//
// src = TootStatus.parseList( context, access_info, result2.array );
// src = TootStatus.parseList( context, access_info, result2.array ,true);
// for(TootStatus status : src ){
// log.d("pinned: %s %s",status.id, status.decoded_content);
// }
@ -1459,12 +1464,16 @@ class Column implements StreamReader.Callback {
default:
case TAB_STATUS:
TootInstance instance = access_info.refInstance.get();
TootInstance instance = access_info.getInstance();
if( access_info.isPseudo() || instance == null ){
TootApiResult r2 = getInstanceInformation( client ,null );
instance = access_info.refInstance.get();
if( instance_tmp != null ){
instance = instance_tmp;
access_info.setInstance( instance_tmp );
}
if( access_info.isPseudo() ) return r2;
}
{
String s = String.format( Locale.JAPAN, PATH_ACCOUNT_STATUSES, profile_id );
if( with_attachment ) s = s + "&only_media=1";
@ -1612,8 +1621,13 @@ class Column implements StreamReader.Callback {
}
return result;
case TYPE_INSTANCE_INFORMATION:
return getInstanceInformation( client ,instance_uri);
case TYPE_INSTANCE_INFORMATION:{
result = getInstanceInformation( client, instance_uri );
if( instance_tmp != null ){
instance_information = instance_tmp;
}
return result;
}
}
}finally{
try{

View File

@ -75,7 +75,7 @@ class HeaderViewHolderInstance extends HeaderViewHolderBase implements View.OnCl
@Override void bindData( Column column ){
this.column = column;
this.instance = column.access_info.refInstance.get();
this.instance = column.instance_information;
if( instance == null ){
btnInstance.setText( "?" );

View File

@ -18,21 +18,24 @@ class HeaderViewHolderSearchDesc extends HeaderViewHolderBase {
, arg_activity.getLayoutInflater().inflate( R.layout.lv_header_search_desc, parent, false )
);
if( activity.timeline_font != null ){
Utils.scanView( viewRoot, new Utils.ScanViewCallback() {
@Override public void onScanView( View v ){
try{
if( v instanceof Button ){
// ボタンは太字なので触らない
}else if( v instanceof TextView ){
if( activity.timeline_font != null ){
( (TextView) v ).setTypeface( activity.timeline_font );
}
if( ! Float.isNaN( activity.timeline_font_size_sp ) ){
( (TextView) v ).setTextSize( activity.timeline_font_size_sp );
}
}
}catch( Throwable ex ){
log.trace( ex );
}
}
} );
}
CharSequence sv = HTMLDecoder.decodeHTML( activity, access_info, html, false, true, null );

View File

@ -243,6 +243,12 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
tvAcct.setTextSize( activity.acct_font_size_sp );
tvTime.setTextSize( activity.acct_font_size_sp );
}
ivBoosted.getLayoutParams().width =
ivFollow.getLayoutParams().width =
ivThumbnail.getLayoutParams().width =
ivThumbnail.getLayoutParams().height = activity.mAvatarIconSize;
}
void bind( Object item ){
@ -379,7 +385,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
ivBoosted.setImageResource( Styler.getAttributeResourceId( activity, icon_attr_id ) );
tvBoostedTime.setText( TootStatus.formatTime( tvBoostedTime.getContext(), time, true ) );
tvBoosted.setText( text );
setAcct( tvBoostedAcct, access_info.getFullAcct( who ) );
setAcct( tvBoostedAcct, access_info.getFullAcct( who ) ,who.acct);
}
private void showFollow( @NonNull TootAccount who ){
@ -387,7 +393,7 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
llFollow.setVisibility( View.VISIBLE );
ivFollow.setImageUrl( activity.pref, 16f, access_info.supplyBaseUrl( who.avatar_static ) );
tvFollowerName.setText( who.decoded_display_name );
setAcct( tvFollowerAcct, access_info.getFullAcct( who ) );
setAcct( tvFollowerAcct, access_info.getFullAcct( who ) ,who.acct );
UserRelation relation = UserRelation.load( access_info.db_id, who.id );
Styler.setFollowIcon( activity, btnFollow, ivFollowedBy, relation );
@ -399,8 +405,9 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
showStatusTime( activity, status );
account_thumbnail = status.account;
setAcct( tvAcct, access_info.getFullAcct( status.account ) );
TootAccount who = account_thumbnail = status.account;
setAcct( tvAcct, access_info.getFullAcct( who ) ,who == null ? "?" : who.acct );
if( status.account == null ){
tvName.setText( "?" );
@ -570,9 +577,9 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
tvTime.setText( sb );
}
private void setAcct( TextView tv, String acct ){
AcctColor ac = AcctColor.load( acct );
tv.setText( AcctColor.hasNickname( ac ) ? ac.nickname : acct );
private void setAcct( @NonNull TextView tv, @NonNull String acctLong,@NonNull String acctShort ){
AcctColor ac = AcctColor.load( acctLong );
tv.setText( AcctColor.hasNickname( ac ) ? ac.nickname : activity.mShortAcctLocalUser ? "@"+acctShort : acctLong );
tv.setTextColor( AcctColor.hasColorForeground( ac ) ? ac.color_fg : this.acct_color );
if( AcctColor.hasColorBackground( ac ) ){

View File

@ -84,6 +84,9 @@ public class Pref {
public static final String KEY_AUTO_CW_LINES = "auto_cw_lines";
public static final String KEY_SHORT_ACCT_LOCAL_USER = "short_acct_local_user";
public static final String KEY_AVATAR_ICON_SIZE = "avatar_icon_size";
// 項目を追加したらAppDataExporter#importPref のswitch文も更新すること
}

View File

@ -1,13 +1,13 @@
package jp.juggler.subwaytooter.api.entity;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.json.JSONObject;
import org.json.JSONObject;
import jp.juggler.subwaytooter.util.LogCategory;
import jp.juggler.subwaytooter.util.Utils;
import jp.juggler.subwaytooter.util.VersionString;
import jp.juggler.subwaytooter.util.LogCategory;
import jp.juggler.subwaytooter.util.Utils;
import jp.juggler.subwaytooter.util.VersionString;
@SuppressWarnings("WeakerAccess")
public class TootInstance {
@ -27,8 +27,12 @@ public class TootInstance {
public String version;
// バージョンの内部表現
public VersionString decoded_version;
// いつ取得したか
public long time_parse;
@Nullable
public static TootInstance parse( JSONObject src ){
if( src == null ) return null;
@ -40,6 +44,7 @@ public class TootInstance {
dst.email = Utils.optStringX( src, "email" );
dst.version = Utils.optStringX( src, "version" );
dst.decoded_version = new VersionString( dst.version );
dst.time_parse = System.currentTimeMillis();
return dst;
}catch( Throwable ex ){
log.trace( ex );
@ -48,11 +53,9 @@ public class TootInstance {
}
}
public boolean isEnoughVersion( @NonNull VersionString check ){
if( decoded_version.isEmpty() || check.isEmpty() ) return false;
int i = VersionString.compare( decoded_version ,check );
int i = VersionString.compare( decoded_version, check );
return i >= 0;
}
}

View File

@ -87,6 +87,14 @@ public class TootStatus extends TootStatusLike {
@Nullable
public static TootStatus parse( @NonNull Context context, @NonNull SavedAccount access_info, JSONObject src ){
return parse( context,access_info,src,false);
}
@Nullable
public static TootStatus parse( @NonNull Context context, @NonNull SavedAccount access_info, JSONObject src ,boolean bPinned){
/*
bPinned 引数がtrueになるのはプロフィールカラムからpinned TL を読んだ時だけである
*/
if( src == null ) return null;
// log.d( "parse: %s", src.toString() );
@ -111,7 +119,8 @@ public class TootStatus extends TootStatusLike {
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.reblog = TootStatus.parse( context, access_info, src.optJSONObject( "reblog" ) );
status.reblog = TootStatus.parse( context, access_info, src.optJSONObject( "reblog" ) ,false );
/* Pinned TL を取得した時にreblogが登場することはないので、reblogをパースするときのbPinnedはfalseでよい */
status.content = Utils.optStringX( src, "content" );
status.created_at = Utils.optStringX( src, "created_at" ); // "2017-04-16T09:37:14.000Z"
status.reblogs_count = src.optLong( "reblogs_count" );
@ -125,7 +134,7 @@ public class TootStatus extends TootStatusLike {
status.tags = TootTag.parseList( src.optJSONArray( "tags" ) );
status.application = TootApplication.parse( src.optJSONObject( "application" ) ); // null
status.pinned = src.optBoolean( "pinned" );
status.pinned = bPinned || src.optBoolean( "pinned" );
status.setSpoilerText( context, Utils.optStringX( src, "spoiler_text" ) );
@ -137,7 +146,6 @@ public class TootStatus extends TootStatusLike {
// status.decoded_tags = HTMLDecoder.decodeTags( account,status.tags );
status.decoded_mentions = HTMLDecoder.decodeMentions( access_info, status.mentions );
status.enquete = NicoEnquete.parse( context,access_info , status.media_attachments , Utils.optStringX( src, "enquete"),status.id,status.time_created_at );
return status;
@ -150,6 +158,11 @@ public class TootStatus extends TootStatusLike {
@NonNull
public static List parseList( @NonNull Context context, @NonNull SavedAccount access_info, JSONArray array ){
return parseList( context,access_info,array,false );
}
@NonNull
public static List parseList( @NonNull Context context, @NonNull SavedAccount access_info, JSONArray array ,boolean bPinned){
List result = new List();
if( array != null ){
int array_size = array.length();
@ -157,7 +170,7 @@ public class TootStatus extends TootStatusLike {
for( int i = 0 ; i < array_size ; ++ i ){
JSONObject src = array.optJSONObject( i );
if( src == null ) continue;
TootStatus item = parse( context, access_info, src );
TootStatus item = parse( context, access_info, src ,bPinned );
if( item != null ) result.add( item );
}
}

View File

@ -84,8 +84,20 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
public long register_time;
private final AtomicReference<TootInstance> refInstance = new AtomicReference<>( null );
private static final long INSTANCE_INFORMATION_EXPIRE = 60000L * 5;
// DBには保存しない
public final AtomicReference<TootInstance> refInstance = new AtomicReference<>( null );
public @Nullable TootInstance getInstance(){
TootInstance instance = refInstance.get();
if( instance != null && System.currentTimeMillis() - instance.time_parse > INSTANCE_INFORMATION_EXPIRE ){
return null;
}
return instance;
}
public void setInstance(@NonNull TootInstance instance){
if( instance != null ) refInstance.set(instance);
}
// アプリデータのインポート時に呼ばれる

View File

@ -2,6 +2,7 @@ package jp.juggler.subwaytooter.util;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import java.math.BigInteger;
import java.util.ArrayList;
@ -9,17 +10,25 @@ import java.util.ArrayList;
public class VersionString {
// static final LogCategory log = new LogCategory( "VersionString" );
private final String src;
@NonNull private final String src;
private final ArrayList<Object> node_list = new ArrayList<>( );
@Override public String toString(){
return src;
}
private final ArrayList< Object > node_list = new ArrayList<>();
public boolean isEmpty(){
return node_list.isEmpty();
}
private static boolean isDelimiter( char c ){
return c == '.' || c == ' ';
}
public VersionString( @Nullable String src ){
this.src = src;
if( src == null ) return;
this.src = src == null ? "" : src;
if( TextUtils.isEmpty( src ) ) return;
int end = src.length();
int next = 0;
while( next < end ){
@ -49,14 +58,10 @@ public class VersionString {
}
}
public boolean isEmpty(){
return node_list.isEmpty();
}
// return -1 if a<b , return 1 if a>b , return 0 if a==b
public static int compare( @NonNull VersionString a, @NonNull VersionString b ){
for( int idx =0 ;; ++idx){
for( int idx = 0 ; ; ++ idx ){
Object ao = ( idx >= a.node_list.size() ? null : a.node_list.get( idx ) );
Object bo = ( idx >= b.node_list.size() ? null : b.node_list.get( idx ) );
if( ao == null ){

View File

@ -591,6 +591,23 @@
<View style="@style/setting_divider"/>
<TextView
style="@style/setting_row_label"
android:text="@string/short_acct_local_user"
/>
<LinearLayout style="@style/setting_row_form">
<Switch
android:id="@+id/swShortAcctLocalUser"
style="@style/setting_horizontal_stretch"
android:gravity="center"
/>
</LinearLayout>
<View style="@style/setting_divider"/>
<TextView
style="@style/setting_row_label"
android:text="@string/relative_timestamp"
@ -1016,6 +1033,25 @@
<View style="@style/setting_divider"/>
<TextView
style="@style/setting_row_label"
android:labelFor="@+id/etAvatarIconSize"
android:text="@string/avatar_icon_size"
/>
<LinearLayout style="@style/setting_row_form">
<EditText
android:id="@+id/etAvatarIconSize"
style="@style/setting_horizontal_stretch"
android:gravity="center"
android:inputType="numberDecimal"
/>
</LinearLayout>
<View style="@style/setting_divider"/>
<!-- =============================================== -->
<TextView
style="@style/setting_group_header"

View File

@ -465,6 +465,9 @@
<string name="profile_pin">Pin on profile</string>
<string name="profile_unpin">Unpin from profile</string>
<string name="profile_pin_progress">Changing pinned status…</string>
<string name="length_warning">\"%1$s\" is too long (%2$d/%3$d characters).\nIt is not acceptable in the standard instance, but it may be acceptable in some instances.\nAre you sure?</string>
<string name="avatar_icon_size">Avatar icon size (unit:dp. default:48. app restart required)</string>
<string name="short_acct_local_user">Short acct for local user (app restart required)</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>-->

View File

@ -752,4 +752,8 @@
<string name="profile_pin">プロフィールに固定表示</string>
<string name="profile_unpin">プロフィールの固定表示を解除</string>
<string name="profile_pin_progress">固定表示の変更中…</string>
<string name="length_warning">\"%1$s\"が長すぎます(%2$d/%3$d文字).\n標準的なインスタンスではエラーとなりますが、いくつかのインスタンスでは許容されるかも。\nよろしいですか?</string>
<string name="avatar_icon_size">アバターアイコンサイズ(単位:dp. デフォルト:48. アプリ再起動が必要)</string>
<string name="short_acct_local_user">ローカルユーザのAcct表記を短くする(アプリ再起動が必要)</string>
</resources>

View File

@ -459,5 +459,8 @@
<string name="profile_pin">Pin on profile</string>
<string name="profile_unpin">Unpin from profile</string>
<string name="profile_pin_progress">Changing pinned status…</string>
<string name="length_warning">\"%1$s\" is too long (%2$d/%3$d characters).\nIt is not acceptable in the standard instance, but it may be acceptable in some instances.\nAre you sure?</string>
<string name="avatar_icon_size">Avatar icon size (unit:dp. default:48. app restart required)</string>
<string name="short_acct_local_user">Short acct for local user (app restart required)</string>
</resources>