Browse Source

Merge branch 'test' into 'master'

RecyclerViewWithPicasso

Moved to RecyvlerView (from NestedScrollView) and to Picasso library for image downloading (from Volley).

See merge request !1
pull/24/head
Apostolos Fanakis 8 years ago
parent
commit
13fc604192
  1. 2
      app/build.gradle
  2. 1
      app/src/main/AndroidManifest.xml
  3. 452
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  4. 431
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  5. 16
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
  6. 10
      app/src/main/java/gr/thmmy/mthmmy/data/Post.java
  7. 10
      app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
  8. 57
      app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java
  9. 72
      app/src/main/java/gr/thmmy/mthmmy/utils/CircularNetworkImageView.java
  10. 66
      app/src/main/java/gr/thmmy/mthmmy/utils/ImageController.java
  11. 41
      app/src/main/java/gr/thmmy/mthmmy/utils/LruBitmapCache.java
  12. 0
      app/src/main/res/drawable/progress_bar_bg.xml
  13. 2
      app/src/main/res/layout/activity_login.xml
  14. 17
      app/src/main/res/layout/activity_topic.xml
  15. 11
      app/src/main/res/layout/activity_topic_post_row.xml
  16. 3
      app/src/main/res/values/dimens.xml
  17. 2
      app/src/main/res/values/strings.xml

2
app/build.gradle

