added authorization to image loader

fixed direct message media preview
This commit is contained in:
Mariotaku Lee 2015-05-10 14:28:42 +08:00
parent 5ccdb8fd8d
commit 12e4be008c
19 changed files with 182 additions and 139 deletions

View File

@ -110,7 +110,7 @@ public class RestAPIFactory {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
final RestMethodInfo methodInfo = RestMethodInfo.get(method, args);
final RestRequest restRequest = requestFactory.create(endpoint, methodInfo, authorization);
final RestRequest restRequest = requestFactory.create(endpoint, methodInfo.toRequestInfo(), authorization);
final Class<?>[] parameterTypes = method.getParameterTypes();
RestResponse response = null;
try {

View File

@ -333,4 +333,67 @@ public final class RestMethodInfo {
}
return null;
}
public RequestInfo toRequestInfo() {
return new RequestInfo(getMethod().value(), getPath(), getQueries(), getForms(),
getHeaders(), getParts(), getExtras(), getBody());
}
public static final class RequestInfo {
private String method;
private String path;
private List<Pair<String, String>> queries, forms, headers;
private List<Pair<String, TypedData>> parts;
private Map<String, Object> extras;
private TypedData body;
public RequestInfo(String method, String path, List<Pair<String, String>> queries,
List<Pair<String, String>> forms, List<Pair<String, String>> headers,
List<Pair<String, TypedData>> parts, Map<String, Object> extras, TypedData body) {
this.method = method;
this.path = path;
this.queries = queries;
this.forms = forms;
this.headers = headers;
this.parts = parts;
this.extras = extras;
this.body = body;
}
public List<Pair<String, String>> getQueries() {
return queries;
}
public List<Pair<String, String>> getForms() {
return forms;
}
public List<Pair<String, String>> getHeaders() {
return headers;
}
public List<Pair<String, TypedData>> getParts() {
return parts;
}
public Map<String, Object> getExtras() {
return extras;
}
public TypedData getBody() {
return body;
}
public String getPath() {
return path;
}
public String getMethod() {
return method;
}
}
}

View File

@ -25,7 +25,7 @@ import org.mariotaku.simplerestapi.RestMethodInfo;
* Created by mariotaku on 15/2/4.
*/
public interface Authorization {
String getHeader(Endpoint endpoint, RestMethodInfo info);
String getHeader(Endpoint endpoint, RestMethodInfo.RequestInfo info);
boolean hasAuthorization();
}

View File

