リファクタ

This commit is contained in:
tateisu 2017-05-05 07:32:53 +09:00
parent 92e3c502fa
commit bf2d902bf5
15 changed files with 1140 additions and 1192 deletions

View File

@ -11,6 +11,7 @@
<w>idempotency</w>
<w>noto</w>
<w>nsfw</w>
<w>proc</w>
<w>reblog</w>
<w>reblogged</w>
<w>reblogs</w>

View File

@ -9,8 +9,8 @@ android {
applicationId "jp.juggler.subwaytooter"
minSdkVersion 21
targetSdkVersion 25
versionCode 34
versionName "0.3.4"
versionCode 35
versionName "0.3.5"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

View File

@ -140,7 +140,7 @@ public class ActMain extends AppCompatActivity
}
}
ColumnViewHolder.ListItemPopup list_item_popup;
StatusButtonsPopup list_item_popup;
void closeListItemPopup(){
if( list_item_popup != null ){
@ -2069,6 +2069,7 @@ public class ActMain extends AppCompatActivity
}
};
private void openOSSLicense(){
startActivity( new Intent( this, ActOSSLicense.class ) );
}
@ -2129,7 +2130,7 @@ public class ActMain extends AppCompatActivity
}else if( result.object != null ){
// ok. empty object will be returned.
for( Column column : pager_adapter.column_list ){
if( column.type == Column.TYPE_NOTIFICATIONS
if( column.column_type == Column.TYPE_NOTIFICATIONS
&& column.access_info.acct.equals( target_account.acct )
){
column.removeNotifications();

View File

@ -7,13 +7,13 @@ import android.support.annotation.NonNull;
import android.support.v4.os.AsyncTaskCompat;
import android.text.TextUtils;
import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
@ -37,11 +37,13 @@ import jp.juggler.subwaytooter.table.MutedApp;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
import jp.juggler.subwaytooter.util.LogCategory;
import jp.juggler.subwaytooter.util.MyListView;
import jp.juggler.subwaytooter.util.ScrollPosition;
import jp.juggler.subwaytooter.util.Utils;
class Column {
private static final LogCategory log = new LogCategory( "Column" );
public static final java.lang.String KEY_COLUMN_COLOR = "color";
private static Object getParamAt( Object[] params, int idx ){
if( params == null || idx >= params.length ){
@ -90,6 +92,8 @@ class Column {
private static final String KEY_DONT_SHOW_REPLY = "dont_show_reply";
private static final String KEY_REGEX_TEXT = "regex_text";
// static final java.lang.String KEY_COLUMN_COLOR = "color";
private static final String KEY_PROFILE_ID = "profile_id";
private static final String KEY_PROFILE_TAB = "tab";
private static final String KEY_STATUS_ID = "status_id";
@ -117,10 +121,10 @@ class Column {
static final int TYPE_BLOCKS = 12;
static final int TYPE_FOLLOW_REQUESTS = 13;
@NonNull private final ActMain activity;
@NonNull final ActMain activity;
@NonNull final SavedAccount access_info;
final int type;
final int column_type;
boolean dont_close;
@ -143,13 +147,12 @@ class Column {
String search_query;
boolean search_resolve;
int scroll_pos;
int scroll_y;
ScrollPosition scroll_pos;
Column( @NonNull ActMain activity, @NonNull SavedAccount access_info, int type, Object... params ){
this.activity = activity;
this.access_info = access_info;
this.type = type;
this.column_type = type;
switch( type ){
case TYPE_CONVERSATION:
@ -170,20 +173,19 @@ class Column {
break;
}
startLoading();
init();
}
void encodeJSON( JSONObject item, int old_index ) throws JSONException{
item.put( KEY_ACCOUNT_ROW_ID, access_info.db_id );
item.put( KEY_TYPE, type );
item.put( KEY_TYPE, column_type );
item.put( KEY_DONT_CLOSE, dont_close );
item.put( KEY_WITH_ATTACHMENT, with_attachment );
item.put( KEY_DONT_SHOW_BOOST, dont_show_boost );
item.put( KEY_DONT_SHOW_REPLY, dont_show_reply );
item.put( KEY_REGEX_TEXT, regex_text );
switch( type ){
switch( column_type ){
case TYPE_CONVERSATION:
item.put( KEY_STATUS_ID, status_id );
break;
@ -215,14 +217,14 @@ class Column {
SavedAccount ac = SavedAccount.loadAccount( log, src.optLong( KEY_ACCOUNT_ROW_ID ) );
if( ac == null ) throw new RuntimeException( "missing account" );
this.access_info = ac;
this.type = src.optInt( KEY_TYPE );
this.column_type = src.optInt( KEY_TYPE );
this.dont_close = src.optBoolean( KEY_DONT_CLOSE );
this.with_attachment = src.optBoolean( KEY_WITH_ATTACHMENT );
this.dont_show_boost = src.optBoolean( KEY_DONT_SHOW_BOOST );
this.dont_show_reply = src.optBoolean( KEY_DONT_SHOW_REPLY );
this.regex_text = Utils.optStringX( src, KEY_REGEX_TEXT );
switch( type ){
switch( column_type ){
case TYPE_CONVERSATION:
this.status_id = src.optLong( KEY_STATUS_ID );
@ -243,11 +245,11 @@ class Column {
break;
}
startLoading();
init();
}
boolean isSameSpec( SavedAccount ai, int type, Object[] params ){
if( type != this.type || ! Utils.equalsNullable( ai.acct, access_info.acct ) ) return false;
if( type != column_type || ! Utils.equalsNullable( ai.acct, access_info.acct ) ) return false;
switch( type ){
default:
return true;
@ -296,7 +298,7 @@ class Column {
}
String getColumnName( boolean bLong ){
switch( type ){
switch( column_type ){
default:
return "?";
@ -394,12 +396,25 @@ class Column {
}
}
boolean bSimpleList;
ItemListAdapter status_adapter;
int acct_pad_lr;
private void init(){
acct_pad_lr = (int) ( 0.5f + 4f * activity.density );
bSimpleList = ( column_type != Column.TYPE_CONVERSATION && activity.pref.getBoolean( Pref.KEY_SIMPLE_LIST, false ) );
status_adapter = new ItemListAdapter(this);
startLoading();
}
void onNicknameUpdated(){
fireVisualCallback2();
}
interface StatusEntryCallback {
void onIterate( TootStatus status );
}
@ -469,7 +484,7 @@ class Column {
// ミュート解除が成功した時に呼ばれる
void removeFromMuteList( SavedAccount target_account, long who_id ){
if( ! target_account.acct.equals( access_info.acct ) ) return;
if( type != TYPE_MUTES ) return;
if( column_type != TYPE_MUTES ) return;
ArrayList< Object > tmp_list = new ArrayList<>( list_data.size() );
for( Object o : list_data ){
@ -490,7 +505,7 @@ class Column {
// ブロック解除が成功したのでブロックリストから削除する
void removeFromBlockList( SavedAccount target_account, long who_id ){
if( ! target_account.acct.equals( access_info.acct ) ) return;
if( type != TYPE_BLOCKS ) return;
if( column_type != TYPE_BLOCKS ) return;
ArrayList< Object > tmp_list = new ArrayList<>( list_data.size() );
for( Object o : list_data ){
@ -507,10 +522,10 @@ class Column {
}
}
public void removeFollowRequest( SavedAccount target_account, long who_id ){
void removeFollowRequest( SavedAccount target_account, long who_id ){
if( ! target_account.acct.equals( access_info.acct ) ) return;
if( type == TYPE_FOLLOW_REQUESTS ){
if( column_type == TYPE_FOLLOW_REQUESTS ){
ArrayList< Object > tmp_list = new ArrayList<>( list_data.size() );
for( Object o : list_data ){
if( o instanceof TootAccount ){
@ -563,43 +578,48 @@ class Column {
}
}
interface VisualCallback {
void removeNotifications(){
cancelLastTask();
list_data.clear();
mRefreshLoadingError = null;
bRefreshLoading = false;
mInitialLoadingError = null;
bInitialLoading = false;
max_id = null;
since_id = null;
fireVisualCallback();
AlarmService.dataRemoved( activity, access_info.db_id );
}
interface Callback {
void onVisualColumn();
void onVisualColumn2();
SwipyRefreshLayout getRefreshLayout();
MyListView getListView();
}
private final LinkedList< VisualCallback > visual_callback = new LinkedList<>();
private Callback callback ;
void addVisualListener( VisualCallback listener ){
if( listener == null ) return;
for( VisualCallback vc : visual_callback ){
if( vc == listener ) return;
}
visual_callback.add( listener );
}
void removeVisualListener( VisualCallback listener ){
if( listener == null ) return;
Iterator< VisualCallback > it = visual_callback.iterator();
while( it.hasNext() ){
VisualCallback vc = it.next();
if( vc == listener ) it.remove();
}
void setCallback( Callback callback ){
this.callback = callback;
}
private final Runnable proc_fireVisualCallback = new Runnable() {
@Override public void run(){
for( VisualCallback aVisual_callback : visual_callback ){
aVisual_callback.onVisualColumn();
}
if(callback != null) callback.onVisualColumn();
}
};
private final Runnable proc_fireVisualCallback2 = new Runnable() {
@Override public void run(){
for( VisualCallback aVisual_callback : visual_callback ){
aVisual_callback.onVisualColumn2();
}
if(callback != null) callback.onVisualColumn2();
}
};
@ -904,7 +924,7 @@ class Column {
try{
TootApiResult result;
switch( type ){
switch( column_type ){
default:
case TYPE_HOME:
@ -1434,7 +1454,7 @@ class Column {
client.setAccount( access_info );
try{
switch( type ){
switch( column_type ){
default:
case TYPE_HOME:
@ -1577,9 +1597,14 @@ class Column {
return null;
}
String startGap( final TootGap gap ){
void startGap( final TootGap gap, int position ){
if( last_task != null ){
return activity.getString( R.string.column_is_busy );
Utils.showToast( activity, true, R.string.column_is_busy );
return;
}
if( callback != null ){
callback.getRefreshLayout().setRefreshing( true );
}
bRefreshLoading = true;
@ -1808,7 +1833,7 @@ class Column {
client.setAccount( access_info );
try{
switch( type ){
switch( column_type ){
default:
case TYPE_HOME:
@ -1946,24 +1971,8 @@ class Column {
};
AsyncTaskCompat.executeParallel( task );
return null;
}
void removeNotifications(){
cancelLastTask();
list_data.clear();
mRefreshLoadingError = null;
bRefreshLoading = false;
mInitialLoadingError = null;
bInitialLoading = false;
max_id = null;
since_id = null;
fireVisualCallback();
AlarmService.dataRemoved( activity, access_info.db_id );
}
private void updateRelation( TootApiClient client, ArrayList< Object > list_tmp ){
if( list_tmp == null || list_tmp.isEmpty() ) return;
@ -2076,5 +2085,8 @@ class Column {
}
}
//////////////////////////////////////////////////////////////////////////////////
}

View File

@ -1,6 +1,5 @@
package jp.juggler.subwaytooter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.SparseArray;
@ -11,20 +10,30 @@ import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.HashSet;
public class ColumnPagerAdapter extends PagerAdapter{
class ColumnPagerAdapter extends PagerAdapter {
final ActMain activity;
final LayoutInflater inflater;
boolean loop_mode = false;
private final ActMain activity;
private final LayoutInflater inflater;
final ArrayList< Column > column_list = new ArrayList<>();
private final SparseArray< ColumnViewHolder > holder_list = new SparseArray<>();
ColumnPagerAdapter( ActMain activity ){
this.activity = activity;
this.inflater = activity.getLayoutInflater();
}
final ArrayList<Column> column_list = new ArrayList<>();
final SparseArray<ColumnViewHolder> holder_list = new SparseArray<>();
@Override public int getCount(){
return column_list.size();
}
Column getColumn( int idx ){
if( idx >= 0 && idx < column_list.size() ) return column_list.get( idx );
return null;
}
ColumnViewHolder getColumnViewHolder( int idx ){
return holder_list.get( idx );
}
int addColumn( ViewPager pager, Column column ){
return addColumn( pager, column, pager.getCurrentItem() + 1 );
@ -41,22 +50,15 @@ public class ColumnPagerAdapter extends PagerAdapter{
return index;
}
private void saveScrollPosition(){
for( int i=0,ie=holder_list.size();i<ie;++i){
holder_list.valueAt( i ).saveScrollPosition();
}
}
public void removeColumn( ViewPager pager,Column column ){
void removeColumn( ViewPager pager, Column column ){
int idx_column = column_list.indexOf( column );
if( idx_column == - 1 ) return;
int idx_showing = pager.getCurrentItem();
pager.setAdapter( null );
column_list.remove( idx_column );
pager.setAdapter( this );
}
public void setOrder( ViewPager pager,ArrayList< Integer > order ){
void setOrder( ViewPager pager, ArrayList< Integer > order ){
pager.setAdapter( null );
ArrayList< Column > tmp_list = new ArrayList<>();
@ -76,28 +78,11 @@ public class ColumnPagerAdapter extends PagerAdapter{
pager.setAdapter( this );
}
public Column getColumn( int idx ){
if( idx >= 0 && idx < column_list.size() ) return column_list.get( idx );
return null;
}
public ColumnViewHolder getColumnViewHolder( int idx ){
return holder_list.get( idx );
}
@Override public int getCount(){
return column_list.size();
}
@Override public CharSequence getPageTitle( int page_idx ){
return "page" + page_idx;
}
@Override
public boolean isViewFromObject( View view, Object object ){
@Override public boolean isViewFromObject( View view, Object object ){
return view == object;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
package jp.juggler.subwaytooter;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.android.volley.toolbox.NetworkImageView;
import jp.juggler.subwaytooter.api.entity.TootAccount;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
import jp.juggler.subwaytooter.util.Emojione;
import jp.juggler.subwaytooter.util.MyLinkMovementMethod;
class HeaderViewHolder implements View.OnClickListener {
private final Column column;
private final ActMain activity;
private final SavedAccount access_info;
final View viewRoot;
private final NetworkImageView ivBackground;
private final TextView tvCreated;
private final NetworkImageView ivAvatar;
private final TextView tvDisplayName;
private final TextView tvAcct;
private final Button btnFollowing;
private final Button btnFollowers;
private final Button btnStatusCount;
private final TextView tvNote;
private final ImageButton btnFollow;
private final ImageView ivFollowedBy;
private TootAccount who;
HeaderViewHolder( Column column, ListView parent ){
this.column = column;
this.activity = column.activity;
this.access_info = column.access_info;
this.viewRoot = activity.getLayoutInflater().inflate( R.layout.lv_list_header, parent, false );
ivBackground = (NetworkImageView) viewRoot.findViewById( R.id.ivBackground );
tvCreated = (TextView) viewRoot.findViewById( R.id.tvCreated );
ivAvatar = (NetworkImageView) viewRoot.findViewById( R.id.ivAvatar );
tvDisplayName = (TextView) viewRoot.findViewById( R.id.tvDisplayName );
tvAcct = (TextView) viewRoot.findViewById( R.id.tvAcct );
btnFollowing = (Button) viewRoot.findViewById( R.id.btnFollowing );
btnFollowers = (Button) viewRoot.findViewById( R.id.btnFollowers );
btnStatusCount = (Button) viewRoot.findViewById( R.id.btnStatusCount );
tvNote = (TextView) viewRoot.findViewById( R.id.tvNote );
View btnMore = viewRoot.findViewById( R.id.btnMore );
btnFollow = (ImageButton) viewRoot.findViewById( R.id.btnFollow );
ivFollowedBy = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy );
ivBackground.setOnClickListener( this );
btnFollowing.setOnClickListener( this );
btnFollowers.setOnClickListener( this );
btnStatusCount.setOnClickListener( this );
btnMore.setOnClickListener( this );
btnFollow.setOnClickListener( this );
tvNote.setMovementMethod( MyLinkMovementMethod.getInstance() );
}
void bind( TootAccount who ){
this.who = who;
if( who == null ){
tvCreated.setText( "" );
ivBackground.setImageDrawable( null );
ivAvatar.setImageDrawable( null );
tvDisplayName.setText( "" );
tvAcct.setText( "@" );
tvNote.setText( "" );
btnStatusCount.setText( activity.getString( R.string.statuses ) + "\n" + "?" );
btnFollowing.setText( activity.getString( R.string.following ) + "\n" + "?" );
btnFollowers.setText( activity.getString( R.string.followers ) + "\n" + "?" );
btnFollow.setImageDrawable( null );
}else{
tvCreated.setText( TootStatus.formatTime( who.time_created_at ) );
ivBackground.setImageUrl( access_info.supplyBaseUrl( who.header_static ), App1.getImageLoader() );
ivAvatar.setImageUrl( access_info.supplyBaseUrl( who.avatar_static ), App1.getImageLoader() );
tvDisplayName.setText( who.display_name );
String s = "@" + access_info.getFullAcct( who );
if( who.locked ){
s += " " + Emojione.map_name2unicode.get( "lock" );
}
tvAcct.setText( Emojione.decodeEmoji( s ) );
tvNote.setText( who.note );
btnStatusCount.setText( activity.getString( R.string.statuses ) + "\n" + who.statuses_count );
btnFollowing.setText( activity.getString( R.string.following ) + "\n" + who.following_count );
btnFollowers.setText( activity.getString( R.string.followers ) + "\n" + who.followers_count );
UserRelation relation = UserRelation.load( access_info.db_id, who.id );
Styler.setFollowIcon( activity, btnFollow, ivFollowedBy, relation, column.column_type );
}
}
@Override
public void onClick( View v ){
switch( v.getId() ){
case R.id.ivBackground:
if( who != null ){
// 強制的にブラウザで開く
activity.openChromeTab( access_info, who.url, true );
}
break;
case R.id.btnFollowing:
column.profile_tab = Column.TAB_FOLLOWING;
column.startLoading();
break;
case R.id.btnFollowers:
column.profile_tab = Column.TAB_FOLLOWERS;
column.startLoading();
break;
case R.id.btnStatusCount:
column.profile_tab = Column.TAB_STATUS;
column.startLoading();
break;
case R.id.btnMore:
if( who != null ){
new DlgContextMenu( activity, access_info, who, null, column.column_type ).show();
}
break;
case R.id.btnFollow:
if( who != null ){
new DlgContextMenu( activity, access_info, who, null, column.column_type ).show();
}
break;
}
}
}

View File

@ -0,0 +1,63 @@
package jp.juggler.subwaytooter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import java.util.ArrayList;
import jp.juggler.subwaytooter.util.MyListView;
class ItemListAdapter extends BaseAdapter implements AdapterView.OnItemClickListener {
private final Column column;
private final ActMain activity;
private final ArrayList< Object > list;
ItemListAdapter( Column column ){
this.column = column;
this.activity = column.activity;
this.list = column.list_data;
}
@Override
public int getCount(){
return column.list_data.size();
}
@Override
public Object getItem( int position ){
if( position >= 0 && position < column.list_data.size() ) return list.get( position );
return null;
}
@Override
public long getItemId( int position ){
return 0;
}
@Override
public View getView( int position, View view, ViewGroup parent ){
Object o = ( position >= 0 && position < list.size() ? list.get( position ) : null );
ItemViewHolder holder;
if( view == null ){
view = activity.getLayoutInflater().inflate( column.bSimpleList ? R.layout.lv_status_simple : R.layout.lv_status, parent, false );
holder = new ItemViewHolder( column, view );
view.setTag( holder );
}else{
holder = (ItemViewHolder) view.getTag();
}
holder.bind( o ,position);
return view;
}
@Override
public void onItemClick( AdapterView< ? > parent, View view, int position, long id ){
Object tag = view.getTag();
if( tag instanceof ItemViewHolder ){
( (ItemViewHolder) tag ).onItemClick( (MyListView) parent, view );
}
}
}

View File

@ -0,0 +1,471 @@
package jp.juggler.subwaytooter;
import android.support.v4.view.ViewCompat;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.volley.toolbox.NetworkImageView;
import jp.juggler.subwaytooter.api.entity.TootAccount;
import jp.juggler.subwaytooter.api.entity.TootAttachment;
import jp.juggler.subwaytooter.api.entity.TootGap;
import jp.juggler.subwaytooter.api.entity.TootNotification;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.table.AcctColor;
import jp.juggler.subwaytooter.table.ContentWarning;
import jp.juggler.subwaytooter.table.MediaShown;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
import jp.juggler.subwaytooter.util.MyLinkMovementMethod;
import jp.juggler.subwaytooter.util.MyListView;
import jp.juggler.subwaytooter.util.MyTextView;
import jp.juggler.subwaytooter.util.Utils;
class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
final ActMain activity;
final Column column;
private final SavedAccount access_info;
private final View llBoosted;
private final ImageView ivBoosted;
private final TextView tvBoosted;
private final TextView tvBoostedAcct;
private final TextView tvBoostedTime;
private final View llFollow;
private final NetworkImageView ivFollow;
private final TextView tvFollowerName;
private final TextView tvFollowerAcct;
private final ImageButton btnFollow;
private final ImageView ivFollowedBy;
private final View llStatus;
private final NetworkImageView ivThumbnail;
private final TextView tvName;
private final TextView tvTime;
private final TextView tvAcct;
private final View llContentWarning;
private final MyTextView tvContentWarning;
private final Button btnContentWarning;
private final View llContents;
private final MyTextView tvMentions;
private final MyTextView tvContent;
private final View flMedia;
private final View btnShowMedia;
private final NetworkImageView ivMedia1;
private final NetworkImageView ivMedia2;
private final NetworkImageView ivMedia3;
private final NetworkImageView ivMedia4;
private final StatusButtons buttons_for_status;
private final View llSearchTag;
private final Button btnSearchTag;
private final TextView tvApplication;
private TootStatus status;
private TootAccount account_thumbnail;
private TootAccount account_boost;
private TootAccount account_follow;
private String search_tag;
private TootGap gap;
private int position;
ItemViewHolder( Column column, View view ){
this.column = column;
this.activity = column.activity;
this.access_info = column.access_info;
this.llBoosted = view.findViewById( R.id.llBoosted );
this.ivBoosted = (ImageView) view.findViewById( R.id.ivBoosted );
this.tvBoosted = (TextView) view.findViewById( R.id.tvBoosted );
this.tvBoostedTime = (TextView) view.findViewById( R.id.tvBoostedTime );
this.tvBoostedAcct = (TextView) view.findViewById( R.id.tvBoostedAcct );
this.llFollow = view.findViewById( R.id.llFollow );
this.ivFollow = (NetworkImageView) view.findViewById( R.id.ivFollow );
this.tvFollowerName = (TextView) view.findViewById( R.id.tvFollowerName );
this.tvFollowerAcct = (TextView) view.findViewById( R.id.tvFollowerAcct );
this.btnFollow = (ImageButton) view.findViewById( R.id.btnFollow );
this.ivFollowedBy = (ImageView) view.findViewById( R.id.ivFollowedBy );
this.llStatus = view.findViewById( R.id.llStatus );
this.ivThumbnail = (NetworkImageView) view.findViewById( R.id.ivThumbnail );
this.tvName = (TextView) view.findViewById( R.id.tvName );
this.tvTime = (TextView) view.findViewById( R.id.tvTime );
this.tvAcct = (TextView) view.findViewById( R.id.tvAcct );
this.llContentWarning = view.findViewById( R.id.llContentWarning );
this.tvContentWarning = (MyTextView) view.findViewById( R.id.tvContentWarning );
this.btnContentWarning = (Button) view.findViewById( R.id.btnContentWarning );
this.llContents = view.findViewById( R.id.llContents );
this.tvContent = (MyTextView) view.findViewById( R.id.tvContent );
this.tvMentions = (MyTextView) view.findViewById( R.id.tvMentions );
this.buttons_for_status = column.bSimpleList ? null : new StatusButtons( column, view );
this.flMedia = view.findViewById( R.id.flMedia );
this.btnShowMedia = view.findViewById( R.id.btnShowMedia );
this.ivMedia1 = (NetworkImageView) view.findViewById( R.id.ivMedia1 );
this.ivMedia2 = (NetworkImageView) view.findViewById( R.id.ivMedia2 );
this.ivMedia3 = (NetworkImageView) view.findViewById( R.id.ivMedia3 );
this.ivMedia4 = (NetworkImageView) view.findViewById( R.id.ivMedia4 );
this.llSearchTag = view.findViewById( R.id.llSearchTag );
this.btnSearchTag = (Button) view.findViewById( R.id.btnSearchTag );
this.tvApplication = (TextView) view.findViewById( R.id.tvApplication );
btnSearchTag.setOnClickListener( this );
btnContentWarning.setOnClickListener( this );
btnShowMedia.setOnClickListener( this );
ivMedia1.setOnClickListener( this );
ivMedia2.setOnClickListener( this );
ivMedia3.setOnClickListener( this );
ivMedia4.setOnClickListener( this );
btnFollow.setOnClickListener( this );
ivThumbnail.setOnClickListener( this );
// ここを個別タップにすると邪魔すぎる tvName.setOnClickListener( this );
llBoosted.setOnClickListener( this );
llFollow.setOnClickListener( this );
btnFollow.setOnClickListener( this );
// ロングタップ
ivThumbnail.setOnLongClickListener( this );
//
tvContent.setMovementMethod( MyLinkMovementMethod.getInstance() );
tvMentions.setMovementMethod( MyLinkMovementMethod.getInstance() );
tvContentWarning.setMovementMethod( MyLinkMovementMethod.getInstance() );
View v;
//
v = view.findViewById( R.id.btnHideMedia );
v.setOnClickListener( this );
}
void bind( Object item ,int position){
this.position = position;
this.status = null;
this.account_thumbnail = null;
this.account_boost = null;
this.account_follow = null;
this.search_tag = null;
this.gap = null;
llBoosted.setVisibility( View.GONE );
llFollow.setVisibility( View.GONE );
llStatus.setVisibility( View.GONE );
llSearchTag.setVisibility( View.GONE );
if( item == null ) return;
if( item instanceof String ){
showSearchTag( (String) item );
}else if( item instanceof TootAccount ){
showFollow( (TootAccount) item );
}else if( item instanceof TootNotification ){
TootNotification n = (TootNotification) item;
if( TootNotification.TYPE_FAVOURITE.equals( n.type ) ){
showBoost(
n.account
, n.time_created_at
, R.attr.btn_favourite
, Utils.formatSpannable1( activity, R.string.display_name_favourited_by, n.account.display_name )
);
if( n.status != null ) showStatus( activity, n.status );
}else if( TootNotification.TYPE_REBLOG.equals( n.type ) ){
showBoost(
n.account
, n.time_created_at
, R.attr.btn_boost
, Utils.formatSpannable1( activity, R.string.display_name_boosted_by, n.account.display_name )
);
if( n.status != null ) showStatus( activity, n.status );
}else if( TootNotification.TYPE_FOLLOW.equals( n.type ) ){
showBoost(
n.account
, n.time_created_at
, R.attr.btn_boost
, Utils.formatSpannable1( activity, R.string.display_name_followed_by, n.account.display_name )
);
//
showFollow( n.account );
}else if( TootNotification.TYPE_MENTION.equals( n.type ) ){
if( ! column.bSimpleList ){
showBoost(
n.account
, n.time_created_at
, R.attr.btn_reply
, Utils.formatSpannable1( activity, R.string.display_name_replied_by, n.account.display_name )
);
}
if( n.status != null ) showStatus( activity, n.status );
}
}else if( item instanceof TootStatus ){
TootStatus status = (TootStatus) item;
if( status.reblog != null ){
showBoost(
status.account
, status.time_created_at
, R.attr.btn_boost
, Utils.formatSpannable1( activity, R.string.display_name_boosted_by, status.account.display_name )
);
showStatus( activity, status.reblog );
}else{
showStatus( activity, status );
}
}else if( item instanceof TootGap ){
showGap( (TootGap) item );
}
}
private void showSearchTag( String tag ){
this.gap = null;
search_tag = tag;
llSearchTag.setVisibility( View.VISIBLE );
btnSearchTag.setText( "#" + tag );
}
private void showGap( TootGap gap ){
this.gap = gap;
search_tag = null;
llSearchTag.setVisibility( View.VISIBLE );
btnSearchTag.setText( activity.getString( R.string.read_gap ) );
}
private void showBoost( TootAccount who, long time, int icon_attr_id, CharSequence text ){
account_boost = who;
llBoosted.setVisibility( View.VISIBLE );
ivBoosted.setImageResource( Styler.getAttributeResourceId( activity, icon_attr_id ) );
tvBoostedTime.setText( TootStatus.formatTime( time ) );
tvBoosted.setText( text );
setAcct( tvBoostedAcct, access_info.getFullAcct( who ), R.attr.colorAcctSmall );
}
private void showFollow( TootAccount who ){
account_follow = who;
llFollow.setVisibility( View.VISIBLE );
ivFollow.setImageUrl( access_info.supplyBaseUrl( who.avatar_static ), App1.getImageLoader() );
tvFollowerName.setText( who.display_name );
setAcct( tvFollowerAcct, access_info.getFullAcct( who ), R.attr.colorAcctSmall );
UserRelation relation = UserRelation.load( access_info.db_id, who.id );
Styler.setFollowIcon( activity, btnFollow, ivFollowedBy, relation, column.column_type );
}
private void showStatus( ActMain activity, TootStatus status ){
this.status = status;
account_thumbnail = status.account;
llStatus.setVisibility( View.VISIBLE );
setAcct( tvAcct, access_info.getFullAcct( status.account ), R.attr.colorAcctSmall );
tvTime.setText( TootStatus.formatTime( status.time_created_at ) );
tvName.setText( status.account.display_name );
ivThumbnail.setImageUrl( access_info.supplyBaseUrl( status.account.avatar_static ), App1.getImageLoader() );
tvContent.setText( status.decoded_content );
// if( status.decoded_tags == null ){
// tvTags.setVisibility( View.GONE );
// }else{
// tvTags.setVisibility( View.VISIBLE );
// tvTags.setText( status.decoded_tags );
// }
if( status.decoded_mentions == null ){
tvMentions.setVisibility( View.GONE );
}else{
tvMentions.setVisibility( View.VISIBLE );
tvMentions.setText( status.decoded_mentions );
}
// Content warning
if( TextUtils.isEmpty( status.spoiler_text ) ){
llContentWarning.setVisibility( View.GONE );
llContents.setVisibility( View.VISIBLE );
}else{
llContentWarning.setVisibility( View.VISIBLE );
tvContentWarning.setText( status.decoded_spoiler_text );
boolean cw_shown = ContentWarning.isShown( access_info.host, status.id, false );
showContent( cw_shown );
}
if( status.media_attachments == null || status.media_attachments.isEmpty() ){
flMedia.setVisibility( View.GONE );
}else{
flMedia.setVisibility( View.VISIBLE );
setMedia( ivMedia1, status, 0 );
setMedia( ivMedia2, status, 1 );
setMedia( ivMedia3, status, 2 );
setMedia( ivMedia4, status, 3 );
// hide sensitive media
boolean is_shown = MediaShown.isShown( access_info.host, status.id, access_info.dont_hide_nsfw || ! status.sensitive );
btnShowMedia.setVisibility( ! is_shown ? View.VISIBLE : View.GONE );
}
if( buttons_for_status != null ){
buttons_for_status.bind( status );
}
if( tvApplication != null ){
switch( column.column_type ){
default:
tvApplication.setVisibility( View.GONE );
break;
case Column.TYPE_CONVERSATION:
if( status.application == null ){
tvApplication.setVisibility( View.GONE );
}else{
tvApplication.setVisibility( View.VISIBLE );
tvApplication.setText( activity.getString( R.string.application_is, status.application.name ) );
}
break;
}
}
}
private void setAcct( TextView tv, String acct, int color_attr_id ){
AcctColor ac = AcctColor.load( acct );
tv.setText( AcctColor.hasNickname( ac ) ? ac.nickname : acct );
tv.setTextColor( AcctColor.hasColorForeground( ac ) ? ac.color_fg : Styler.getAttributeColor( activity, color_attr_id ) );
if( AcctColor.hasColorBackground( ac ) ){
tv.setBackgroundColor( ac.color_bg );
}else{
ViewCompat.setBackground( tv, null );
}
tv.setPaddingRelative( column.acct_pad_lr, 0, column.acct_pad_lr, 0 );
}
private void showContent( boolean shown ){
btnContentWarning.setText( shown ? R.string.hide : R.string.show );
llContents.setVisibility( shown ? View.VISIBLE : View.GONE );
}
private void setMedia( NetworkImageView iv, TootStatus status, int idx ){
if( idx >= status.media_attachments.size() ){
iv.setVisibility( View.GONE );
}else{
iv.setVisibility( View.VISIBLE );
TootAttachment ta = status.media_attachments.get( idx );
String url = ta.preview_url;
if( TextUtils.isEmpty( url ) ) url = ta.remote_url;
iv.setImageUrl( access_info.supplyBaseUrl( url ), App1.getImageLoader() );
}
}
@Override public void onClick( View v ){
switch( v.getId() ){
case R.id.btnHideMedia:
MediaShown.save( access_info.host, status.id, false );
btnShowMedia.setVisibility( View.VISIBLE );
break;
case R.id.btnShowMedia:
MediaShown.save( access_info.host, status.id, true );
btnShowMedia.setVisibility( View.GONE );
break;
case R.id.ivMedia1:
clickMedia( 0 );
break;
case R.id.ivMedia2:
clickMedia( 1 );
break;
case R.id.ivMedia3:
clickMedia( 2 );
break;
case R.id.ivMedia4:
clickMedia( 3 );
break;
case R.id.btnContentWarning:{
boolean new_shown = ( llContents.getVisibility() == View.GONE );
ContentWarning.save( access_info.host, status.id, new_shown );
column.status_adapter.notifyDataSetChanged();
break;
}
case R.id.ivThumbnail:
activity.performOpenUser( access_info, account_thumbnail );
break;
case R.id.llBoosted:
activity.performOpenUser( access_info, account_boost );
break;
case R.id.llFollow:
activity.performOpenUser( access_info, account_follow );
break;
case R.id.btnFollow:
new DlgContextMenu( activity, access_info, account_follow, null, column.column_type ).show();
break;
case R.id.btnSearchTag:
if( search_tag != null ){
activity.openHashTag( access_info, search_tag );
}else if( gap != null ){
column.startGap( gap, position );
}
break;
}
}
@Override public boolean onLongClick( View v ){
switch( v.getId() ){
case R.id.ivThumbnail:
new DlgContextMenu( activity, access_info, account_thumbnail, null, column.column_type ).show();
break;
}
return false;
}
private void clickMedia( int i ){
try{
TootAttachment a = status.media_attachments.get( i );
String sv;
if( Pref.pref( activity ).getBoolean( Pref.KEY_PRIOR_LOCAL_URL, false ) ){
sv = a.url;
if( TextUtils.isEmpty( sv ) ){
sv = a.remote_url;
}
}else{
sv = a.remote_url;
if( TextUtils.isEmpty( sv ) ){
sv = a.url;
}
}
activity.openChromeTab( access_info, sv, false );
}catch( Throwable ex ){
ex.printStackTrace();
}
}
// 簡略ビューの時だけ呼ばれる
// StatusButtonsPopupを表示する
void onItemClick( MyListView listView, View anchor ){
if( status != null ){
activity.closeListItemPopup();
activity.list_item_popup = new StatusButtonsPopup( column );
activity.list_item_popup.show( listView, anchor, status );
}
}
}

View File

@ -1,123 +0,0 @@
package jp.juggler.subwaytooter;
import android.app.Activity;
import android.support.v4.view.PagerAdapter;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
public class PagerAdapterBase extends PagerAdapter{
public static abstract class PageViewHolder{
public final AtomicBoolean is_destroyed = new AtomicBoolean( false );
public final Activity activity;
@SuppressWarnings( "UnusedParameters" )
public PageViewHolder( Activity activity, View ignored ){
this.activity = activity;
}
public boolean isPageDestroyed(){
return is_destroyed.get() || activity.isFinishing();
}
@SuppressWarnings( "RedundantThrows" )
protected abstract void onPageCreate( @SuppressWarnings( "UnusedParameters" ) int page_idx, View root ) throws Throwable;
@SuppressWarnings( "RedundantThrows" )
protected abstract void onPageDestroy( @SuppressWarnings( "UnusedParameters" ) int page_idx, @SuppressWarnings( "UnusedParameters" ) View root ) throws Throwable;
}
public final Activity activity;
public final LayoutInflater inflater;
public PagerAdapterBase( Activity activity ){
this.activity = activity;
this.inflater = activity.getLayoutInflater();
}
protected final ArrayList<CharSequence> title_list = new ArrayList<>();
protected final ArrayList<Integer> layout_id_list = new ArrayList<>();
protected final ArrayList<Class<? extends PageViewHolder>> holder_class_list = new ArrayList<>();
protected final SparseArray<PageViewHolder> holder_list = new SparseArray<>();
public int addPage( CharSequence title, int layout_id, Class<? extends PageViewHolder> holder_class ){
int idx = title_list.size();
title_list.add( title );
layout_id_list.add( layout_id );
holder_class_list.add( holder_class );
// ページのインデックスを返す
return idx;
}
// ページが存在する場合そのViewHolderを返す
// ページのViewが生成されていない場合はnullを返す
public <T> T getPage( int idx ){
PageViewHolder vh = holder_list.get( idx );
if( vh == null ) return null;
return (T) holder_class_list.get( idx ).cast( vh );
}
public boolean loop_mode = false;
public int getCountReal(){
return title_list.size();
}
@Override public int getCount(){
return loop_mode ? Integer.MAX_VALUE : title_list.size();
}
@Override public CharSequence getPageTitle( int page_idx ){
return title_list.get( page_idx % getCountReal() );
}
@Override
public boolean isViewFromObject( View view, Object object ){
return view == object;
}
@Override public Object instantiateItem( ViewGroup container, int page_idx ){
View root = inflater.inflate( layout_id_list.get( page_idx % getCountReal() ), container, false );
container.addView( root, 0 );
try{
PageViewHolder holder =
holder_class_list.get( page_idx % getCountReal() )
.getConstructor( Activity.class, View.class )
.newInstance( activity, root );
//
holder_list.put( page_idx, holder );
//
holder.onPageCreate( page_idx % getCountReal(), root );
//
}catch( Throwable ex ){
ex.printStackTrace();
}
return root;
}
@Override public void destroyItem( ViewGroup container, int page_idx, Object object ){
View view = (View) object;
//
container.removeView( view );
//
try{
PageViewHolder holder = holder_list.get( page_idx );
holder_list.remove( page_idx );
if( holder != null ){
holder.is_destroyed.set( true );
holder.onPageDestroy( page_idx % getCountReal(), view );
}
}catch( Throwable ex ){
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,148 @@
package jp.juggler.subwaytooter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.PopupWindow;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
import jp.juggler.subwaytooter.util.Utils;
class StatusButtons implements View.OnClickListener {
private final Column column;
private final ActMain activity;
private final SavedAccount access_info;
private final Button btnBoost;
private final Button btnFavourite;
private final ImageButton btnFollow2;
private final ImageView ivFollowedBy2;
private final View llFollow2;
StatusButtons( Column column, View viewRoot ){
this.column = column;
this.activity = column.activity;
this.access_info = column.access_info;
btnBoost = (Button) viewRoot.findViewById( R.id.btnBoost );
btnFavourite = (Button) viewRoot.findViewById( R.id.btnFavourite );
btnFollow2 = (ImageButton) viewRoot.findViewById( R.id.btnFollow2 );
ivFollowedBy2 = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy2 );
llFollow2 = viewRoot.findViewById( R.id.llFollow2 );
btnBoost.setOnClickListener( this );
btnFavourite.setOnClickListener( this );
btnFollow2.setOnClickListener( this );
View v;
//
v = viewRoot.findViewById( R.id.btnMore );
v.setOnClickListener( this );
//
v = viewRoot.findViewById( R.id.btnConversation );
v.setOnClickListener( this );
//
v = viewRoot.findViewById( R.id.btnReply );
v.setOnClickListener( this );
}
private TootStatus status;
private UserRelation relation;
void bind( TootStatus status ){
this.status = status;
int color_normal = Styler.getAttributeColor( activity, R.attr.colorImageButton );
int color_accent = Styler.getAttributeColor( activity, R.attr.colorImageButtonAccent );
if( TootStatus.VISIBILITY_DIRECT.equals( status.visibility ) ){
setButton( btnBoost, false, color_accent, R.attr.ic_mail, "" );
}else if( TootStatus.VISIBILITY_PRIVATE.equals( status.visibility ) ){
setButton( btnBoost, false, color_accent, R.attr.ic_lock, "" );
}else if( activity.isBusyBoost( access_info, status ) ){
setButton( btnBoost, false, color_normal, R.attr.btn_refresh, "?" );
}else{
int color = ( status.reblogged ? color_accent : color_normal );
setButton( btnBoost, true, color, R.attr.btn_boost, Long.toString( status.reblogs_count ) );
}
if( activity.isBusyFav( access_info, status ) ){
setButton( btnFavourite, false, color_normal, R.attr.btn_refresh, "?" );
}else{
int color = ( status.favourited ? color_accent : color_normal );
setButton( btnFavourite, true, color, R.attr.btn_favourite, Long.toString( status.favourites_count ) );
}
if( ! activity.pref.getBoolean( Pref.KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR, false ) ){
llFollow2.setVisibility( View.GONE );
this.relation = null;
}else{
llFollow2.setVisibility( View.VISIBLE );
this.relation = UserRelation.load( access_info.db_id, status.account.id );
Styler.setFollowIcon( activity, btnFollow2, ivFollowedBy2, relation, column.column_type );
}
}
private void setButton( Button b, boolean enabled, int color, int icon_attr, String text ){
Drawable d = Styler.getAttributeDrawable( activity, icon_attr ).mutate();
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
b.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
b.setText( text );
b.setTextColor( color );
b.setEnabled( enabled );
}
PopupWindow close_window;
@Override public void onClick( View v ){
if( close_window != null ) close_window.dismiss();
switch( v.getId() ){
case R.id.btnConversation:
activity.performConversation( access_info, status );
break;
case R.id.btnReply:
if( access_info.isPseudo() ){
Utils.showToast( activity, false, R.string.not_available_for_pseudo_account );
}else{
activity.performReply( access_info, status );
}
break;
case R.id.btnBoost:
if( access_info.isPseudo() ){
Utils.showToast( activity, false, R.string.not_available_for_pseudo_account );
}else{
activity.performBoost( access_info, status, false, column.bSimpleList ? activity.boost_complete_callback : null );
}
break;
case R.id.btnFavourite:
if( access_info.isPseudo() ){
Utils.showToast( activity, false, R.string.not_available_for_pseudo_account );
}else{
activity.performFavourite( access_info, status, column.bSimpleList ? activity.favourite_complete_callback : null );
}
break;
case R.id.btnMore:
new DlgContextMenu( activity, access_info, status.account, status, column.column_type ).show();
break;
case R.id.btnFollow2:
//noinspection StatementWithEmptyBody
if( relation.blocking || relation.muting ){
// 何もしない
}else if( relation.following || relation.requested ){
activity.callFollow( access_info, status.account, false, false, activity.unfollow_complete_callback );
}else{
activity.callFollow( access_info, status.account, true, false, activity.follow_complete_callback );
}
break;
}
}
}

View File

@ -0,0 +1,95 @@
package jp.juggler.subwaytooter;
import android.annotation.SuppressLint;
import android.graphics.drawable.ColorDrawable;
import android.os.SystemClock;
import android.support.v4.view.MotionEventCompat;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.util.MyListView;
class StatusButtonsPopup {
private final Column column;
private final View viewRoot;
private final StatusButtons buttons_for_status;
@SuppressLint("InflateParams") StatusButtonsPopup( Column column ){
this.column = column;
this.viewRoot = column.activity.getLayoutInflater().inflate( R.layout.list_item_popup, null, false );
this.buttons_for_status = new StatusButtons( column, viewRoot );
}
private PopupWindow window;
void dismiss(){
if( window != null && window.isShowing() ){
window.dismiss();
}
}
void show( final MyListView listView, View anchor, TootStatus status ){
//
window = new PopupWindow( column.activity );
window.setWidth( WindowManager.LayoutParams.WRAP_CONTENT );
window.setHeight( WindowManager.LayoutParams.WRAP_CONTENT );
window.setContentView( viewRoot );
window.setBackgroundDrawable( new ColorDrawable( 0x00000000 ) );
window.setTouchable( true );
window.setOutsideTouchable( true );
window.setTouchInterceptor( new View.OnTouchListener() {
@Override public boolean onTouch( View v, MotionEvent event ){
if( MotionEventCompat.getActionMasked( event ) == MotionEvent.ACTION_OUTSIDE ){
window.dismiss();
listView.last_popup_close = SystemClock.elapsedRealtime();
return true;
}
return false;
}
} );
buttons_for_status.bind( status );
buttons_for_status.close_window = window;
int[] location = new int[ 2 ];
anchor.getLocationOnScreen( location );
int anchor_top = location[ 1 ];
listView.getLocationOnScreen( location );
int listView_top = location[ 1 ];
float density = column.activity.density;
int clip_top = listView_top + (int) ( 0.5f + 8f * density );
int clip_bottom = listView_top + listView.getHeight() - (int) ( 0.5f + 8f * density );
int popup_height = (int) ( 0.5f + ( 56f + 24f ) * density );
int popup_y = anchor_top + anchor.getHeight() / 2;
if( popup_y < clip_top ){
// 画面外のは画面内にする
popup_y = clip_top;
}else if( clip_bottom - popup_y < popup_height ){
// 画面外のは画面内にする
if( popup_y > clip_bottom ) popup_y = clip_bottom;
// 画面の下側にあるならポップアップの吹き出しが下から出ているように見せる
viewRoot.findViewById( R.id.ivTriangleTop ).setVisibility( View.GONE );
viewRoot.findViewById( R.id.ivTriangleBottom ).setVisibility( View.VISIBLE );
popup_y -= popup_height;
}
window.showAtLocation(
listView
, Gravity.CENTER_HORIZONTAL | Gravity.TOP
, 0
, popup_y
);
}
}

View File

@ -89,6 +89,9 @@ public class TootAccount {
dst.id = src.optLong( "id",-1L );
dst.username = Utils.optStringX( src, "username" );
dst.acct = Utils.optStringX( src, "acct" );
if( dst.acct == null){
dst.acct = "?@?";
}
String sv = Utils.optStringX( src, "display_name" );
if( TextUtils.isEmpty( sv ) ){

View File

@ -13,6 +13,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.util.HTMLDecoder;
@ -170,14 +172,20 @@ public class TootStatus extends TootId {
return result;
}
private static final SimpleDateFormat date_format_utc = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault() );
private static final Pattern reTime = Pattern.compile("\\A(\\d+\\D+\\d+\\D+\\d+\\D+\\d+\\D+\\d+\\D+\\d+\\D+\\d+)");
private static final SimpleDateFormat date_format_utc = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.getDefault() );
static long parseTime( LogCategory log, String strTime ){
if( ! TextUtils.isEmpty( strTime ) ){
try{
Matcher m = reTime.matcher( strTime );
if(!m.find() ){
log.d("!!invalid time format: %s",strTime);
}else{
date_format_utc.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
return date_format_utc.parse( strTime ).getTime();
}catch( ParseException ex ){
return date_format_utc.parse( m.group( 1 ) ).getTime();
}
}catch( Throwable ex ){// ParseException, ArrayIndexOutOfBoundsException
ex.printStackTrace();
log.e( ex, "TootStatus.parseTime failed. src=%s",strTime );
}

View File

@ -0,0 +1,6 @@
package jp.juggler.subwaytooter.util;
public class ScrollPosition {
public int index;
public int offset;
}