@ -33,8 +33,8 @@ dependencies {
compile 'com.android.support:cardview-v7:25.0.1'
compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.squareup.okhttp3:okhttp:3.5.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'org.jsoup:jsoup:1.10.1'
compile 'com.android.volley:volley:1.0.0'
compile 'com.github.franmontiel:PersistentCookieJar:v1.0.0'
compile('com.mikepenz:materialdrawer:5.8.0@aar') {
transitive = true

1
app/src/main/AndroidManifest.xml

@ -6,7 +6,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:name=".utils.ImageController"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"

452
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java

@ -1,41 +1,27 @@
package gr.thmmy.mthmmy.activities.topic;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.Pair;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.toolbox.ImageLoader;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -49,8 +35,6 @@ import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.BaseActivity;
import gr.thmmy.mthmmy.activities.LoginActivity;
import gr.thmmy.mthmmy.data.Post;
import gr.thmmy.mthmmy.utils.CircularNetworkImageView;
import gr.thmmy.mthmmy.utils.ImageController;
import okhttp3.Request;
import okhttp3.Response;
@ -64,14 +48,13 @@ public class TopicActivity extends BaseActivity {
/* --Posts-- */
private List<Post> postsList;
private LinearLayout postsLinearLayout;
private static final int NO_POST_FOCUS = -1;
private int postFocus = NO_POST_FOCUS;
//Quote
private final ArrayList<Integer> toQuoteList = new ArrayList<>();
public static final ArrayList<Integer> toQuoteList = new ArrayList<>();
/* --Topic's pages-- */
private int thisPage = 1;
private String base_url = "";
public static String base_url = "";
private int numberOfPages = 1;
private final SparseArray<String> pagesUrls = new SparseArray<>();
//Page select
@ -83,21 +66,19 @@ public class TopicActivity extends BaseActivity {
private static final int SMALL_STEP = 1;
private static final int LARGE_STEP = 10;
private Integer pageRequestValue;
private ImageButton firstPage;
private ImageButton previousPage;
private ImageButton nextPage;
private ImageButton lastPage;
/* --Thumbnail-- */
private static final int THUMBNAIL_SIZE = 80;
private ImageLoader imageLoader = ImageController.getInstance().getImageLoader();
//Other variables
private ProgressBar progressBar;
@SuppressWarnings("unused")
private static final String TAG = "TopicActivity";
private String topicTitle;
private String parsedTitle;
private FloatingActionButton replyFAB;
private String parsedTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -107,7 +88,7 @@ public class TopicActivity extends BaseActivity {
Bundle extras = getIntent().getExtras();
topicTitle = getIntent().getExtras().getString("TOPIC_TITLE");
//Initialize toolbar
//Initialize toolbar, drawer and ProgressBar
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(topicTitle);
setSupportActionBar(toolbar);
@ -116,14 +97,8 @@ public class TopicActivity extends BaseActivity {
createDrawer();
//Variables initialization
postsLinearLayout = (LinearLayout) findViewById(R.id.posts_list);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
if (imageLoader == null)
imageLoader = ImageController.getInstance().getImageLoader();
postsList = new ArrayList<>();
@ -137,6 +112,7 @@ public class TopicActivity extends BaseActivity {
initDecrementButton(previousPage, SMALL_STEP);
initIncrementButton(nextPage, SMALL_STEP);
initIncrementButton(lastPage, LARGE_STEP);
firstPage.setEnabled(false);
previousPage.setEnabled(false);
nextPage.setEnabled(false);
@ -211,11 +187,10 @@ public class TopicActivity extends BaseActivity {
@Override
protected void onDestroy() { //When finished cancel whatever request can still be canceled
super.onDestroy();
ImageController.getInstance().cancelPendingRequests();
}
//--------------------------------------BOTTOM NAV BAR METHODS--------------------------------------
//--------------------------------------BOTTOM NAV BAR METHODS--------------------------------------
private void initIncrementButton(ImageButton increment, final int step) {
// Increment once for a click
increment.setOnClickListener(new View.OnClickListener() {
@ -318,8 +293,8 @@ public class TopicActivity extends BaseActivity {
private void changePage(int pageRequested) {
if (pageRequested != thisPage - 1) {
//Restart activity with new page
Pair<View, String> p1 = Pair.create((View)replyFAB, "fab");
Pair<View, String> p2 = Pair.create((View)toolbar, "toolbar");
Pair<View, String> p1 = Pair.create((View) replyFAB, "fab");
Pair<View, String> p2 = Pair.create((View) toolbar, "toolbar");
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(this, p1, p2);
@ -332,7 +307,7 @@ public class TopicActivity extends BaseActivity {
}
//------------------------------------BOTTOM NAV BAR METHODS END------------------------------------
//---------------------------------------TOPIC ASYNC TASK-------------------------------------------
//---------------------------------------TOPIC ASYNC TASK-------------------------------------------
public class TopicTask extends AsyncTask<String, Void, Boolean> {
//Class variables
private static final String TAG = "TopicTask"; //Separate tag for AsyncTask
@ -389,6 +364,14 @@ public class TopicActivity extends BaseActivity {
pageRequestValue = thisPage;
if (numberOfPages >= 1000)
pageIndicator.setTextSize(16);
firstPage.setEnabled(true);
previousPage.setEnabled(true);
nextPage.setEnabled(true);
lastPage.setEnabled(true);
if (topicTitle == null || Objects.equals(topicTitle, ""))
toolbar.setTitle(parsedTitle);
}
/* Parse method */
@ -396,11 +379,10 @@ public class TopicActivity extends BaseActivity {
//Find topic title if missing
if (topicTitle == null || Objects.equals(topicTitle, "")) {
parsedTitle = document.select("td[id=top_subject]").first().text();
if(parsedTitle.contains("Topic:")) {
if (parsedTitle.contains("Topic:")) {
parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Topic:") + 7
, parsedTitle.indexOf("(Read") - 2);
}
else{
} else {
parsedTitle = parsedTitle.substring(parsedTitle.indexOf("Θέμα:") + 6
, parsedTitle.indexOf("(Αναγνώστηκε") - 2);
Log.d(TAG, parsedTitle);
@ -432,298 +414,26 @@ public class TopicActivity extends BaseActivity {
* adds a card for each post to the ScrollView.
*/
private void populateLayout() {
//Enable reply button
replyFAB.setEnabled(true);
//Set topic title if not already present
if (topicTitle == null || Objects.equals(topicTitle, "")) {
topicTitle = parsedTitle;
if (toolbar != null) {
toolbar.setTitle(topicTitle);
}
}
//Now that parsing is complete and we have the url for every page enable page nav buttons
firstPage.setEnabled(true);
previousPage.setEnabled(true);
nextPage.setEnabled(true);
lastPage.setEnabled(true);
//Initialize an inflater
LayoutInflater inflater = (LayoutInflater) getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Create a card for each post
for (final Post currentPost : postsList) {
//Inflate a topic post row layout
View convertView = inflater.inflate(R.layout.activity_topic_post_row
, postsLinearLayout, false);
//Get an ImageLoader instance
if (imageLoader == null)
imageLoader = ImageController.getInstance().getImageLoader();
//Initialize layout's graphic elements
//Basic stuff
final CardView cardView = (CardView) convertView.findViewById(R.id.card_view);
final FrameLayout postDateAndNumberExp = (FrameLayout) convertView.findViewById(R.id.post_date_and_number_exp);
TextView postDate = (TextView) convertView.findViewById(R.id.post_date);
TextView postNum = (TextView) convertView.findViewById(R.id.post_number);
CircularNetworkImageView thumbnail = (CircularNetworkImageView) convertView.findViewById(R.id.thumbnail);
final TextView username = (TextView) convertView.findViewById(R.id.username);
final TextView subject = (TextView) convertView.findViewById(R.id.subject);
final WebView post = (WebView) convertView.findViewById(R.id.post);
final ImageButton quoteToggle = (ImageButton) convertView.findViewById(R.id.toggle_quote_button);
//User's extra
RelativeLayout header = (RelativeLayout) convertView.findViewById(R.id.header);
final LinearLayout userExtraInfo = (LinearLayout) convertView.findViewById(R.id.user_extra_info);
//Post's WebView parameters set
post.setClickable(true);
post.setWebViewClient(new LinkLauncher());
post.getSettings().setJavaScriptEnabled(true);
//TODO
post.getSettings().setPluginState(WebSettings.PluginState.ON_DEMAND);
//Avoiding errors about layout having 0 width/height
thumbnail.setMinimumWidth(1);
thumbnail.setMinimumHeight(1);
//Set thumbnail size
thumbnail.setMaxWidth(THUMBNAIL_SIZE);
thumbnail.setMaxHeight(THUMBNAIL_SIZE);
//Thumbnail image set
if (currentPost.getThumbnailUrl() != null
&& !Objects.equals(currentPost.getThumbnailUrl(), "")) {
thumbnail.setImageUrl(currentPost.getThumbnailUrl(), imageLoader);
}
//Username set
username.setText(currentPost.getAuthor());
//Post's submit date set
postDate.setText(currentPost.getPostDate());
//Post's index number set
if (currentPost.getPostNumber() != 0)
postNum.setText(getString(R.string.user_number_of_posts, currentPost.getPostNumber()));
//postNum.setText("#" + currentPost.getPostNumber());
else
postNum.setText("");
//Post's subject set
subject.setText(currentPost.getSubject());
//Post's text set
post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null);
quoteToggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (view.isSelected()) {
if (toQuoteList.contains(currentPost.getPostNumber())) {
toQuoteList.remove(toQuoteList.indexOf(currentPost.getPostNumber()));
view.setSelected(false);
} else
Log.i(TAG, "An error occurred while trying to exclude post from" +
"toQuoteList, post wasn't there!");
} else {
toQuoteList.add(currentPost.getPostNumber());
view.setSelected(true);
}
}
});
//If user is not deleted then we have more to do
if (!currentPost.isDeleted()) { //Set extra info
//Variables for Graphics
TextView g_specialRank, g_rank, g_gender, g_numberOfPosts, g_personalText;
LinearLayout g_stars_holder = (LinearLayout) convertView.findViewById(R.id.stars);
//Variables for content
String c_specialRank = currentPost.getSpecialRank(), c_rank = currentPost.getRank(), c_gender = currentPost.getGender(), c_numberOfPosts = currentPost.getNumberOfPosts(), c_personalText = currentPost.getPersonalText(), c_urlOfStars = currentPost.getUrlOfStars();
int c_numberOfStars = currentPost.getNumberOfStars();
if (!Objects.equals(c_specialRank, "") && c_specialRank != null) {
g_specialRank = (TextView) convertView.findViewById(R.id.special_rank);
g_specialRank.setText(c_specialRank);
g_specialRank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_rank, "") && c_rank != null) {
g_rank = (TextView) convertView.findViewById(R.id.rank);
g_rank.setText(c_rank);
g_rank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_gender, "") && c_gender != null) {
g_gender = (TextView) convertView.findViewById(R.id.gender);
g_gender.setText(c_gender);
g_gender.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_numberOfPosts, "") && c_numberOfPosts != null) {
g_numberOfPosts = (TextView) convertView.findViewById(R.id.number_of_posts);
g_numberOfPosts.setText(c_numberOfPosts);
g_numberOfPosts.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_personalText, "") && c_personalText != null) {
g_personalText = (TextView) convertView.findViewById(R.id.personal_text);
g_personalText.setText("\"" + c_personalText + "\"");
g_personalText.setVisibility(View.VISIBLE);
}
for (int i = 0; i < c_numberOfStars; ++i) {
CircularNetworkImageView star = new CircularNetworkImageView(this);
star.setImageUrl(c_urlOfStars, imageLoader);
//Remove spacing between stars...
//Don't know why this is happening in the first place
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins((int) getResources().getDimension(R.dimen.stars_margin)
, 0
, (int) getResources().getDimension(R.dimen.stars_margin)
, 0);
star.setLayoutParams(params);
g_stars_holder.addView(star, 0);
g_stars_holder.setVisibility(View.VISIBLE);
}
/* --Header expand/collapse functionality-- */
header.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(userExtraInfo);
}
});
//Clicking the expanded part of a header should collapse the extra info
userExtraInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(v);
}
});
/* --Header expand/collapse functionality end-- */
}
/* --Card expand/collapse functionality-- */
//Should expand/collapse when card is touched
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animatePostExtraInfoVisibility(postDateAndNumberExp
, username, subject
,ContextCompat.getColor(getApplicationContext(), R.color.black)
,ContextCompat.getColor(getApplicationContext(), R.color.secondary_text));
}
});
//Also when post is clicked
post.setOnTouchListener(new CustomTouchListener(post,cardView, quoteToggle));
/* --Card expand/collapse-like functionality end-- */
//Add view to the linear layout that holds all posts
postsLinearLayout.addView(convertView);
//Set post focus
if (postFocus != NO_POST_FOCUS) {
RecyclerView recyclerView = (RecyclerView)findViewById(R.id.topic_recycler_view);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
TopicAdapter adapter = new TopicAdapter(getApplicationContext(), postsList);
recyclerView.setAdapter(adapter);
//Set post focus
if (postFocus != NO_POST_FOCUS) {
for (int i = 0; i < postsList.size(); ++i) {
Post currentPost = postsList.get(i);
if (currentPost.getPostIndex() == postFocus) {
//TODO
}
}
}
}
//--------------------------------------POPULATE UI METHOD END--------------------------------------
//--------------------------------------CUSTOM WEBVIEW CLIENT---------------------------------------
/**
* This class is used to handle link clicks in WebViews.
* When link url is one that the app can handle internally, it does.
* Otherwise user is prompt to open the link in a browser.
*/
@SuppressWarnings("unchecked")
private class LinkLauncher extends WebViewClient { //Used to handle link clicks
//Older versions
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
final Uri uri = Uri.parse(url);
return handleUri(uri);
}
//Newest versions
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
final Uri uri = request.getUrl();
return handleUri(uri);
}
//Handle url clicks
private boolean handleUri(final Uri uri) {
//Method always returns true as we don't want any url to be loaded in WebViews
Log.i(TAG, "Uri = " + uri);
final String host = uri.getHost(); //Get requested url's host
final String uriString = uri.toString();
//Determine if you are going to pass the url to a
//host's application activity or load it in a browser.
if (Objects.equals(host, "www.thmmy.gr")) {
//This is my web site, so figure out what Activity should launch
if (uriString.contains("topic=")) { //This url points to a topic
//Is the link pointing to current topic?
if (Objects.equals(
uriString.substring(0, uriString.lastIndexOf(".")), base_url)) {
//Get uri's targeted message's index number
String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3);
if (msgIndexReq.contains("#"))
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf("#"));
else
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf(";"));
//Is this post already shown now? (is it in current page?)
for (Post post : postsList) {
if (post.getPostIndex() == Integer.parseInt(msgIndexReq)) {
//Don't restart Activity
//Just change post focus
//TODO
return true;
}
}
}
//Restart activity with new data
Pair<View, String> p1 = Pair.create((View) replyFAB, "fab");
Pair<View, String> p2 = Pair.create((View) toolbar, "toolbar");
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(TopicActivity.this, p1, p2);
Intent intent = getIntent();
intent.putExtra("TOPIC_URL", uri.toString());
intent.putExtra("TOPIC_TITLE", "");
startActivity(intent, options.toBundle());
finish();
}
return true;
}
//Otherwise, the link is not for a page on my site, so launch
//another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
return true;
}
}
//------------------------------------CUSTOM WEBVIEW CLIENT END-------------------------------------
//--------------------------------------POPULATE UI METHOD END--------------------------------------
//----------------------------------------REPETITIVE UPDATER----------------------------------------
@ -750,94 +460,4 @@ public class TopicActivity extends BaseActivity {
}
}
//--------------------------------------REPETITIVE UPDATER END--------------------------------------
//--------------------------------------CUSTOM TOUCH LISTENER---------------------------------------
/**
* This class is a gesture detector for WebViews.
* It handles post's clicks, long clicks and touch and drag.
*/
private class CustomTouchListener implements View.OnTouchListener {
//Long press handling
private final int LONG_PRESS_DURATION = 650;
private final Handler webViewLongClickHandler = new Handler();
private boolean wasLongClick = false;
private float downCoordinateX;
private float downCoordinateY;
private final float SCROLL_THRESHOLD = 7;
final private WebView post;
final private CardView cardView;
final private ImageButton quoteToggle;
//Other variables
final static int FINGER_RELEASED = 0;
final static int FINGER_TOUCHED = 1;
final static int FINGER_DRAGGING = 2;
final static int FINGER_UNDEFINED = 3;
private int fingerState = FINGER_RELEASED;
CustomTouchListener(WebView pPost, CardView pCard, ImageButton pQuoteToggle){
post = pPost;
cardView = pCard;
quoteToggle = pQuoteToggle;
}
final Runnable WebViewLongClick = new Runnable() {
public void run() {
wasLongClick = true;
quoteToggle.performClick();
}
};
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
downCoordinateX = motionEvent.getX();
downCoordinateY = motionEvent.getY();
if (fingerState == FINGER_RELEASED)
fingerState = FINGER_TOUCHED;
else
fingerState = FINGER_UNDEFINED;
//Start long click runnable
webViewLongClickHandler.postDelayed(WebViewLongClick
, LONG_PRESS_DURATION);
break;
case MotionEvent.ACTION_UP:
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
if (!wasLongClick && fingerState != FINGER_DRAGGING) {
//If this was a link don't expand the card
WebView.HitTestResult htResult = post.getHitTestResult();
if (htResult.getExtra() != null
&& htResult.getExtra() != null)
return false;
//Else expand/collapse card
cardView.performClick();
} else
wasLongClick = false;
fingerState = FINGER_RELEASED;
break;
case MotionEvent.ACTION_MOVE:
//If finger moved too much, cancel long click
if (((Math.abs(downCoordinateX - motionEvent.getX()) > SCROLL_THRESHOLD ||
Math.abs(downCoordinateY - motionEvent.getY()) > SCROLL_THRESHOLD))) {
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
fingerState = FINGER_DRAGGING;
} else fingerState = FINGER_UNDEFINED;
break;
default:
fingerState = FINGER_UNDEFINED;
}
return false;
}
}
//------------------------------------CUSTOM TOUCH LISTENER END-------------------------------------
}