@ -23,7 +23,7 @@ public class Endpoint {
this.url = url;
}
public static String constructUrl(String endpoint, RestMethodInfo requestInfo) {
public static String constructUrl(String endpoint, RestMethodInfo.RequestInfo requestInfo) {
return constructUrl(endpoint, requestInfo.getPath(), requestInfo.getQueries());
}

View File

@ -4,7 +4,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Pair;
import org.mariotaku.simplerestapi.RestMethod;
import org.mariotaku.simplerestapi.RestMethodInfo;
import org.mariotaku.simplerestapi.http.mime.TypedData;
@ -101,22 +100,21 @@ public final class RestRequest {
}
public interface Factory {
RestRequest create(@NonNull Endpoint endpoint, @NonNull RestMethodInfo info, @Nullable Authorization authorization);
RestRequest create(@NonNull Endpoint endpoint, @NonNull RestMethodInfo.RequestInfo info, @Nullable Authorization authorization);
}
public static final class DefaultFactory implements Factory {
@Override
public RestRequest create(@NonNull Endpoint endpoint, @NonNull RestMethodInfo methodInfo, @Nullable Authorization authorization) {
final RestMethod restMethod = methodInfo.getMethod();
final String url = Endpoint.constructUrl(endpoint.getUrl(), methodInfo);
final ArrayList<Pair<String, String>> headers = new ArrayList<>(methodInfo.getHeaders());
public RestRequest create(@NonNull Endpoint endpoint, @NonNull RestMethodInfo.RequestInfo requestInfo, @Nullable Authorization authorization) {
final String url = Endpoint.constructUrl(endpoint.getUrl(), requestInfo);
final ArrayList<Pair<String, String>> headers = new ArrayList<>(requestInfo.getHeaders());
if (authorization != null && authorization.hasAuthorization()) {
headers.add(Pair.create("Authorization", authorization.getHeader(endpoint, methodInfo)));
headers.add(Pair.create("Authorization", authorization.getHeader(endpoint, requestInfo)));
}
return new RestRequest(restMethod.value(), url, headers, methodInfo.getBody(), null);
return new RestRequest(requestInfo.getMethod(), url, headers, requestInfo.getBody(), null);
}
}
}

View File

@ -39,7 +39,7 @@ public final class BasicAuthorization implements Authorization {
}
@Override
public String getHeader(Endpoint endpoint, RestMethodInfo info) {
public String getHeader(Endpoint endpoint, RestMethodInfo.RequestInfo info) {
if (!hasAuthorization()) return null;
return "Basic " + Base64.encodeToString((user + ":" + password).getBytes(), Base64.NO_WRAP);
}

View File

@ -31,7 +31,7 @@ import org.mariotaku.simplerestapi.http.Endpoint;
public final class EmptyAuthorization implements Authorization {
@Override
public String getHeader(Endpoint endpoint, RestMethodInfo info) {
public String getHeader(Endpoint endpoint, RestMethodInfo.RequestInfo info) {
return null;
}

View File

@ -22,7 +22,6 @@ package org.mariotaku.twidere.api.twitter.auth;
import android.util.Base64;
import android.util.Pair;
import org.mariotaku.simplerestapi.RestMethod;
import org.mariotaku.simplerestapi.RestMethodInfo;
import org.mariotaku.simplerestapi.Utils;
import org.mariotaku.simplerestapi.http.Authorization;
@ -44,7 +43,7 @@ import javax.crypto.spec.SecretKeySpec;
/**
* Created by mariotaku on 15/2/4.
*/
public class OAuthAuthorization implements Authorization,OAuthSupport {
public class OAuthAuthorization implements Authorization, OAuthSupport {
private static final String DEFAULT_ENCODING = "UTF-8";
private static final String OAUTH_SIGNATURE_METHOD = "HMAC-SHA1";
@ -77,7 +76,7 @@ public class OAuthAuthorization implements Authorization,OAuthSupport {
return oauthToken;
}
private String generateOAuthSignature(RestMethod method, String url,
private String generateOAuthSignature(String method, String url,
String oauthNonce, long timestamp,
String oauthToken, String oauthTokenSecret,
List<Pair<String, String>> queries,
@ -120,7 +119,7 @@ public class OAuthAuthorization implements Authorization,OAuthSupport {
SecretKeySpec secret = new SecretKeySpec(signingKey.getBytes(), mac.getAlgorithm());
mac.init(secret);
String urlNoQuery = url.indexOf('?') != -1 ? url.substring(0, url.indexOf('?')) : url;
final String baseString = encode(method.value()) + '&' + encode(urlNoQuery) + '&' + encode(paramBuilder.toString());
final String baseString = encode(method) + '&' + encode(urlNoQuery) + '&' + encode(paramBuilder.toString());
final byte[] signature = mac.doFinal(baseString.getBytes(DEFAULT_ENCODING));
return Base64.encodeToString(signature, Base64.NO_WRAP);
} catch (NoSuchAlgorithmException e) {
@ -131,10 +130,11 @@ public class OAuthAuthorization implements Authorization,OAuthSupport {
}
@Override
public String getHeader(Endpoint endpoint, RestMethodInfo request) {
if (!(endpoint instanceof OAuthEndpoint)) throw new IllegalArgumentException("OAuthEndpoint required");
public String getHeader(Endpoint endpoint, RestMethodInfo.RequestInfo request) {
if (!(endpoint instanceof OAuthEndpoint))
throw new IllegalArgumentException("OAuthEndpoint required");
final OAuthEndpoint oauthEndpoint = (OAuthEndpoint) endpoint;
final RestMethod method = request.getMethod();
final String method = request.getMethod();
final String url = Endpoint.constructUrl(oauthEndpoint.getSignUrl(), request);
final String oauthNonce = generateOAuthNonce();
final long timestamp = System.currentTimeMillis() / 1000;

View File

@ -1,50 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.api.twitter.auth;
import org.mariotaku.simplerestapi.RestMethodInfo;
import org.mariotaku.simplerestapi.http.Authorization;
import org.mariotaku.simplerestapi.http.Endpoint;
/**
* Created by mariotaku on 15/4/19.
*/
public final class XAuthAuthorization implements Authorization, OAuthSupport {
@Override
public String getHeader(Endpoint endpoint, RestMethodInfo info) {
return null;
}
@Override
public boolean hasAuthorization() {
return false;
}
@Override
public String getConsumerKey() {
return null;
}
@Override
public String getConsumerSecret() {
return null;
}
}

View File

@ -233,13 +233,7 @@ public interface SharedPreferenceConstants {
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
String KEY_LINK_TO_QUOTED_TWEET = "link_to_quoted_tweet";
@Preference(type = BOOLEAN)
String KEY_BACKGROUND_TOAST_NOTIFICATION = "background_toast_notification";
@Preference(type = STRING)
String KEY_COMPOSE_QUIT_ACTION = "compose_quit_action";
@Preference(type = BOOLEAN)
String KEY_NO_CLOSE_AFTER_TWEET_SENT = "no_close_after_tweet_sent";
@Preference(type = BOOLEAN)
String KEY_FAST_IMAGE_LOADING = "fast_image_loading";
@Preference(type = STRING, hasDefault = false)
String KEY_API_URL_FORMAT = "api_url_format";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)

View File

@ -97,6 +97,10 @@ public class MessageConversationAdapter extends Adapter<ViewHolder> implements C
return mMediaLoader;
}
public MediaLoadingHandler getMediaLoadingHandler() {
return mMediaLoadingHandler;
}
public TwidereLinkify getLinkify() {
return mLinkify;
}

View File

@ -291,7 +291,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
stopService(new Intent(this, RefreshService.class));
startRefreshServiceIfNeeded(this);
} else if (KEY_ENABLE_PROXY.equals(key) || KEY_CONNECTION_TIMEOUT.equals(key) || KEY_PROXY_HOST.equals(key)
|| KEY_PROXY_PORT.equals(key) || KEY_FAST_IMAGE_LOADING.equals(key)) {
|| KEY_PROXY_PORT.equals(key)) {
reloadConnectivitySettings();
} else if (KEY_USAGE_STATISTICS.equals(key)) {
stopService(new Intent(this, UCDService.class));

View File

@ -28,6 +28,10 @@ import android.util.Pair;
import com.bluelinelabs.logansquare.LoganSquare;
import org.mariotaku.jsonserializer.JSONFileIO;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.model.ParcelableActivity;
import org.mariotaku.twidere.util.TwitterAPIUtils;
import org.mariotaku.twidere.util.Utils;
@ -42,12 +46,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import static org.mariotaku.twidere.util.TwitterAPIUtils.getTwitterInstance;
import static org.mariotaku.twidere.util.Utils.truncateActivities;
public abstract class Twitter4JActivitiesLoader extends ParcelableActivitiesLoader {
@ -153,8 +151,10 @@ public abstract class Twitter4JActivitiesLoader extends ParcelableActivitiesLoad
private List<ParcelableActivity> getCachedData(final File file) {
if (file == null) return null;
FileInputStream is = null;
try {
return LoganSquare.parseList(new FileInputStream(file), ParcelableActivity.class);
is = new FileInputStream(file);
return LoganSquare.parseList(is, ParcelableActivity.class);
} catch (final IOException e) {
if (Utils.isDebugBuild()) {
Log.w(LOGTAG, e);
@ -164,6 +164,8 @@ public abstract class Twitter4JActivitiesLoader extends ParcelableActivitiesLoad
throw e;
}
Log.e(LOGTAG, "Error unserializing data", e);
} finally {
Utils.closeSilently(is);
}
return null;
}

View File

@ -100,6 +100,10 @@ public class MediaLoaderWrapper implements Constants {
public void displayPreviewImageWithCredentials(final ImageView view, final String url, final long accountId,
final MediaLoadingHandler loadingHandler) {
if (accountId <= 0) {
displayPreviewImage(view, url, loadingHandler);
return;
}
final DisplayImageOptions.Builder b = new DisplayImageOptions.Builder();
b.cloneFrom(mImageDisplayOptions);
b.extraForDownloader(new AccountExtra(accountId));

View File

@ -160,8 +160,8 @@ public class TwitterAPIUtils implements TwidereConstants {
factory.setRequestFactory(new RestRequest.Factory() {
@Override
public RestRequest create(@NonNull Endpoint endpoint, @NonNull RestMethodInfo info, @Nullable Authorization authorization) {
final RestMethod restMethod = info.getMethod();
public RestRequest create(@NonNull Endpoint endpoint, @NonNull RestMethodInfo.RequestInfo info, @Nullable Authorization authorization) {
final String restMethod = info.getMethod();
final String url = Endpoint.constructUrl(endpoint.getUrl(), info);
final ArrayList<Pair<String, String>> headers = new ArrayList<>(info.getHeaders());
@ -169,7 +169,7 @@ public class TwitterAPIUtils implements TwidereConstants {
headers.add(Pair.create("Authorization", authorization.getHeader(endpoint, info)));
}
headers.add(Pair.create("User-Agent", userAgent));
return new RestRequest(restMethod.value(), url, headers, info.getBody(), null);
return new RestRequest(restMethod, url, headers, info.getBody(), null);
}
});
factory.setExceptionFactory(new RestAPIFactory.ExceptionFactory() {

View File

@ -32,7 +32,9 @@ import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.squareup.pollexor.Thumbor;
import com.squareup.pollexor.ThumborUrlBuilder;
import org.mariotaku.simplerestapi.RestMethodInfo;
import org.mariotaku.simplerestapi.http.Authorization;
import org.mariotaku.simplerestapi.http.Endpoint;
import org.mariotaku.simplerestapi.http.RestHttpClient;
import org.mariotaku.simplerestapi.http.RestRequest;
import org.mariotaku.simplerestapi.http.RestResponse;
@ -40,6 +42,8 @@ import org.mariotaku.simplerestapi.http.mime.TypedData;
import org.mariotaku.simplerestapi.method.GET;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.auth.OAuthAuthorization;
import org.mariotaku.twidere.api.twitter.auth.OAuthEndpoint;
import org.mariotaku.twidere.constant.SharedPreferenceConstants;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableCredentials;
@ -50,14 +54,13 @@ import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.util.TwitterAPIUtils;
import org.mariotaku.twidere.util.Utils;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.mariotaku.twidere.api.twitter.TwitterException;
public class TwidereImageDownloader extends BaseImageDownloader implements Constants {
private final Context mContext;
@ -65,7 +68,6 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
private final boolean mUseThumbor;
private Thumbor mThumbor;
private RestHttpClient mClient;
private boolean mFastImageLoading;
private final boolean mFullImage;
private final String mTwitterProfileImageSize;
@ -83,7 +85,6 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
public void reloadConnectivitySettings() {
mClient = TwitterAPIUtils.getDefaultHttpClient(mContext);
mFastImageLoading = mPreferences.getBoolean(KEY_FAST_IMAGE_LOADING);
if (mUseThumbor && mPreferences.getBoolean(KEY_THUMBOR_ENABLED)) {
final String address = mPreferences.getString(KEY_THUMBOR_ADDRESS, null);
final String securityKey = mPreferences.getString(KEY_THUMBOR_SECURITY_KEY, null);
@ -104,8 +105,7 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
@Override
protected InputStream getStreamFromNetwork(final String uriString, final Object extras) throws IOException {
if (uriString == null) return null;
final ParcelableMedia media = MediaPreviewUtils.getAllAvailableImage(uriString, mFullImage, mFullImage
|| !mFastImageLoading ? mClient : null);
final ParcelableMedia media = MediaPreviewUtils.getAllAvailableImage(uriString, mFullImage, mClient);
try {
final String mediaUrl = media != null ? media.media_url : uriString;
if (isTwitterProfileImage(uriString)) {
@ -113,24 +113,20 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
return getStreamFromNetworkInternal(replaced, extras);
} else
return getStreamFromNetworkInternal(mediaUrl, extras);
} catch (final TwitterException e) {
final int statusCode = e.getStatusCode();
if (statusCode != -1 && isTwitterProfileImage(uriString) && !uriString.contains("_normal.")) {
try {
return getStreamFromNetworkInternal(Utils.getNormalTwitterProfileImage(uriString), extras);
} catch (final TwitterException ignored) {
}
} catch (final FileNotFoundException e) {
if (isTwitterProfileImage(uriString) && !uriString.contains("_normal.")) {
return getStreamFromNetworkInternal(Utils.getNormalTwitterProfileImage(uriString), extras);
}
throw new IOException(String.format(Locale.US, "Error downloading image %s, error code: %d", uriString,
statusCode));
throw new IOException(String.format(Locale.US, "Error downloading image %s", uriString));
}
}
private String getReplacedUri(@NonNull final Uri uri, final String apiUrlFormat) {
if (apiUrlFormat == null) return uri.toString();
private Uri getReplacedUri(@NonNull final Uri uri, final String apiUrlFormat) {
if (apiUrlFormat == null) return uri;
if (isTwitterUri(uri)) {
final StringBuilder sb = new StringBuilder();
final String domain = uri.getHost().replaceAll("\\.?twitter.com", "");
final String host = uri.getHost();
final String domain = host.substring(0, host.lastIndexOf(".twitter.com"));
final String path = uri.getPath();
sb.append(Utils.getApiUrl(apiUrlFormat, domain, path));
final String query = uri.getQuery();
@ -143,13 +139,12 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
sb.append("#");
sb.append(fragment);
}
return sb.toString();
return Uri.parse(sb.toString());
}
return uri.toString();
return uri;
}
private ContentLengthInputStream getStreamFromNetworkInternal(final String uriString, final Object extras)
throws IOException, TwitterException {
private ContentLengthInputStream getStreamFromNetworkInternal(final String uriString, final Object extras) throws IOException {
final Uri uri = Uri.parse(uriString);
final Authorization auth;
final ParcelableCredentials account;
@ -161,35 +156,63 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
account = null;
auth = null;
}
String modifiedUri = getReplacedUri(uri, account != null ? account.api_url_format : null);
if (mThumbor != null) {
modifiedUri = mThumbor.buildImage(modifiedUri).filter(ThumborUrlBuilder.quality(85)).toUrl();
}
Uri modifiedUri = getReplacedUri(uri, account != null ? account.api_url_format : null);
final List<Pair<String, String>> additionalHeaders = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
additionalHeaders.add(Pair.create("Accept", "image/webp, */*"));
}
if (auth!= null && auth.hasAuthorization()) {
// additionalHeaders.add(Pair.create("Authorization", auth.getHeader()));
final String method = GET.METHOD;
if (auth != null && auth.hasAuthorization()) {
final Endpoint endpoint;
if (auth instanceof OAuthAuthorization) {
endpoint = new OAuthEndpoint(getEndpoint(modifiedUri), getEndpoint(uri));
} else {
endpoint = new Endpoint(getEndpoint(modifiedUri));
}
final List<Pair<String, String>> queries = new ArrayList<>();
for (String name : uri.getQueryParameterNames()) {
for (String value : uri.getQueryParameters(name)) {
queries.add(Pair.create(name, value));
}
}
final RestMethodInfo.RequestInfo info = new RestMethodInfo.RequestInfo(method, uri.getPath(), queries, null, additionalHeaders, null, null, null);
additionalHeaders.add(Pair.create("Authorization", auth.getHeader(endpoint, info)));
}
final RestResponse resp = mClient.execute(new RestRequest.Builder().method(GET.METHOD).url(modifiedUri).headers(additionalHeaders).build());
final String requestUri;
if (mThumbor != null) {
requestUri = mThumbor.buildImage(modifiedUri.toString()).filter(ThumborUrlBuilder.quality(85)).toUrl();
} else {
requestUri = modifiedUri.toString();
}
final RestResponse resp = mClient.execute(new RestRequest.Builder().method(method).url(requestUri).headers(additionalHeaders).build());
final TypedData body = resp.getBody();
return new ContentLengthInputStream(body.stream(), (int) body.length());
}
private String getEndpoint(Uri uri) {
final StringBuilder sb = new StringBuilder();
sb.append(uri.getScheme());
sb.append("://");
sb.append(uri.getHost());
if (uri.getPort() != -1) {
sb.append(':');
sb.append(uri.getPort());
}
sb.append("/");
return sb.toString();
}
private boolean isTwitterAuthRequired(final Uri uri) {
if (uri == null) return false;
return "ton.twitter.com".equalsIgnoreCase(uri.getHost());
return uri != null && "ton.twitter.com".equalsIgnoreCase(uri.getHost());
}
private boolean isTwitterProfileImage(final String uriString) {
if (TextUtils.isEmpty(uriString)) return false;
return TwidereLinkify.PATTERN_TWITTER_PROFILE_IMAGES.matcher(uriString).matches();
return !TextUtils.isEmpty(uriString) && TwidereLinkify.PATTERN_TWITTER_PROFILE_IMAGES.matcher(uriString).matches();
}
private boolean isTwitterUri(final Uri uri) {
if (uri == null) return false;
return "ton.twitter.com".equalsIgnoreCase(uri.getHost());
return uri != null && "ton.twitter.com".equalsIgnoreCase(uri.getHost());
}
}

View File

@ -90,6 +90,14 @@ public class CardMediaContainer extends ViewGroup implements Constants {
final long accountId,
final OnMediaClickListener mediaClickListener,
final MediaLoadingHandler loadingHandler) {
displayMedia(mediaArray, loader, accountId, false, mediaClickListener, loadingHandler);
}
public void displayMedia(@Nullable final ParcelableMedia[] mediaArray,
@NonNull final MediaLoaderWrapper loader,
final long accountId, boolean withCredentials,
final OnMediaClickListener mediaClickListener,
final MediaLoadingHandler loadingHandler) {
if (mediaArray == null || mMediaPreviewStyle == VALUE_MEDIA_PREVIEW_STYLE_CODE_NONE) {
for (int i = 0, j = getChildCount(); i < j; i++) {
final View child = getChildAt(i);
@ -115,11 +123,11 @@ public class CardMediaContainer extends ViewGroup implements Constants {
}
if (i < k) {
final ParcelableMedia media = mediaArray[i];
if (TextUtils.isEmpty(media.preview_url)) {
// For backward compatibility
loader.displayPreviewImage(imageView, media.media_url, loadingHandler);
final String url = TextUtils.isEmpty(media.preview_url) ? media.media_url : media.preview_url;
if (withCredentials) {
loader.displayPreviewImageWithCredentials(imageView, url, accountId, loadingHandler);
} else {
loader.displayPreviewImage(imageView, media.preview_url, loadingHandler);
loader.displayPreviewImage(imageView, url, loadingHandler);
}
child.setTag(media);
child.setVisibility(VISIBLE);

View File

@ -69,6 +69,7 @@ public class MessageViewHolder extends ViewHolder implements OnMediaClickListene
text = (TextView) itemView.findViewById(R.id.text);
time = (TextView) itemView.findViewById(R.id.time);
mediaContainer = (CardMediaContainer) itemView.findViewById(R.id.media_preview_container);
mediaContainer.setStyle(adapter.getMediaPreviewStyle());
}
public void displayMessage(Cursor cursor, CursorIndices indices) {
@ -84,7 +85,7 @@ public class MessageViewHolder extends ViewHolder implements OnMediaClickListene
text.setMovementMethod(null);
time.setText(Utils.formatToLongTimeString(context, timestamp));
mediaContainer.setVisibility(media != null && media.length > 0 ? View.VISIBLE : View.GONE);
mediaContainer.displayMedia(media, loader, accountId, this, null);
mediaContainer.displayMedia(media, loader, accountId, true, this, adapter.getMediaLoadingHandler());
}
@Override

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
@ -18,28 +17,25 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:showIn="@layout/card_item_message_conversation_incoming">
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible">
android:layout_height="wrap_content">
<include layout="@layout/layout_card_media_preview"/>
<include layout="@layout/layout_card_media_preview" />
</org.mariotaku.twidere.view.CardMediaContainer>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/media_preview_container"
android:orientation="vertical"
android:padding="@dimen/element_spacing_normal">
@ -49,7 +45,7 @@
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
tools:text="@string/sample_status_text"/>
tools:text="@string/sample_status_text" />
<TextView
android:id="@+id/time"
@ -57,6 +53,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:textColor="?android:attr/textColorSecondary"
tools:text="12:00"/>
tools:text="12:00" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>