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

670 lines
23 KiB
Java

package jp.juggler.subwaytooter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
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 java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import jp.juggler.subwaytooter.api.entity.TootAccount;
import jp.juggler.subwaytooter.api.entity.TootAttachment;
import jp.juggler.subwaytooter.api.entity.TootNotification;
import jp.juggler.subwaytooter.api.entity.TootReport;
import jp.juggler.subwaytooter.api.entity.TootStatus;
import jp.juggler.subwaytooter.table.ContentWarning;
import jp.juggler.subwaytooter.table.MediaShown;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.util.HTMLDecoder;
import jp.juggler.subwaytooter.util.LogCategory;
import jp.juggler.subwaytooter.util.Utils;
public class ColumnViewHolder implements View.OnClickListener, Column.VisualCallback {
static final LogCategory log = new LogCategory( "ColumnViewHolder" );
public final AtomicBoolean is_destroyed = new AtomicBoolean( false );
public final ActMain activity;
public final Column column;
public final int column_index;
public ColumnViewHolder( ActMain activity, Column column, int column_index ){
log.d( "ctor" );
this.activity = activity;
this.column = column;
this.column_index = column_index;
}
public boolean isPageDestroyed(){
return is_destroyed.get() || activity.isFinishing();
}
TextView tvLoading;
ListView listView;
TextView tvColumnContext;
TextView tvColumnName;
StatusListAdapter status_adapter;
HeaderViewHolder vh_header;
void onPageCreate( View root ){
log.d( "onPageCreate:%s", column.getColumnName() );
tvColumnName = (TextView) root.findViewById( R.id.tvColumnName );
tvColumnContext = (TextView) root.findViewById( R.id.tvColumnContext );
root.findViewById( R.id.btnColumnClose ).setOnClickListener( this );
root.findViewById( R.id.btnColumnReload ).setOnClickListener( this );
tvLoading = (TextView) root.findViewById( R.id.tvLoading );
listView = (ListView) root.findViewById( R.id.listView );
status_adapter = new StatusListAdapter();
listView.setAdapter( status_adapter );
if( column.type == Column.TYPE_TL_STATUSES ){
vh_header = new HeaderViewHolder( activity, listView );
listView.addHeaderView( vh_header.viewRoot );
}
//
column.addVisualListener( this );
onVisualColumn();
}
void onPageDestroy( View root ){
log.d( "onPageDestroy:%s", column.getColumnName() );
column.removeVisualListener( this );
}
@Override
public void onClick( View v ){
switch( v.getId() ){
case R.id.btnColumnClose:
activity.performColumnClose( false, column );
break;
case R.id.btnColumnReload:
column.reload();
break;
}
}
void showError( String message ){
tvLoading.setVisibility( View.VISIBLE );
listView.setVisibility( View.GONE );
tvLoading.setText( message );
}
@Override
public void onVisualColumn(){
tvColumnContext.setText( column.access_info.getFullAcct( column.access_info ) );
tvColumnName.setText( column.getColumnName() );
if( column.is_dispose.get() ){
showError( "column was disposed." );
return;
}
if( vh_header != null ){
vh_header.bind( activity, column.access_info, column.who_account );
}
if( column.is_loading ){
String message = column.task_progress;
if( message == null ) message = "loading?";
showError( message );
return;
}
switch( column.type ){
default:
case Column.TYPE_TL_HOME:
case Column.TYPE_TL_LOCAL:
case Column.TYPE_TL_FEDERATE:
case Column.TYPE_TL_FAVOURITES:
case Column.TYPE_TL_STATUSES:
if( column.status_list.isEmpty() && vh_header == null ){
showError( activity.getString( R.string.list_empty ) );
}else{
tvLoading.setVisibility( View.GONE );
listView.setVisibility( View.VISIBLE );
status_adapter.set( column.status_list );
}
break;
case Column.TYPE_TL_REPORTS:
if( column.report_list.isEmpty() ){
showError( activity.getString( R.string.list_empty ) );
}else{
tvLoading.setVisibility( View.GONE );
listView.setVisibility( View.VISIBLE );
status_adapter.set( column.report_list );
}
break;
case Column.TYPE_TL_NOTIFICATIONS:
if( column.notification_list.isEmpty() ){
showError( activity.getString( R.string.list_empty ) );
}else{
tvLoading.setVisibility( View.GONE );
listView.setVisibility( View.VISIBLE );
status_adapter.set( column.notification_list );
}
break;
}
}
///////////////////////////////////////////////////////////////////
class StatusListAdapter extends BaseAdapter {
final ArrayList< Object > status_list = new ArrayList<>();
public void set( TootStatus.List src ){
this.status_list.clear();
this.status_list.addAll( src );
notifyDataSetChanged();
}
public void set( TootReport.List src ){
this.status_list.clear();
this.status_list.addAll( src );
notifyDataSetChanged();
}
public void set( TootNotification.List src ){
this.status_list.clear();
this.status_list.addAll( src );
notifyDataSetChanged();
}
@Override
public int getCount(){
return status_list.size();
}
@Override
public Object getItem( int position ){
if( position >= 0 && position < status_list.size() ) return status_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 < status_list.size() ? status_list.get( position ) : null );
StatusViewHolder holder;
if( view == null ){
view = activity.getLayoutInflater().inflate( R.layout.lv_status, parent, false );
holder = new StatusViewHolder( view );
view.setTag( holder );
}else{
holder = (StatusViewHolder) view.getTag();
}
holder.bind( activity, view, o, column.access_info );
return view;
}
}
class StatusViewHolder implements View.OnClickListener {
final View llBoosted;
final ImageView ivBoosted;
final TextView tvBoosted;
final TextView tvBoostedTime;
final View llFollow;
final NetworkImageView ivFollow;
final TextView tvFollowerName;
final TextView tvFollowerAcct;
final ImageButton btnFollow;
final View llStatus;
final NetworkImageView ivThumbnail;
final TextView tvName;
final TextView tvTime;
final View llContentWarning;
final TextView tvContentWarning;
final Button btnContentWarning;
final View llContents;
final TextView tvTags;
final TextView tvMentions;
final TextView tvContent;
final View flMedia;
final View btnHideMedia;
final View btnShowMedia;
final NetworkImageView ivMedia1;
final NetworkImageView ivMedia2;
final NetworkImageView ivMedia3;
final NetworkImageView ivMedia4;
final ImageButton btnReply;
final Button btnBoost;
final Button btnFavourite;
final ImageButton btnMore;
TootStatus status;
SavedAccount account;
TootAccount account_thumbnail;
TootAccount account_boost;
TootAccount account_follow;
public StatusViewHolder( View view ){
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.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.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.llContentWarning = view.findViewById( R.id.llContentWarning );
this.tvContentWarning = (TextView) view.findViewById( R.id.tvContentWarning );
this.btnContentWarning = (Button) view.findViewById( R.id.btnContentWarning );
this.llContents = view.findViewById( R.id.llContents );
this.tvContent = (TextView) view.findViewById( R.id.tvContent );
this.tvTags = (TextView) view.findViewById( R.id.tvTags );
this.tvMentions = (TextView) view.findViewById( R.id.tvMentions );
this.btnReply = (ImageButton) view.findViewById( R.id.btnReply );
this.btnBoost = (Button) view.findViewById( R.id.btnBoost );
this.btnFavourite = (Button) view.findViewById( R.id.btnFavourite );
this.btnMore = (ImageButton) view.findViewById( R.id.btnMore );
this.flMedia = view.findViewById( R.id.flMedia );
this.btnHideMedia = view.findViewById( R.id.btnHideMedia );
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 );
btnContentWarning.setOnClickListener( this );
btnHideMedia.setOnClickListener( this );
btnShowMedia.setOnClickListener( this );
ivMedia1.setOnClickListener( this );
ivMedia2.setOnClickListener( this );
ivMedia3.setOnClickListener( this );
ivMedia4.setOnClickListener( this );
btnReply.setOnClickListener( this );
btnBoost.setOnClickListener( this );
btnFavourite.setOnClickListener( this );
btnMore.setOnClickListener( this );
ivThumbnail.setOnClickListener( this );
tvName.setOnClickListener( this );
llBoosted.setOnClickListener( this );
llFollow.setOnClickListener( this );
btnFollow.setOnClickListener( this );
tvContent.setMovementMethod( LinkMovementMethod.getInstance() );
tvTags.setMovementMethod( LinkMovementMethod.getInstance() );
tvMentions.setMovementMethod( LinkMovementMethod.getInstance() );
}
public void bind( ActMain activity, View view, Object item, SavedAccount access_info ){
this.account = access_info;
llBoosted.setVisibility( View.GONE );
llFollow.setVisibility( View.GONE );
llStatus.setVisibility( View.GONE );
if( item == null ) return;
if( item instanceof TootNotification ){
TootNotification n = (TootNotification) item;
if( TootNotification.TYPE_FAVOURITE.equals( n.type ) ){
account_boost = n.account;
llBoosted.setVisibility( View.VISIBLE );
ivBoosted.setImageResource( R.drawable.btn_favourite );
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
+ "\n" + access_info.getFullAcct(account_boost )
);
tvBoosted.setText( Utils.formatSpannable1( activity,R.string.display_name_favourited_by, account_boost.display_name));
if( n.status != null ) bindSub( activity, view, n.status, access_info );
}else if( TootNotification.TYPE_REBLOG.equals( n.type ) ){
account_boost = n.account;
llBoosted.setVisibility( View.VISIBLE );
ivBoosted.setImageResource( R.drawable.btn_boost );
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
+ "\n" + access_info.getFullAcct(account_boost )
);
tvBoosted.setText( Utils.formatSpannable1( activity, R.string.display_name_boosted_by, account_boost.display_name ) );
account_boost = n.account;
if( n.status != null ) bindSub( activity, view, n.status, access_info );
}else if( TootNotification.TYPE_FOLLOW.equals( n.type ) ){
account_boost = n.account;
llBoosted.setVisibility( View.VISIBLE );
ivBoosted.setImageResource( R.drawable.btn_boost );
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
+ "\n" + access_info.getFullAcct( account_boost )
);
tvBoosted.setText( Utils.formatSpannable1( activity, R.string.display_name_followed_by, account_boost.display_name ) );
//
account_follow = n.account;
llFollow.setVisibility( View.VISIBLE );
ivFollow.setImageUrl( account_follow.avatar_static, App1.getImageLoader() );
tvFollowerName.setText(account_follow.display_name );
tvFollowerAcct.setText( access_info.getFullAcct( account_follow ) );
}else if( TootNotification.TYPE_MENTION.equals( n.type ) ){
account_boost = n.account;
llBoosted.setVisibility( View.VISIBLE );
ivBoosted.setImageResource( R.drawable.btn_reply );
tvBoostedTime.setText( TootStatus.formatTime( n.time_created_at )
+ "\n" + access_info.getFullAcct(account_boost )
);
tvBoosted.setText( Utils.formatSpannable1( activity, R.string.display_name_replied_by, account_boost.display_name ) );
if( n.status != null ) bindSub( activity, view, n.status, access_info );
}
return;
}
if( item instanceof TootStatus ){
TootStatus status = (TootStatus) item;
if( status.reblog != null ){
account_boost = status.account;
llBoosted.setVisibility( View.VISIBLE );
ivBoosted.setImageResource( R.drawable.btn_boost );
tvBoostedTime.setText( TootStatus.formatTime( status.time_created_at )
+ "\n" + access_info.getFullAcct( account_boost )
);
tvBoosted.setText( Utils.formatSpannable1( activity, R.string.display_name_boosted_by, status.account.display_name ) );
bindSub( activity, view, status.reblog, access_info );
}else{
bindSub( activity, view, status, access_info );
}
}
}
private void bindSub( ActMain activity, View view, TootStatus status, SavedAccount account ){
this.status = status;
account_thumbnail = status.account;
llStatus.setVisibility( View.VISIBLE );
tvTime.setText( TootStatus.formatTime( status.time_created_at )
+ "\n" + account.getFullAcct( status.account )
);
tvName.setText( status.account.display_name );
ivThumbnail.setImageUrl( 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.spoiler_text );
boolean cw_shown = ContentWarning.isShown( account.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( account.host, status.id, account.dont_hide_nsfw || ! status.sensitive );
btnShowMedia.setVisibility( ! is_shown ? View.VISIBLE : View.GONE );
}
Drawable d;
int color;
if( activity.isBusyBoost( account,status )){
color = 0xff000000;
d = ContextCompat.getDrawable( activity, R.drawable.btn_boost ).mutate();
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
btnBoost.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
btnBoost.setText( "?" );
btnBoost.setTextColor( color );
}else{
color = ( status.reblogged ? 0xff0088ff : 0xff000000 );
d = ContextCompat.getDrawable( activity, R.drawable.btn_boost ).mutate();
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
btnBoost.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
btnBoost.setText( Long.toString( status.reblogs_count ) );
btnBoost.setTextColor( color );
}
if( activity.isBusyFav( account,status )){
color = 0xff000000;
d = ContextCompat.getDrawable( activity, R.drawable.btn_refresh ).mutate();
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
btnFavourite.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
btnFavourite.setText( "?" );
btnFavourite.setTextColor( color );
}else{
color = ( status.favourited ? 0xff0088ff : 0xff000000 );
d = ContextCompat.getDrawable( activity, R.drawable.btn_favourite ).mutate();
d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP );
btnFavourite.setCompoundDrawablesRelativeWithIntrinsicBounds( d, null, null, null );
btnFavourite.setText( Long.toString( status.favourites_count ) );
btnFavourite.setTextColor( color );
}
}
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( url, App1.getImageLoader() );
}
}
@Override
public void onClick( View v ){
switch( v.getId() ){
case R.id.btnHideMedia:
MediaShown.save( account.host, status.id, false );
btnShowMedia.setVisibility( View.VISIBLE );
break;
case R.id.btnShowMedia:
MediaShown.save( account.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( account.host, status.id, new_shown );
showContent( new_shown );
break;
}
case R.id.btnReply:
activity.performReply( account,status);
break;
case R.id.btnBoost:
activity.performBoost( account,status.reblog != null ? status.reblog : status ,false);
break;
case R.id.btnFavourite:
activity.performFavourite( account,status.reblog != null ? status.reblog : status);
break;
case R.id.btnMore:
activity.performMore( account,status);
break;
case R.id.ivThumbnail:
case R.id.tvName:
activity.performOpenUser(account,account_thumbnail);
break;
case R.id.llBoosted:
activity.performOpenUser(account,account_boost);
break;
case R.id.llFollow:
activity.performOpenUser(account,account_follow);
break;
}
}
private void clickMedia( int i ){
try{
TootAttachment a = status.media_attachments.get( i );
String sv = a.remote_url;
if( TextUtils.isEmpty( sv ) ){
sv = a.url;
}
activity.openChromeTab( sv );
}catch( Throwable ex ){
ex.printStackTrace();
}
}
}
class HeaderViewHolder implements View.OnClickListener {
final View viewRoot;
final NetworkImageView ivBackground;
final TextView tvCreated;
final NetworkImageView ivAvatar;
final TextView tvDisplayName;
final TextView tvAcct;
final Button btnFollowing;
final Button btnFollowers;
final Button btnStatusCount;
final TextView tvNote;
TootAccount who;
public HeaderViewHolder( final ActMain activity, ListView parent ){
viewRoot = activity.getLayoutInflater().inflate( R.layout.lv_list_header, parent, false );
this.ivBackground = (NetworkImageView) viewRoot.findViewById( R.id.ivBackground );
this.tvCreated = (TextView) viewRoot.findViewById( R.id.tvCreated );
this.ivAvatar = (NetworkImageView) viewRoot.findViewById( R.id.ivAvatar );
this.tvDisplayName = (TextView) viewRoot.findViewById( R.id.tvDisplayName );
this.tvAcct = (TextView) viewRoot.findViewById( R.id.tvAcct );
this.btnFollowing = (Button) viewRoot.findViewById( R.id.btnFollowing );
this.btnFollowers = (Button) viewRoot.findViewById( R.id.btnFollowers );
this.btnStatusCount = (Button) viewRoot.findViewById( R.id.btnStatusCount );
this.tvNote = (TextView) viewRoot.findViewById( R.id.tvNote );
ivBackground.setOnClickListener( this );
btnFollowing.setOnClickListener( this );
btnFollowers.setOnClickListener( this );
btnStatusCount.setOnClickListener( this );
tvNote.setMovementMethod( LinkMovementMethod.getInstance() );
}
public void bind( ActMain activity, SavedAccount access_info, 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" + "?" );
}else{
tvCreated.setText( TootStatus.formatTime( who.time_created_at ) );
ivBackground.setImageUrl( who.header_static, App1.getImageLoader() );
ivAvatar.setImageUrl( who.avatar_static, App1.getImageLoader() );
tvDisplayName.setText( who.display_name );
tvAcct.setText( access_info.getFullAcct( who ) );
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 );
}
}
@Override
public void onClick( View v ){
switch( v.getId() ){
case R.id.ivBackground:
if( who != null ){
activity.openBrowser( who.url );
}
break;
case R.id.btnFollowing:
Utils.showToast( activity, false, "not implemented" );
break;
case R.id.btnFollowers:
Utils.showToast( activity, false, "not implemented" );
break;
case R.id.btnStatusCount:
Utils.showToast( activity, false, "not implemented" );
break;
}
}
}
}