431
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java

@ -0,0 +1,431 @@
package gr.thmmy.mthmmy.activities.topic;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.List;
import java.util.Objects;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.data.Post;
import gr.thmmy.mthmmy.utils.CircleTransform;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.base_url;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.toQuoteList;
class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
private static final String TAG = "TopicAdapter";
private static int THUMBNAIL_SIZE;
private final Context context;
private final List<Post> postsList;
class MyViewHolder extends RecyclerView.ViewHolder {
final CardView cardView;
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 TextView specialRank, rank, gender, numberOfPosts, personalText;
final LinearLayout stars_holder;
MyViewHolder(View view) {
super(view);
//Initialize layout's graphic elements
//Basic stuff
cardView = (CardView) view.findViewById(R.id.card_view);
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);
quoteToggle = (ImageButton) view.findViewById(R.id.toggle_quote_button);
//User's extra
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_holder = (LinearLayout) view.findViewById(R.id.stars);
}
/**
* Possible cleanup needed (like so:)
* https://stackoverflow.com/questions/24897441/picasso-how-to-cancel-all-image-requests-made-in-an-adapter
* TODO
*/
}
TopicAdapter(Context context, List<Post> postsList) {
this.context = context;
this.postsList = postsList;
THUMBNAIL_SIZE = (int) context.getResources().getDimension(R.dimen.thumbnail_size);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_topic_post_row, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
final Post currentPost = postsList.get(position);
//Post's WebView parameters set
holder.post.setClickable(true);
holder.post.setWebViewClient(new LinkLauncher());
holder.post.getSettings().setJavaScriptEnabled(true);
//Avoiding errors about layout having 0 width/height
holder.thumbnail.setMinimumWidth(1);
holder.thumbnail.setMinimumHeight(1);
//Set 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);
//Username set
holder.username.setText(currentPost.getAuthor());
//Post's submit date set
holder.postDate.setText(currentPost.getPostDate());
//Post's index number set
if (currentPost.getPostNumber() != 0)
holder.postNum.setText(context.getString(
R.string.user_number_of_posts, currentPost.getPostNumber()));
else
holder.postNum.setText("");
//Post's subject set
holder.subject.setText(currentPost.getSubject());
//Post's text set
holder.post.loadDataWithBaseURL("file:///android_asset/", currentPost.getContent(), "text/html", "UTF-8", null);
holder.quoteToggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (view.isSelected()) {
if (toQuoteList.contains(currentPost.getPostNumber())) {
toQuoteList.remove(toQuoteList.indexOf(currentPost.getPostNumber()));
view.setSelected(false);
} else
Log.i(TAG, "An error occurred while trying to exclude post from" +
"toQuoteList, post wasn't there!");
} else {
toQuoteList.add(currentPost.getPostNumber());
view.setSelected(true);
}
}
});
//If user is not deleted then we have more to do
if (!currentPost.isDeleted()) { //Set extra info
//Variables for content
String c_specialRank = currentPost.getSpecialRank(), c_rank = currentPost.getRank(), c_gender = currentPost.getGender(), c_numberOfPosts = currentPost.getNumberOfPosts(), c_personalText = currentPost.getPersonalText(), c_urlOfStars = currentPost.getUrlOfStars();
int c_numberOfStars = currentPost.getNumberOfStars();
if (!Objects.equals(c_specialRank, "") && c_specialRank != null) {
holder.specialRank.setText(c_specialRank);
holder.specialRank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_rank, "") && c_rank != null) {
holder.rank.setText(c_rank);
holder.rank.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_gender, "") && c_gender != null) {
holder.gender.setText(c_gender);
holder.gender.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_numberOfPosts, "") && c_numberOfPosts != null) {
holder.numberOfPosts.setText(c_numberOfPosts);
holder.numberOfPosts.setVisibility(View.VISIBLE);
}
if (!Objects.equals(c_personalText, "") && c_personalText != null) {
holder.personalText.setText("\"" + c_personalText + "\"");
holder.personalText.setVisibility(View.VISIBLE);
}
for (int i = 0; i < c_numberOfStars; ++i) {
ImageView star = new ImageView(context);
Picasso.with(context)
.load(c_urlOfStars)
.into(star);
//Remove spacing between stars...
//Don't know why this is happening in the first place
//TODO change layout? other solution?
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins((int) context.getResources().getDimension(R.dimen.stars_margin)
, 0
, (int) context.getResources().getDimension(R.dimen.stars_margin)
, 0);
star.setLayoutParams(params);
holder.stars_holder.addView(star, 0);
holder.stars_holder.setVisibility(View.VISIBLE);
}
/* --Header expand/collapse functionality-- */
holder.header.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(holder.userExtraInfo);
}
});
//Clicking the expanded part of a header should collapse the extra info
holder.userExtraInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animateUserExtraInfoVisibility(v);
}
});
/* --Header expand/collapse functionality end-- */
}
/* --Card expand/collapse functionality-- */
//Should expand/collapse when card is touched
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TopicAnimations.animatePostExtraInfoVisibility(holder.postDateAndNumberExp
, holder.username, holder.subject
, Color.parseColor("#000000")
, Color.parseColor("#757575"));
}
});
//Also when post is clicked
holder.post.setOnTouchListener(new CustomTouchListener(holder.post, holder.cardView, holder.quoteToggle));
}
@Override
public int getItemCount() {
return postsList.size();
}
//--------------------------------------CUSTOM TOUCH LISTENER---------------------------------------
/**
* This class is a gesture detector for WebViews.
* It handles post's clicks, long clicks and touch and drag.
*/
private class CustomTouchListener implements View.OnTouchListener {
//Long press handling
private final int LONG_PRESS_DURATION = 650;
private final Handler webViewLongClickHandler = new Handler();
private boolean wasLongClick = false;
private float downCoordinateX;
private float downCoordinateY;
private final float SCROLL_THRESHOLD = 7;
final private WebView post;
final private CardView cardView;
final private ImageButton quoteToggle;
//Other variables
final static int FINGER_RELEASED = 0;
final static int FINGER_TOUCHED = 1;
final static int FINGER_DRAGGING = 2;
final static int FINGER_UNDEFINED = 3;
private int fingerState = FINGER_RELEASED;
CustomTouchListener(WebView pPost, CardView pCard, ImageButton pQuoteToggle) {
post = pPost;
cardView = pCard;
quoteToggle = pQuoteToggle;
}
final Runnable WebViewLongClick = new Runnable() {
public void run() {
wasLongClick = true;
quoteToggle.performClick();
}
};
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
downCoordinateX = motionEvent.getX();
downCoordinateY = motionEvent.getY();
if (fingerState == FINGER_RELEASED)
fingerState = FINGER_TOUCHED;
else
fingerState = FINGER_UNDEFINED;
//Start long click runnable
webViewLongClickHandler.postDelayed(WebViewLongClick
, LONG_PRESS_DURATION);
break;
case MotionEvent.ACTION_UP:
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
if (!wasLongClick && fingerState != FINGER_DRAGGING) {
//If this was a link don't expand the card
WebView.HitTestResult htResult = post.getHitTestResult();
if (htResult.getExtra() != null
&& htResult.getExtra() != null)
return false;
//Else expand/collapse card
cardView.performClick();
} else
wasLongClick = false;
fingerState = FINGER_RELEASED;
break;
case MotionEvent.ACTION_MOVE:
//If finger moved too much, cancel long click
if (((Math.abs(downCoordinateX - motionEvent.getX()) > SCROLL_THRESHOLD ||
Math.abs(downCoordinateY - motionEvent.getY()) > SCROLL_THRESHOLD))) {
webViewLongClickHandler.removeCallbacks(WebViewLongClick);
fingerState = FINGER_DRAGGING;
} else fingerState = FINGER_UNDEFINED;
break;
default:
fingerState = FINGER_UNDEFINED;
}
return false;
}
}
//------------------------------------CUSTOM TOUCH LISTENER END-------------------------------------
//--------------------------------------CUSTOM WEBVIEW CLIENT---------------------------------------
/**
* This class is used to handle link clicks in WebViews.
* When link url is one that the app can handle internally, it does.
* Otherwise user is prompt to open the link in a browser.
*/
@SuppressWarnings("unchecked")
private class LinkLauncher extends WebViewClient { //Used to handle link clicks
//Older versions
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
final Uri uri = Uri.parse(url);
return handleUri(uri);
}
//Newest versions
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
final Uri uri = request.getUrl();
return handleUri(uri);
}
//Handle url clicks
private boolean handleUri(final Uri uri) {
//Method always returns true as we don't want any url to be loaded in WebViews
Log.i(TAG, "Uri clicked = " + uri);
final String host = uri.getHost(); //Get requested url's host
final String uriString = uri.toString();
//Determine if you are going to pass the url to a
//host's application activity or load it in a browser.
if (Objects.equals(host, "www.thmmy.gr")) {
//This is my web site, so figure out what Activity should launch
if (uriString.contains("topic=")) { //This url points to a topic
//Is the link pointing to current topic?
if (Objects.equals(
uriString.substring(0, uriString.lastIndexOf(".")), base_url)) {
//Get uri's targeted message's index number
String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3);
if (msgIndexReq.contains("#"))
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf("#"));
else
msgIndexReq = msgIndexReq.substring(0, msgIndexReq.indexOf(";"));
//Is this post already shown now? (is it in current page?)
for (Post post : postsList) {
if (post.getPostIndex() == Integer.parseInt(msgIndexReq)) {
//Don't restart Activity
//Just change post focus
//TODO
return true;
}
}
}
//Restart activity with new data
//TODO
}
return true;
}
//Otherwise, the link is not for a page on my site, so launch
//another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return true;
}
}
//------------------------------------CUSTOM WEBVIEW CLIENT END-------------------------------------
}

