@ -10,10 +10,15 @@ import android.net.Uri;
import android.os.Build ;
import android.os.Build ;
import android.os.Bundle ;
import android.os.Bundle ;
import android.support.annotation.NonNull ;
import android.support.annotation.NonNull ;
import android.support.annotation.Nullable ;
import android.support.v4.content.res.ResourcesCompat ;
import android.support.v4.content.res.ResourcesCompat ;
import android.support.v7.widget.AppCompatImageButton ;
import android.support.v7.widget.CardView ;
import android.support.v7.widget.CardView ;
import android.support.v7.widget.RecyclerView ;
import android.support.v7.widget.RecyclerView ;
import android.text.Editable ;
import android.text.TextUtils ;
import android.text.TextUtils ;
import android.text.TextWatcher ;
import android.view.LayoutInflater ;
import android.view.LayoutInflater ;
import android.view.MotionEvent ;
import android.view.MotionEvent ;
import android.view.View ;
import android.view.View ;
@ -21,6 +26,7 @@ import android.view.ViewGroup;
import android.webkit.WebResourceRequest ;
import android.webkit.WebResourceRequest ;
import android.webkit.WebView ;
import android.webkit.WebView ;
import android.webkit.WebViewClient ;
import android.webkit.WebViewClient ;
import android.widget.EditText ;
import android.widget.FrameLayout ;
import android.widget.FrameLayout ;
import android.widget.ImageButton ;
import android.widget.ImageButton ;
import android.widget.ImageView ;
import android.widget.ImageView ;
@ -30,8 +36,14 @@ import android.widget.TextView;
import com.squareup.picasso.Picasso ;
import com.squareup.picasso.Picasso ;
import java.text.DateFormat ;
import java.text.ParseException ;
import java.text.SimpleDateFormat ;
import java.util.ArrayList ;
import java.util.ArrayList ;
import java.util.Calendar ;
import java.util.Date ;
import java.util.List ;
import java.util.List ;
import java.util.Locale ;
import java.util.Objects ;
import java.util.Objects ;
import gr.thmmy.mthmmy.R ;
import gr.thmmy.mthmmy.R ;
@ -42,7 +54,8 @@ import gr.thmmy.mthmmy.model.Post;
import gr.thmmy.mthmmy.model.ThmmyFile ;
import gr.thmmy.mthmmy.model.ThmmyFile ;
import gr.thmmy.mthmmy.model.ThmmyPage ;
import gr.thmmy.mthmmy.model.ThmmyPage ;
import gr.thmmy.mthmmy.utils.CircleTransform ;
import gr.thmmy.mthmmy.utils.CircleTransform ;
import mthmmy.utils.Report ;
import timber.log.Timber ;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK ;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK ;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE ;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE ;
@ -50,21 +63,20 @@ import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL ;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL ;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL ;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL ;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME ;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME ;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.toQuoteList ;
import static gr.thmmy.mthmmy.activities.topic.Posting.htmlToBBcode ;
import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager ;
/ * *
/ * *
* Custom { @link android . support . v7 . widget . RecyclerView . Adapter } used for topics .
* Custom { @link android . support . v7 . widget . RecyclerView . Adapter } used for topics .
* /
* /
class TopicAdapter extends RecyclerView . Adapter < TopicAdapter . MyViewHolder > {
class TopicAdapter extends RecyclerView . Adapter < RecyclerView . ViewHolder > {
/ * *
* Debug Tag for logging debug output to LogCat
* /
private static final String TAG = "TopicAdapter" ;
/ * *
/ * *
* Int that holds thumbnail ' s size defined in R . dimen
* Int that holds thumbnail ' s size defined in R . dimen
* /
* /
private static int THUMBNAIL_SIZE ;
private static int THUMBNAIL_SIZE ;
private final Context context ;
private final Context context ;
private String topicTitle ;
private ArrayList < Integer > toQuoteList = new ArrayList < > ( ) ;
private final List < Post > postsList ;
private final List < Post > postsList ;
/ * *
/ * *
* Used to hold the state of visibility and other attributes for views that are animated or
* Used to hold the state of visibility and other attributes for views that are animated or
@ -87,69 +99,20 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
* /
* /
private static final int isQuoteButtonChecked = 2 ;
private static final int isQuoteButtonChecked = 2 ;
private TopicActivity . TopicTask topicTask ;
private TopicActivity . TopicTask topicTask ;
private TopicActivity . ReplyTask replyTask ;
private final int VIEW_TYPE_POST = 0 ;
private final int VIEW_TYPE_QUICK_REPLY = 1 ;
/ * *
private String [ ] replyDataHolder = new String [ 2 ] ;
* Custom { @link RecyclerView . ViewHolder } implementation
private int replySubject = 0 , replyText = 1 ;
* /
private String loadedPageUrl = "" ;
class MyViewHolder extends RecyclerView . ViewHolder {
final CardView cardView ;
final LinearLayout cardChildLinear ;
final FrameLayout postDateAndNumberExp ;
final TextView postDate , postNum , username , subject ;
final ImageView thumbnail ;
final public WebView post ;
final ImageButton quoteToggle ;
final RelativeLayout header ;
final LinearLayout userExtraInfo ;
final View bodyFooterDivider ;
final LinearLayout postFooter ;
final TextView specialRank , rank , gender , numberOfPosts , personalText , stars ;
MyViewHolder ( View view ) {
super ( view ) ;
//Initializes layout's graphic elements
//Standard stuff
cardView = ( CardView ) view . findViewById ( R . id . card_view ) ;
cardChildLinear = ( LinearLayout ) view . findViewById ( R . id . card_child_linear ) ;
postDateAndNumberExp = ( FrameLayout ) view . findViewById ( R . id . post_date_and_number_exp ) ;
postDate = ( TextView ) view . findViewById ( R . id . post_date ) ;
postNum = ( TextView ) view . findViewById ( R . id . post_number ) ;
thumbnail = ( ImageView ) view . findViewById ( R . id . thumbnail ) ;
username = ( TextView ) view . findViewById ( R . id . username ) ;
subject = ( TextView ) view . findViewById ( R . id . subject ) ;
post = ( WebView ) view . findViewById ( R . id . post ) ;
post . setBackgroundColor ( Color . argb ( 1 , 255 , 255 , 255 ) ) ;
quoteToggle = ( ImageButton ) view . findViewById ( R . id . toggle_quote_button ) ;
bodyFooterDivider = view . findViewById ( R . id . body_footer_divider ) ;
postFooter = ( LinearLayout ) view . findViewById ( R . id . post_footer ) ;
//User's extra info
header = ( RelativeLayout ) view . findViewById ( R . id . header ) ;
userExtraInfo = ( LinearLayout ) view . findViewById ( R . id . user_extra_info ) ;
specialRank = ( TextView ) view . findViewById ( R . id . special_rank ) ;
rank = ( TextView ) view . findViewById ( R . id . rank ) ;
gender = ( TextView ) view . findViewById ( R . id . gender ) ;
numberOfPosts = ( TextView ) view . findViewById ( R . id . number_of_posts ) ;
personalText = ( TextView ) view . findViewById ( R . id . personal_text ) ;
stars = ( TextView ) view . findViewById ( R . id . stars ) ;
}
/ * *
* Cancels all pending Picasso requests
* /
void cleanup ( ) {
Picasso . with ( context ) . cancelRequest ( thumbnail ) ;
thumbnail . setImageDrawable ( null ) ;
}
}
/ * *
/ * *
* @param context the context of the { @link RecyclerView }
* @param context the context of the { @link RecyclerView }
* @param postsList List of { @link Post } objects to use
* @param postsList List of { @link Post } objects to use
* /
* /
TopicAdapter ( Context context , List < Post > postsList ,
TopicAdapter ( Context context , List < Post > postsList , TopicActivity . TopicTask topicTask
TopicActivity . TopicTask topicTask ) {
, String topicTitle , String loadedPageUrl ) {
this . context = context ;
this . context = context ;
this . postsList = postsList ;
this . postsList = postsList ;
@ -159,177 +122,225 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
viewProperties . add ( new boolean [ 3 ] ) ;
viewProperties . add ( new boolean [ 3 ] ) ;
}
}
this . topicTask = topicTask ;
this . topicTask = topicTask ;
this . topicTitle = topicTitle ;
this . loadedPageUrl = loadedPageUrl ;
}
}
@Override
void prepareForReply ( TopicActivity . ReplyTask replyTask ) {
public void onViewRecycled ( final MyViewHolder holder ) {
this . replyTask = replyTask ;
holder . cleanup ( ) ;
}
void setTopicInfo ( String topicTitle , String loadedPageUrl ) {
this . topicTitle = topicTitle ;
this . loadedPageUrl = loadedPageUrl ;
}
}
@Override
@Override
public MyViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) {
public int getItemViewType ( int position ) {
View itemView = LayoutInflater . from ( parent . getContext ( ) )
return postsList . get ( position ) = = null ? VIEW_TYPE_QUICK_REPLY : VIEW_TYPE_POST ;
. inflate ( R . layout . activity_topic_post_row , parent , false ) ;
return new MyViewHolder ( itemView ) ;
}
}
@SuppressLint ( "SetJavaScriptEnabled" )
@Override
@Override
public void onBindViewHolder ( final MyViewHolder holder , final int position ) {
public RecyclerView . ViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) {
final Post currentPost = postsList . get ( position ) ;
if ( viewType = = VIEW_TYPE_POST ) {
View itemView = LayoutInflater . from ( parent . getContext ( ) )
//Post's WebView parameters
. inflate ( R . layout . activity_topic_post_row , parent , false ) ;
holder . post . setClickable ( true ) ;
return new PostViewHolder ( itemView ) ;
holder . post . setWebViewClient ( new LinkLauncher ( ) ) ;
} else if ( viewType = = VIEW_TYPE_QUICK_REPLY ) {
View view = LayoutInflater . from ( parent . getContext ( ) ) .
//Avoids errors about layout having 0 width/height
inflate ( R . layout . activity_topic_quick_reply_row , parent , false ) ;
holder . thumbnail . setMinimumWidth ( 1 ) ;
view . findViewById ( R . id . quick_reply_submit ) . setEnabled ( true ) ;
holder . thumbnail . setMinimumHeight ( 1 ) ;
//Default post subject
//Sets thumbnail size
replyDataHolder [ replySubject ] = "Re: " + topicTitle ;
holder . thumbnail . setMaxWidth ( THUMBNAIL_SIZE ) ;
//Build quotes
holder . thumbnail . setMaxHeight ( THUMBNAIL_SIZE ) ;
String quotes = "" ;
for ( int quotePosition : toQuoteList ) {
//noinspection ConstantConditions
quotes + = buildQuote ( quotePosition ) ;
Picasso . with ( context )
}
. load ( currentPost . getThumbnailUrl ( ) )
if ( ! Objects . equals ( quotes , "" ) )
. resize ( THUMBNAIL_SIZE , THUMBNAIL_SIZE )
replyDataHolder [ replyText ] = htmlToBBcode ( quotes ) ;
. centerCrop ( )
return new QuickReplyViewHolder ( view , new CustomEditTextListener ( replySubject ) ,
. error ( ResourcesCompat . getDrawable ( context . getResources ( )
new CustomEditTextListener ( replyText ) ) ;
, R . drawable . ic_default_user_thumbnail , null ) )
}
. placeholder ( ResourcesCompat . getDrawable ( context . getResources ( )
return null ;
, R . drawable . ic_default_user_thumbnail , null ) )
}
. transform ( new CircleTransform ( ) )
. into ( holder . thumbnail ) ;
//Sets username,submit date, index number, subject, post's and attached files texts
holder . username . setText ( currentPost . getAuthor ( ) ) ;
holder . postDate . setText ( currentPost . getPostDate ( ) ) ;
if ( currentPost . getPostNumber ( ) ! = 0 )
holder . postNum . setText ( context . getString (
R . string . user_number_of_posts , currentPost . getPostNumber ( ) ) ) ;
else
holder . postNum . setText ( "" ) ;
holder . subject . setText ( currentPost . getSubject ( ) ) ;
holder . post . loadDataWithBaseURL ( "file:///android_asset/" , currentPost . getContent ( ) , "text/html" , "UTF-8" , null ) ;
if ( currentPost . getAttachedFiles ( ) ! = null & & currentPost . getAttachedFiles ( ) . size ( ) ! = 0 ) {
holder . bodyFooterDivider . setVisibility ( View . VISIBLE ) ;
int filesTextColor ;
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M ) {
filesTextColor = context . getResources ( ) . getColor ( R . color . accent , null ) ;
} else //noinspection deprecation
filesTextColor = context . getResources ( ) . getColor ( R . color . accent ) ;
holder . postFooter . removeAllViews ( ) ;
for ( final ThmmyFile attachedFile : currentPost . getAttachedFiles ( ) ) {
final TextView attached = new TextView ( context ) ;
attached . setTextSize ( 10f ) ;
attached . setClickable ( true ) ;
attached . setTypeface ( Typeface . createFromAsset ( context . getAssets ( )
, "fonts/fontawesome-webfont.ttf" ) ) ;
attached . setText ( faIconFromFilename ( attachedFile . getFilename ( ) ) + " "
+ attachedFile . getFilename ( ) + attachedFile . getFileInfo ( ) ) ;
attached . setTextColor ( filesTextColor ) ;
attached . setPadding ( 0 , 3 , 0 , 3 ) ;
attached . setOnClickListener ( new View . OnClickListener ( ) {
@SuppressLint ( { "SetJavaScriptEnabled" , "SetTextI18n" } )
@Override
@Override
public void onClick ( View view ) {
public void onBindViewHolder ( final RecyclerView . ViewHolder currentHolder , final int position ) {
( ( BaseActivity ) context ) . launchDownloadService ( attachedFile ) ;
if ( currentHolder instanceof PostViewHolder ) {
final Post currentPost = postsList . get ( position ) ;
final PostViewHolder holder = ( PostViewHolder ) currentHolder ;
//Post's WebView parameters
holder . post . setClickable ( true ) ;
holder . post . setWebViewClient ( new LinkLauncher ( ) ) ;
//Avoids errors about layout having 0 width/height
holder . thumbnail . setMinimumWidth ( 1 ) ;
holder . thumbnail . setMinimumHeight ( 1 ) ;
//Sets thumbnail size
holder . thumbnail . setMaxWidth ( THUMBNAIL_SIZE ) ;
holder . thumbnail . setMaxHeight ( THUMBNAIL_SIZE ) ;
//noinspection ConstantConditions
Picasso . with ( context )
. load ( currentPost . getThumbnailUrl ( ) )
. resize ( THUMBNAIL_SIZE , THUMBNAIL_SIZE )
. centerCrop ( )
. error ( ResourcesCompat . getDrawable ( context . getResources ( )
, R . drawable . ic_default_user_thumbnail , null ) )
. placeholder ( ResourcesCompat . getDrawable ( context . getResources ( )
, R . drawable . ic_default_user_thumbnail , null ) )
. transform ( new CircleTransform ( ) )
. into ( holder . thumbnail ) ;
//Sets username,submit date, index number, subject, post's and attached files texts
holder . username . setText ( currentPost . getAuthor ( ) ) ;
holder . postDate . setText ( currentPost . getPostDate ( ) ) ;
if ( currentPost . getPostNumber ( ) ! = 0 )
holder . postNum . setText ( context . getString (
R . string . user_number_of_posts , currentPost . getPostNumber ( ) ) ) ;
else
holder . postNum . setText ( "" ) ;
holder . subject . setText ( currentPost . getSubject ( ) ) ;
holder . post . loadDataWithBaseURL ( "file:///android_asset/" , currentPost . getContent ( ) , "text/html" , "UTF-8" , null ) ;
if ( ( currentPost . getAttachedFiles ( ) ! = null & & currentPost . getAttachedFiles ( ) . size ( ) ! = 0 )
| | ( currentPost . getLastEdit ( ) ! = null ) ) {
holder . bodyFooterDivider . setVisibility ( View . VISIBLE ) ;
holder . postFooter . removeAllViews ( ) ;
if ( currentPost . getAttachedFiles ( ) ! = null & & currentPost . getAttachedFiles ( ) . size ( ) ! = 0 ) {
int filesTextColor ;
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M ) {
filesTextColor = context . getResources ( ) . getColor ( R . color . accent , null ) ;
} else //noinspection deprecation
filesTextColor = context . getResources ( ) . getColor ( R . color . accent ) ;
for ( final ThmmyFile attachedFile : currentPost . getAttachedFiles ( ) ) {
final TextView attached = new TextView ( context ) ;
attached . setTextSize ( 10f ) ;
attached . setClickable ( true ) ;
attached . setTypeface ( Typeface . createFromAsset ( context . getAssets ( )
, "fonts/fontawesome-webfont.ttf" ) ) ;
attached . setText ( faIconFromFilename ( attachedFile . getFilename ( ) ) + " "
+ attachedFile . getFilename ( ) + attachedFile . getFileInfo ( ) ) ;
attached . setTextColor ( filesTextColor ) ;
attached . setPadding ( 0 , 3 , 0 , 3 ) ;
attached . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View view ) {
( ( BaseActivity ) context ) . launchDownloadService ( attachedFile ) ;
}
} ) ;
holder . postFooter . addView ( attached ) ;
}
}
} ) ;
}
if ( currentPost . getLastEdit ( ) ! = null & & currentPost . getLastEdit ( ) . length ( ) > 0 ) {
int lastEditTextColor ;
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M ) {
lastEditTextColor = context . getResources ( ) . getColor ( R . color . white , null ) ;
} else //noinspection deprecation
lastEditTextColor = context . getResources ( ) . getColor ( R . color . white ) ;
final TextView lastEdit = new TextView ( context ) ;
lastEdit . setTextSize ( 12f ) ;
lastEdit . setText ( currentPost . getLastEdit ( ) ) ;
lastEdit . setTextColor ( lastEditTextColor ) ;
lastEdit . setPadding ( 0 , 3 , 0 , 3 ) ;
holder . postFooter . addView ( lastEdit ) ;
}
} else {
holder . bodyFooterDivider . setVisibility ( View . GONE ) ;
holder . postFooter . removeAllViews ( ) ;
}
holder . postFooter . addView ( attached ) ;
String mSpecialRank , mRank , mGender , mNumberOfPosts , mPersonalText ;
int mNumberOfStars , mUserColor ;
if ( ! currentPost . isDeleted ( ) ) { //Sets user's extra info
mSpecialRank = currentPost . getSpecialRank ( ) ;
mRank = currentPost . getRank ( ) ;
mGender = currentPost . getGender ( ) ;
mNumberOfPosts = currentPost . getNumberOfPosts ( ) ;
mPersonalText = currentPost . getPersonalText ( ) ;
mNumberOfStars = currentPost . getNumberOfStars ( ) ;
mUserColor = currentPost . getUserColor ( ) ;
} else {
mSpecialRank = null ;
mRank = null ;
mGender = null ;
mNumberOfPosts = null ;
mPersonalText = null ;
mNumberOfStars = 0 ;
mUserColor = 0 ;
}
}
} else {
holder . bodyFooterDivider . setVisibility ( View . GONE ) ;
holder . postFooter . removeAllViews ( ) ;
}
String mSpecialRank , mRank , mGender , mNumberOfPosts , mPersonalText ;
if ( ! Objects . equals ( mSpecialRank , "" ) & & mSpecialRank ! = null ) {
int mNumberOfStars , mUserColor ;
holder . specialRank . setText ( mSpecialRank ) ;
holder . specialRank . setVisibility ( View . VISIBLE ) ;
if ( ! currentPost . isDeleted ( ) ) { //Sets user's extra info
} else
mSpecialRank = currentPost . getSpecialRank ( ) ;
holder . specialRank . setVisibility ( View . GONE ) ;
mRank = currentPost . getRank ( ) ;
if ( ! Objects . equals ( mRank , "" ) & & mRank ! = null ) {
mGender = currentPost . getGender ( ) ;
holder . rank . setText ( mRank ) ;
mNumberOfPosts = currentPost . getNumberOfPosts ( ) ;
holder . rank . setVisibility ( View . VISIBLE ) ;
mPersonalText = currentPost . getPersonalText ( ) ;
} else
mNumberOfStars = currentPost . getNumberOfStars ( ) ;
holder . rank . setVisibility ( View . GONE ) ;
mUserColor = currentPost . getUserColor ( ) ;
if ( ! Objects . equals ( mGender , "" ) & & mGender ! = null ) {
} else {
holder . gender . setText ( mGender ) ;
mSpecialRank = null ;
holder . gender . setVisibility ( View . VISIBLE ) ;
mRank = null ;
} else
mGender = null ;
holder . gender . setVisibility ( View . GONE ) ;
mNumberOfPosts = null ;
if ( ! Objects . equals ( mNumberOfPosts , "" ) & & mNumberOfPosts ! = null ) {
mPersonalText = null ;
holder . numberOfPosts . setText ( mNumberOfPosts ) ;
mNumberOfStars = 0 ;
holder . numberOfPosts . setVisibility ( View . VISIBLE ) ;
mUserColor = 0 ;
} else
}
holder . numberOfPosts . setVisibility ( View . GONE ) ;
if ( ! Objects . equals ( mPersonalText , "" ) & & mPersonalText ! = null ) {
holder . personalText . setText ( "\"" + mPersonalText + "\"" ) ;
holder . personalText . setVisibility ( View . VISIBLE ) ;
} else
holder . personalText . setVisibility ( View . GONE ) ;
if ( mNumberOfStars > 0 ) {
holder . stars . setTypeface ( Typeface . createFromAsset ( context . getAssets ( )
, "fonts/fontawesome-webfont.ttf" ) ) ;
if ( ! Objects . equals ( mSpecialRank , "" ) & & mSpecialRank ! = null ) {
String aStar = context . getResources ( ) . getString ( R . string . fa_icon_star ) ;
holder . specialRank . setText ( mSpecialRank ) ;
String usersStars = "" ;
holder . specialRank . setVisibility ( View . VISIBLE ) ;
for ( int i = 0 ; i < mNumberOfStars ; + + i ) {
} else
usersStars + = aStar ;
holder . specialRank . setVisibility ( View . GONE ) ;
}
if ( ! Objects . equals ( mRank , "" ) & & mRank ! = null ) {
holder . stars . setText ( usersStars ) ;
holder . rank . setText ( mRank ) ;
holder . stars . setTextColor ( mUserColor ) ;
holder . rank . setVisibility ( View . VISIBLE ) ;
holder . stars . setVisibility ( View . VISIBLE ) ;
} else
} else
holder . rank . setVisibility ( View . GONE ) ;
holder . stars . setVisibility ( View . GONE ) ;
if ( ! Objects . equals ( mGender , "" ) & & mGender ! = null ) {
//Special card for special member of the month!
holder . gender . setText ( mGender ) ;
if ( mUserColor = = TopicParser . USER_COLOR_PINK ) {
holder . gender . setVisibility ( View . VISIBLE ) ;
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . LOLLIPOP ) {
} else
holder . cardChildLinear . setBackground ( context . getResources ( ) .
holder . gender . setVisibility ( View . GONE ) ;
getDrawable ( R . drawable . member_of_the_month_card , null ) ) ;
if ( ! Objects . equals ( mNumberOfPosts , "" ) & & mNumberOfPosts ! = null ) {
} else //noinspection deprecation
holder . numberOfPosts . setText ( mNumberOfPosts ) ;
holder . cardChildLinear . setBackground ( context . getResources ( ) .
holder . numberOfPosts . setVisibility ( View . VISIBLE ) ;
getDrawable ( R . drawable . member_of_the_month_card ) ) ;
} else
} else holder . cardChildLinear . setBackground ( null ) ;
holder . numberOfPosts . setVisibility ( View . GONE ) ;
if ( ! Objects . equals ( mPersonalText , "" ) & & mPersonalText ! = null ) {
//Avoid's view's visibility recycling
holder . personalText . setText ( "\"" + mPersonalText + "\"" ) ;
if ( ! currentPost . isDeleted ( ) & & viewProperties . get ( position ) [ isUserExtraInfoVisibile ] ) {
holder . personalText . setVisibility ( View . VISIBLE ) ;
holder . userExtraInfo . setVisibility ( View . VISIBLE ) ;
} else
holder . userExtraInfo . setAlpha ( 1 . 0f ) ;
holder . personalText . setVisibility ( View . GONE ) ;
} else {
if ( mNumberOfStars > 0 ) {
holder . userExtraInfo . setVisibility ( View . GONE ) ;
holder . stars . setTypeface ( Typeface . createFromAsset ( context . getAssets ( )
holder . userExtraInfo . setAlpha ( 0 . 0f ) ;
, "fonts/fontawesome-webfont.ttf" ) ) ;
String aStar = context . getResources ( ) . getString ( R . string . fa_icon_star ) ;
String usersStars = "" ;
for ( int i = 0 ; i < mNumberOfStars ; + + i ) {
usersStars + = aStar ;
}
}
holder . stars . setText ( usersStars ) ;
if ( ! currentPost . isDeleted ( ) ) {
holder . stars . setTextColor ( mUserColor ) ;
//Sets graphics behavior
holder . stars . setVisibility ( View . VISIBLE ) ;
holder . thumbnail . setOnClickListener ( new View . OnClickListener ( ) {
} else
@Override
holder . stars . setVisibility ( View . GONE ) ;
public void onClick ( View view ) {
//Special card for special member of the month!
//Clicking the thumbnail opens user's profile
if ( mUserColor = = TopicParser . USER_COLOR_PINK ) {
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . LOLLIPOP ) {
holder . cardChildLinear . setBackground ( context . getResources ( ) .
getDrawable ( R . drawable . member_of_the_month_card , null ) ) ;
} else //noinspection deprecation
holder . cardChildLinear . setBackground ( context . getResources ( ) .
getDrawable ( R . drawable . member_of_the_month_card ) ) ;
} else holder . cardChildLinear . setBackground ( null ) ;
//Avoid's view's visibility recycling
if ( ! currentPost . isDeleted ( ) & & viewProperties . get ( position ) [ isUserExtraInfoVisibile ] ) {
holder . userExtraInfo . setVisibility ( View . VISIBLE ) ;
holder . userExtraInfo . setAlpha ( 1 . 0f ) ;
} else {
holder . userExtraInfo . setVisibility ( View . GONE ) ;
holder . userExtraInfo . setAlpha ( 0 . 0f ) ;
}
if ( ! currentPost . isDeleted ( ) ) {
//Sets graphics behavior
holder . header . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
//Clicking an expanded header starts profile activity
if ( viewProperties . get ( holder . getAdapterPosition ( ) ) [ isUserExtraInfoVisibile ] ) {
Intent intent = new Intent ( context , ProfileActivity . class ) ;
Intent intent = new Intent ( context , ProfileActivity . class ) ;
Bundle extras = new Bundle ( ) ;
Bundle extras = new Bundle ( ) ;
extras . putString ( BUNDLE_PROFILE_URL , currentPost . getProfileURL ( ) ) ;
extras . putString ( BUNDLE_PROFILE_URL , currentPost . getProfileURL ( ) ) ;
@ -342,99 +353,138 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
intent . setFlags ( FLAG_ACTIVITY_NEW_TASK ) ;
intent . setFlags ( FLAG_ACTIVITY_NEW_TASK ) ;
context . startActivity ( intent ) ;
context . startActivity ( intent ) ;
}
}
} ) ;
holder . header . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
//Clicking the header makes it expand/collapse
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
tmp [ isUserExtraInfoVisibile ] = ! tmp [ isUserExtraInfoVisibile ] ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
TopicAnimations . animateUserExtraInfoVisibility ( holder . userExtraInfo ) ;
}
} ) ;
//Clicking the expanded part of a header (the extra info) makes it collapse
holder . userExtraInfo . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
tmp [ isUserExtraInfoVisibile ] = false ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
TopicAnimations . animateUserExtraInfoVisibility ( v ) ;
}
} ) ;
} else {
holder . header . setOnClickListener ( null ) ;
holder . userExtraInfo . setOnClickListener ( null ) ;
}
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
//Avoid's view's visibility recycling
tmp [ isUserExtraInfoVisibile ] = ! tmp [ isUserExtraInfoVisibile ] ;
if ( viewProperties . get ( position ) [ isPostDateAndNumberVisibile ] ) { //Expanded
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
holder . postDateAndNumberExp . setVisibility ( View . VISIBLE ) ;
TopicAnimations . animateUserExtraInfoVisibility ( holder . userExtraInfo ) ;
holder . postDateAndNumberExp . setAlpha ( 1 . 0f ) ;
}
holder . postDateAndNumberExp . setTranslationY ( 0 ) ;
} ) ;
//Clicking the expanded part of a header (the extra info) makes it collapse
holder . username . setMaxLines ( Integer . MAX_VALUE ) ;
holder . userExtraInfo . setOnClickListener ( new View . OnClickListener ( ) {
holder . username . setEllipsize ( null ) ;
holder . subject . setTextColor ( Color . parseColor ( "#FFFFFF" ) ) ;
holder . subject . setMaxLines ( Integer . MAX_VALUE ) ;
holder . subject . setEllipsize ( null ) ;
} else { //Collapsed
holder . postDateAndNumberExp . setVisibility ( View . GONE ) ;
holder . postDateAndNumberExp . setAlpha ( 0 . 0f ) ;
holder . postDateAndNumberExp . setTranslationY ( holder . postDateAndNumberExp . getHeight ( ) ) ;
holder . username . setMaxLines ( 1 ) ;
holder . username . setEllipsize ( TextUtils . TruncateAt . END ) ;
holder . subject . setTextColor ( Color . parseColor ( "#757575" ) ) ;
holder . subject . setMaxLines ( 1 ) ;
holder . subject . setEllipsize ( TextUtils . TruncateAt . END ) ;
}
//noinspection PointlessBooleanExpression,ConstantConditions
if ( ! BaseActivity . getSessionManager ( ) . isLoggedIn ( ) )
holder . quoteToggle . setVisibility ( View . GONE ) ;
else {
if ( viewProperties . get ( position ) [ isQuoteButtonChecked ] )
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_checked ) ;
else
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_unchecked ) ;
//Sets graphics behavior
holder . quoteToggle . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View view ) {
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
if ( tmp [ isQuoteButtonChecked ] ) {
if ( toQuoteList . contains ( postsList . indexOf ( currentPost ) ) ) {
toQuoteList . remove ( toQuoteList . indexOf ( postsList . indexOf ( currentPost ) ) ) ;
} else
Timber . i ( "An error occurred while trying to exclude post from" +
"toQuoteList, post wasn't there!" ) ;
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_unchecked ) ;
} else {
toQuoteList . add ( postsList . indexOf ( currentPost ) ) ;
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_checked ) ;
}
tmp [ isQuoteButtonChecked ] = ! tmp [ isQuoteButtonChecked ] ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
}
} ) ;
}
//Card expand/collapse when card is touched
holder . cardView . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View v ) {
public void onClick ( View view ) {
//Change post's viewProperties accordingly
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
tmp [ 1 ] = false ;
tmp [ isPostDateAndNumberVisibile ] = ! tmp [ isPostDateAndNumberVisibile ] ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
TopicAnimations . animateUserExtraInfoVisibility ( v ) ;
TopicAnimations . animatePostExtraInfoVisibility ( holder . postDateAndNumberExp
, holder . username , holder . subject
, Color . parseColor ( "#FFFFFF" )
, Color . parseColor ( "#757575" ) ) ;
}
}
} ) ;
} ) ;
} else {
//Also when post is clicked
holder . header . setOnClickListener ( null ) ;
holder . post . setOnTouchListener ( new CustomTouchListener ( holder . post , holder . cardView ) ) ;
holder . userExtraInfo . setOnClickListener ( null ) ;
} else if ( currentHolder instanceof QuickReplyViewHolder ) {
}
final QuickReplyViewHolder holder = ( QuickReplyViewHolder ) currentHolder ;
//Avoid's view's visibility recycling
//noinspection ConstantConditions
if ( viewProperties . get ( position ) [ isPostDateAndNumberVisibile ] ) { //Expanded
Picasso . with ( context )
holder . postDateAndNumberExp . setVisibility ( View . VISIBLE ) ;
. load ( getSessionManager ( ) . getAvatarLink ( ) )
holder . postDateAndNumberExp . setAlpha ( 1 . 0f ) ;
. resize ( THUMBNAIL_SIZE , THUMBNAIL_SIZE )
holder . postDateAndNumberExp . setTranslationY ( 0 ) ;
. centerCrop ( )
. error ( ResourcesCompat . getDrawable ( context . getResources ( )
holder . username . setMaxLines ( Integer . MAX_VALUE ) ;
, R . drawable . ic_default_user_thumbnail , null ) )
holder . username . setEllipsize ( null ) ;
. placeholder ( ResourcesCompat . getDrawable ( context . getResources ( )
, R . drawable . ic_default_user_thumbnail , null ) )
holder . subject . setTextColor ( Color . parseColor ( "#FFFFFF" ) ) ;
. transform ( new CircleTransform ( ) )
holder . subject . setMaxLines ( Integer . MAX_VALUE ) ;
. into ( holder . thumbnail ) ;
holder . subject . setEllipsize ( null ) ;
holder . username . setText ( getSessionManager ( ) . getUsername ( ) ) ;
} else { //Collapsed
holder . quickReplySubject . setText ( replyDataHolder [ replySubject ] ) ;
holder . postDateAndNumberExp . setVisibility ( View . GONE ) ;
holder . postDateAndNumberExp . setAlpha ( 0 . 0f ) ;
if ( replyDataHolder [ replyText ] ! = null & & ! Objects . equals ( replyDataHolder [ replyText ] , "" ) )
holder . postDateAndNumberExp . setTranslationY ( holder . postDateAndNumberExp . getHeight ( ) ) ;
holder . quickReply . setText ( replyDataHolder [ replyText ] ) ;
holder . username . setMaxLines ( 1 ) ;
holder . submitButton . setOnClickListener ( new View . OnClickListener ( ) {
holder . username . setEllipsize ( TextUtils . TruncateAt . END ) ;
holder . subject . setTextColor ( Color . parseColor ( "#757575" ) ) ;
holder . subject . setMaxLines ( 1 ) ;
holder . subject . setEllipsize ( TextUtils . TruncateAt . END ) ;
}
//noinspection PointlessBooleanExpression,ConstantConditions
if ( ! BaseActivity . getSessionManager ( ) . isLoggedIn ( ) | | true ) //Hide it until reply is implemented
holder . quoteToggle . setVisibility ( View . GONE ) ;
else {
if ( viewProperties . get ( position ) [ isQuoteButtonChecked ] )
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_checked ) ;
else
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_unchecked ) ;
//Sets graphics behavior
holder . quoteToggle . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View view ) {
public void onClick ( View view ) {
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
if ( holder . quickReplySubject . getText ( ) . toString ( ) . isEmpty ( ) ) return ;
if ( tmp [ isQuoteButtonChecked ] ) {
if ( holder . quickReply . getText ( ) . toString ( ) . isEmpty ( ) ) return ;
if ( toQuoteList . contains ( currentPost . getPostNumber ( ) ) ) {
holder . submitButton . setEnabled ( false ) ;
toQuoteList . remove ( toQuoteList . indexOf ( currentPost . getPostNumber ( ) ) ) ;
replyTask . execute ( holder . quickReplySubject . getText ( ) . toString ( ) ,
} else
holder . quickReply . getText ( ) . toString ( ) ) ;
Report . i ( TAG , "An error occurred while trying to exclude post from" +
"toQuoteList, post wasn't there!" ) ;
holder . quickReplySubject . getText ( ) . clear ( ) ;
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_unchecked ) ;
holder . quickReplySubject . setText ( "Re: " + topicTitle ) ;
} else {
holder . quickReply . getText ( ) . clear ( ) ;
toQuoteList . add ( currentPost . getPostNumber ( ) ) ;
holder . quoteToggle . setImageResource ( R . drawable . ic_format_quote_checked ) ;
}
tmp [ isQuoteButtonChecked ] = ! tmp [ isQuoteButtonChecked ] ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
}
}
} ) ;
} ) ;
}
}
//Card expand/collapse when card is touched
holder . cardView . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View view ) {
//Change post's viewProperties accordingly
boolean [ ] tmp = viewProperties . get ( holder . getAdapterPosition ( ) ) ;
tmp [ isPostDateAndNumberVisibile ] = ! tmp [ isPostDateAndNumberVisibile ] ;
viewProperties . set ( holder . getAdapterPosition ( ) , tmp ) ;
TopicAnimations . animatePostExtraInfoVisibility ( holder . postDateAndNumberExp
, holder . username , holder . subject
, Color . parseColor ( "#FFFFFF" )
, Color . parseColor ( "#757575" ) ) ;
}
} ) ;
//Also when post is clicked
holder . post . setOnTouchListener ( new CustomTouchListener ( holder . post , holder . cardView ) ) ;
}
}
void customNotifyDataSetChanged ( TopicActivity . TopicTask topicTask ) {
void customNotifyDataSetChanged ( TopicActivity . TopicTask topicTask ) {
@ -452,6 +502,79 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
return postsList . size ( ) ;
return postsList . size ( ) ;
}
}
/ * *
* Custom { @link RecyclerView . ViewHolder } implementation
* /
private class PostViewHolder extends RecyclerView . ViewHolder {
final CardView cardView ;
final LinearLayout cardChildLinear ;
final FrameLayout postDateAndNumberExp ;
final TextView postDate , postNum , username , subject ;
final ImageView thumbnail ;
final public WebView post ;
final ImageButton quoteToggle ;
final RelativeLayout header ;
final LinearLayout userExtraInfo ;
final View bodyFooterDivider ;
final LinearLayout postFooter ;
final TextView specialRank , rank , gender , numberOfPosts , personalText , stars ;
PostViewHolder ( View view ) {
super ( view ) ;
//Initializes layout's graphic elements
//Standard stuff
cardView = ( CardView ) view . findViewById ( R . id . card_view ) ;
cardChildLinear = ( LinearLayout ) view . findViewById ( R . id . card_child_linear ) ;
postDateAndNumberExp = ( FrameLayout ) view . findViewById ( R . id . post_date_and_number_exp ) ;
postDate = ( TextView ) view . findViewById ( R . id . post_date ) ;
postNum = ( TextView ) view . findViewById ( R . id . post_number ) ;
thumbnail = ( ImageView ) view . findViewById ( R . id . thumbnail ) ;
username = ( TextView ) view . findViewById ( R . id . username ) ;
subject = ( TextView ) view . findViewById ( R . id . subject ) ;
post = ( WebView ) view . findViewById ( R . id . post ) ;
post . setBackgroundColor ( Color . argb ( 1 , 255 , 255 , 255 ) ) ;
quoteToggle = ( ImageButton ) view . findViewById ( R . id . toggle_quote_button ) ;
bodyFooterDivider = view . findViewById ( R . id . body_footer_divider ) ;
postFooter = ( LinearLayout ) view . findViewById ( R . id . post_footer ) ;
//User's extra info
header = ( RelativeLayout ) view . findViewById ( R . id . header ) ;
userExtraInfo = ( LinearLayout ) view . findViewById ( R . id . user_extra_info ) ;
specialRank = ( TextView ) view . findViewById ( R . id . special_rank ) ;
rank = ( TextView ) view . findViewById ( R . id . rank ) ;
gender = ( TextView ) view . findViewById ( R . id . gender ) ;
numberOfPosts = ( TextView ) view . findViewById ( R . id . number_of_posts ) ;
personalText = ( TextView ) view . findViewById ( R . id . personal_text ) ;
stars = ( TextView ) view . findViewById ( R . id . stars ) ;
}
}
/ * *
* Custom { @link RecyclerView . ViewHolder } implementation
* /
private static class QuickReplyViewHolder extends RecyclerView . ViewHolder {
final ImageView thumbnail ;
final TextView username ;
final EditText quickReply , quickReplySubject ;
final AppCompatImageButton submitButton ;
final CustomEditTextListener replySubject , replyText ;
QuickReplyViewHolder ( View quickReply , CustomEditTextListener replySubject
, CustomEditTextListener replyText ) {
super ( quickReply ) ;
thumbnail = ( ImageView ) quickReply . findViewById ( R . id . thumbnail ) ;
username = ( TextView ) quickReply . findViewById ( R . id . username ) ;
this . quickReply = ( EditText ) quickReply . findViewById ( R . id . quick_reply_text ) ;
this . replyText = replyText ;
this . quickReply . addTextChangedListener ( replyText ) ;
quickReplySubject = ( EditText ) quickReply . findViewById ( R . id . quick_reply_subject ) ;
this . replySubject = replySubject ;
quickReplySubject . addTextChangedListener ( replySubject ) ;
submitButton = ( AppCompatImageButton ) quickReply . findViewById ( R . id . quick_reply_submit ) ;
}
}
/ * *
/ * *
* This class is a gesture detector for WebViews . It handles post ' s clicks , long clicks and
* This class is a gesture detector for WebViews . It handles post ' s clicks , long clicks and
* touch and drag .
* touch and drag .
@ -592,6 +715,84 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
//Method always returns true as no url should be loaded in the WebViews
//Method always returns true as no url should be loaded in the WebViews
return true ;
return true ;
}
}
}
private class CustomEditTextListener implements TextWatcher {
private final int positionInDataHolder ;
CustomEditTextListener ( int positionInDataHolder ) {
this . positionInDataHolder = positionInDataHolder ;
}
@Override
public void beforeTextChanged ( CharSequence charSequence , int i , int i2 , int i3 ) {
}
@Override
public void onTextChanged ( CharSequence charSequence , int i , int i2 , int i3 ) {
replyDataHolder [ positionInDataHolder ] = charSequence . toString ( ) ;
}
@Override
public void afterTextChanged ( Editable editable ) {
}
}
@Nullable
private String buildQuote ( int quotePosition ) {
Date postDate = null ;
{
String date = postsList . get ( quotePosition ) . getPostDate ( ) ;
if ( date ! = null ) {
DateFormat format = new SimpleDateFormat ( "MMMM d, yyyy, h:m:s a" , Locale . ENGLISH ) ;
date = date . replace ( "Ιανουαρίου" , "January" ) ;
date = date . replace ( "Φεβρουαρίου" , "February" ) ;
date = date . replace ( "Μαρτίου" , "March" ) ;
date = date . replace ( "Απριλίου" , "April" ) ;
date = date . replace ( "Μαΐου" , "May" ) ;
date = date . replace ( "Ιουνίου" , "June" ) ;
date = date . replace ( "Ιουλίου" , "July" ) ;
date = date . replace ( "Αυγούστου" , "August" ) ;
date = date . replace ( "Σεπτεμβρίου" , "September" ) ;
date = date . replace ( "Οκτωβρίου" , "October" ) ;
date = date . replace ( "Νοεμβρίου" , "November" ) ;
date = date . replace ( "Δεκεμβρίου" , "December" ) ;
if ( date . contains ( "Today" ) ) {
date = date . replace ( "Today at" ,
Calendar . getInstance ( ) . getDisplayName ( Calendar . MONTH ,
Calendar . LONG , Locale . ENGLISH )
+ " " + Calendar . getInstance ( ) . get ( Calendar . DAY_OF_MONTH )
+ ", " + Calendar . getInstance ( ) . get ( Calendar . YEAR ) + "," ) ;
} else if ( date . contains ( "Σήμερα" ) ) {
date = date . replace ( "Σήμερα στις" ,
Calendar . getInstance ( ) . getDisplayName ( Calendar . MONTH ,
Calendar . LONG , Locale . ENGLISH )
+ " " + Calendar . getInstance ( ) . get ( Calendar . DAY_OF_MONTH )
+ ", " + Calendar . getInstance ( ) . get ( Calendar . YEAR ) + "," ) ;
if ( date . contains ( "πμ" ) ) date = date . replace ( "πμ" , "am" ) ;
if ( date . contains ( "μμ" ) ) date = date . replace ( "μμ" , "pm" ) ;
}
try {
postDate = format . parse ( date ) ;
} catch ( ParseException e ) {
e . printStackTrace ( ) ;
}
}
}
if ( postsList . get ( quotePosition ) . getPostIndex ( ) ! = 0 ) {
if ( postDate ! = null ) {
return "[quote author=" + postsList . get ( quotePosition ) . getAuthor ( )
+ " link=topic=" + ThmmyPage . getTopicId ( loadedPageUrl ) + ".msg"
+ postsList . get ( quotePosition ) . getPostIndex ( )
+ "#msg" + postsList . get ( quotePosition ) . getPostIndex ( )
+ " date=" + postDate . getTime ( ) / 1000 + "]"
+ "\n" + postsList . get ( quotePosition ) . getContent ( )
+ "\n" + "[/quote]" + "\n\n" ;
}
}
return null ;
}
}
/ * *
/ * *