mirror of https://github.com/ThmmyNoLife/mTHMMY
Browse Source
RecyclerViewWithPicasso Moved to RecyvlerView (from NestedScrollView) and to Picasso library for image downloading (from Volley). See merge request !1pull/24/head
Apostolos Fanakis
8 years ago
17 changed files with 556 additions and 637 deletions
@ -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-------------------------------------
|
||||
|
|
||||
|
} |
@ -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"; |
||||
|
} |
||||
|
} |
@ -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; |
|
||||
} |
|
||||
} |
|
@ -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; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
@ -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); |
|
||||
} |
|
||||
} |
|
Loading…
Reference in new issue