16
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java

@ -1,7 +1,5 @@
package gr.thmmy.mthmmy.activities.topic;
import android.util.Log;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
@ -28,6 +26,7 @@ class TopicParser {
private static String genderAltMale;
private static String genderAltFemale;
@SuppressWarnings("unused")
private static final String TAG = "TopicParser";
static int parseCurrentPageIndex(Document doc) {
@ -123,15 +122,18 @@ class TopicParser {
for (Element _noembed : noembedTag) {
embededVideosUrls.add(_noembed.text().substring(_noembed.text()
.indexOf("href=\"https://www.youtube.com/watch?") + 6
, _noembed.text().indexOf("target") - 6));
.indexOf("href=\"https://www.youtube.com/watch?") + 38
, _noembed.text().indexOf("target") - 2));
}
int tmp_counter = 0;
while (p_post.contains("<embed")) {
if (tmp_counter > embededVideosUrls.size())
break;
p_post = p_post.replace(
p_post.substring(p_post.indexOf("<embed"), p_post.indexOf("/noembed>") + 9)
, "<iframe width=\"200\" height=\"315\" src=\""
, "<iframe width=\"100%\" height=\"auto\" src=\""
+ "https://www.youtube.com/embed/"
+ embededVideosUrls.get(tmp_counter)
+ "\" frameborder=\"0\" allowfullscreen></iframe>"
);
@ -223,14 +225,14 @@ class TopicParser {
}
//Add new post in postsList, extended information needed
returnList.add(new Post(p_thumbnailUrl, p_userName, p_subject, p_post
, p_postIndex, p_postNum, p_postDate, false, p_rank
, p_postIndex, p_postNum, p_postDate, p_rank
, p_specialRank, p_gender, p_numberOfPosts, p_personalText
, p_urlOfStars, p_numberOfStars));
} else { //Deleted user
//Add new post in postsList, only standard information needed
returnList.add(new Post(p_thumbnailUrl, p_userName, p_subject
, p_post, p_postIndex, p_postNum, p_postDate, true));
, p_post, p_postIndex, p_postNum, p_postDate));
}
}
return returnList;

10
app/src/main/java/gr/thmmy/mthmmy/data/Post.java

@ -21,8 +21,8 @@ public class Post {
private int numberOfStars;
public Post(String thumbnailUrl, String author, String subject, String content
, int postIndex, int postNumber, String postDate, boolean isDeleted
, String rank, String special_rank, String gender, String numberOfPosts
, int postIndex, int postNumber, String postDate, String rank
, String special_rank, String gender, String numberOfPosts
, String personalText, String urlOfStars, int numberOfStars) {
this.thumbnailUrl = thumbnailUrl;
this.author = author;
@ -31,7 +31,7 @@ public class Post {
this.postIndex = postIndex;
this.postNumber = postNumber;
this.postDate = postDate;
this.isDeleted = isDeleted;
this.isDeleted = false;
this.rank = rank;
this.specialRank = special_rank;
this.gender = gender;
@ -42,7 +42,7 @@ public class Post {
}
public Post(String thumbnailUrl, String author, String subject, String content
, int postIndex, int postNumber, String postDate, boolean isDeleted) {
, int postIndex, int postNumber, String postDate) {
this.thumbnailUrl = thumbnailUrl;
this.author = author;
this.subject = subject;
@ -50,7 +50,7 @@ public class Post {
this.postIndex = postIndex;
this.postNumber = postNumber;
this.postDate = postDate;
this.isDeleted = isDeleted;
this.isDeleted = true;
rank = "Rank";
specialRank = "Special rank";
gender = "Gender";

10
app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java

@ -4,8 +4,6 @@ import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Environment;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
@ -23,8 +21,6 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import gr.thmmy.mthmmy.utils.ImageController;
import mthmmy.utils.Report;
import okhttp3.Cookie;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
@ -308,7 +304,7 @@ public class SessionManager
return null;
}
private File getUserAvatar(String image_url, final String package_name, final String image_name) {
/*private File getUserAvatar(String image_url, final String package_name, final String image_name) {
final File[] returnImage = {null};
ImageController.getInstance().getImageLoader().get(image_url, new ImageLoader.ImageListener() {
@ -342,7 +338,7 @@ public class SessionManager
}
});
return returnImage[0];
}
}*/
/** Create a File for saving an image or video */
private File getOutputMediaFile(String packageName, String imageName){
@ -371,4 +367,4 @@ public class SessionManager
//----------------------------------OTHER FUNCTIONS END-----------------------------------------
}
}

57
app/src/main/java/gr/thmmy/mthmmy/utils/CircleTransform.java

@ -0,0 +1,57 @@
package gr.thmmy.mthmmy.utils;
/*
* Copyright 2014 Julian Shen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.squareup.picasso.Transformation;
public class CircleTransform implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circle";
}
}

72
app/src/main/java/gr/thmmy/mthmmy/utils/CircularNetworkImageView.java

@ -1,72 +0,0 @@
package gr.thmmy.mthmmy.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import com.android.volley.toolbox.NetworkImageView;
public class CircularNetworkImageView extends NetworkImageView {
private static final int THUMBNAIL_SIZE = 80;
private Context mContext;
public CircularNetworkImageView(Context context) {
super(context);
mContext = context;
}
public CircularNetworkImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
mContext = context;
}
public CircularNetworkImageView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
mContext = context;
}
@Override
public void setImageBitmap(Bitmap bm) {
if (bm == null) return;
setImageDrawable(new BitmapDrawable(mContext.getResources(),
getCircularBitmap(bm)));
}
/**
* Creates a circular bitmap and uses whichever dimension is smaller to determine the width
* <br/>Also constrains the circle to the leftmost part of the image
*/
private Bitmap getCircularBitmap(Bitmap bitmap) {
bitmap = Bitmap.createScaledBitmap(bitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
int size = bitmap.getWidth();
if (bitmap.getWidth() > bitmap.getHeight())
size = bitmap.getHeight();
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, size, size);
final RectF rectF = new RectF(rect);
final float roundPx = size / 2;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}

66
app/src/main/java/gr/thmmy/mthmmy/utils/ImageController.java

@ -1,66 +0,0 @@
package gr.thmmy.mthmmy.utils;
import android.app.Application;
import android.text.TextUtils;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
public class ImageController extends Application {
private static final String TAG = ImageController.class.getSimpleName();
private static ImageController mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
public static synchronized ImageController getInstance() {
return mInstance;
}
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
private RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public ImageLoader getImageLoader() {
getRequestQueue();
if (mImageLoader == null) {
mImageLoader = new ImageLoader(this.mRequestQueue,
new LruBitmapCache());
}
return this.mImageLoader;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
getRequestQueue().add(req);
}
public void cancelPendingRequests() {
mRequestQueue.cancelAll(new RequestQueue.RequestFilter() {
@Override
public boolean apply(Request<?> request) {
return true;
}
});
}
}

41
app/src/main/java/gr/thmmy/mthmmy/utils/LruBitmapCache.java

@ -1,41 +0,0 @@
package gr.thmmy.mthmmy.utils;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import com.android.volley.toolbox.ImageLoader.ImageCache;
class LruBitmapCache extends LruCache<String, Bitmap> implements
ImageCache {
private static final int CACHE_SIZE_DIVIDER = 8;
LruBitmapCache() {
this(getDefaultLruCacheSize());
}
private LruBitmapCache(int sizeInKiloBytes) {
super(sizeInKiloBytes);
}
private static int getDefaultLruCacheSize() {
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / CACHE_SIZE_DIVIDER;
return cacheSize;
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
@Override
public Bitmap getBitmap(String url) {
return get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}

0
app/src/main/res/drawable/login_progress_bar_bg.xml → app/src/main/res/drawable/progress_bar_bg.xml

2
app/src/main/res/layout/activity_login.xml

@ -114,7 +114,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/login_progress_bar_bg"/>
android:background="@drawable/progress_bar_bg"/>
<TextView
android:layout_width="wrap_content"

17
app/src/main/res/layout/activity_topic.xml

@ -27,7 +27,8 @@
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
<android.support.v7.widget.RecyclerView
android:id="@+id/topic_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|start"
@ -36,18 +37,7 @@
android:background="@color/background"
android:scrollbars="none"
tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity">
<LinearLayout
android:id="@+id/posts_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingBottom="4dp"
android:paddingTop="4dp">
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.v7.widget.RecyclerView>
<LinearLayout
android:id="@+id/bottom_navigation_bar"
@ -110,6 +100,7 @@
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:background="@drawable/progress_bar_bg"
android:visibility="invisible"/>
<android.support.design.widget.FloatingActionButton

11
app/src/main/res/layout/activity_topic_post_row.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@ -82,15 +81,16 @@
android:layout_centerVertical="true"
android:layout_marginEnd="16dp">
<gr.thmmy.mthmmy.utils.CircularNetworkImageView
<ImageView
android:id="@+id/thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:src="@drawable/ic_default_user_thumbnail"
android:contentDescription="@string/thumbnail"
android:maxHeight="@dimen/thumbnail_size"
android:maxWidth="@dimen/thumbnail_size"/>
android:maxWidth="@dimen/thumbnail_size"
android:src="@drawable/ic_default_user_thumbnail"/>
</FrameLayout>
<TextView
@ -123,7 +123,8 @@
android:layout_height="@dimen/quote_button"
android:layout_marginEnd="9dp"
android:layout_marginTop="9dp"
android:background="@drawable/ic_toggle_quote_bg"/>
android:background="@drawable/ic_toggle_quote_bg"
android:contentDescription="@string/quote"/>
</LinearLayout>
<LinearLayout

3
app/src/main/res/values/dimens.xml

@ -3,8 +3,7 @@
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="appbar_padding_top">8dp</dimen>
<dimen name="thumbnail_size">80dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="thumbnail_size">44dp</dimen>
<dimen name="stars_margin">-15dp</dimen>
<dimen name="quote_button">36dp</dimen>
</resources>

2
app/src/main/res/values/strings.xml

@ -17,6 +17,8 @@
<string name="username">Username should be here&#8230;</string>
<string name="subject">Subject should be here&#8230;</string>
<string name="post">Post should be here&#8230;</string>
<string name="thumbnail">Thumbnail should be here&#8230;</string>
<string name="quote">Quote button should be here&#8230;</string>
<string name="text_first">first</string>
<string name="text_previous">previous</string>
<string name="text_page">Page</string>

Loading…
Cancel
Save