fixed some NPEs

fixed dialog preference edit text style
This commit is contained in:
Mariotaku Lee 2017-04-07 09:19:09 +08:00
parent 0f076d38b3
commit 4db3a4e851
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
17 changed files with 403 additions and 429 deletions

View File

@ -21,11 +21,15 @@ package org.mariotaku.microblog.library.twitter;
import org.mariotaku.microblog.library.twitter.annotation.StreamWith;
import org.mariotaku.microblog.library.twitter.callback.UserStreamCallback;
import org.mariotaku.microblog.library.twitter.template.StatusAnnotationTemplate;
import org.mariotaku.restfu.annotation.method.GET;
import org.mariotaku.restfu.annotation.param.Queries;
/**
* Twitter UserStream API
* Created by mariotaku on 15/5/26.
*/
@Queries(template = StatusAnnotationTemplate.class)
public interface TwitterUserStream {
@GET("/user.json")

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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
*/
package org.mariotaku.twidere.fragment;
import android.os.Bundle;
import android.support.v7.preference.EditTextPreference;
import android.view.View;
import android.widget.EditText;
public class ThemedEditTextPreferenceDialogFragmentCompat extends ThemedPreferenceDialogFragmentCompat {
private EditText mEditText;
public static ThemedEditTextPreferenceDialogFragmentCompat newInstance(String key) {
final ThemedEditTextPreferenceDialogFragmentCompat fragment =
new ThemedEditTextPreferenceDialogFragmentCompat();
final Bundle args = new Bundle();
args.putString(ARG_KEY, key);
fragment.setArguments(args);
return fragment;
}
@Override
protected boolean needInputMethod() {
return true;
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
mEditText = (EditText) view.findViewById(android.R.id.edit);
final EditTextPreference preference = (EditTextPreference) getPreference();
mEditText.setText(preference.getText());
}
@Override
public void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
final String value = mEditText.getText().toString();
final EditTextPreference preference = (EditTextPreference) getPreference();
if (preference.callChangeListener(value)) {
preference.setText(value);
}
}
}
}

View File

@ -1,303 +0,0 @@
package org.mariotaku.twidere.model.util;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.mariotaku.microblog.library.fanfou.model.Photo;
import org.mariotaku.microblog.library.gnusocial.model.Attachment;
import org.mariotaku.microblog.library.twitter.model.CardEntity;
import org.mariotaku.microblog.library.twitter.model.EntitySupport;
import org.mariotaku.microblog.library.twitter.model.ExtendedEntitySupport;
import org.mariotaku.microblog.library.twitter.model.MediaEntity;
import org.mariotaku.microblog.library.twitter.model.Status;
import org.mariotaku.microblog.library.twitter.model.UrlEntity;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableMediaUpdate;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.InternalTwitterContentUtils;
import org.mariotaku.twidere.util.TwidereArrayUtils;
import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor;
import java.util.ArrayList;
import java.util.List;
/**
* Created by mariotaku on 16/2/13.
*/
public class ParcelableMediaUtils {
private ParcelableMediaUtils() {
}
@NonNull
public static ParcelableMedia[] fromEntities(@Nullable final EntitySupport entities) {
if (entities == null) return new ParcelableMedia[0];
final List<ParcelableMedia> list = new ArrayList<>();
final MediaEntity[] mediaEntities;
if (entities instanceof ExtendedEntitySupport) {
final ExtendedEntitySupport extendedEntities = (ExtendedEntitySupport) entities;
final MediaEntity[] extendedMediaEntities = extendedEntities.getExtendedMediaEntities();
mediaEntities = extendedMediaEntities != null ? extendedMediaEntities : entities.getMediaEntities();
} else {
mediaEntities = entities.getMediaEntities();
}
if (mediaEntities != null) {
for (final MediaEntity media : mediaEntities) {
final String mediaURL = InternalTwitterContentUtils.getMediaUrl(media);
if (mediaURL != null) {
list.add(ParcelableMediaUtils.fromMediaEntity(media));
}
}
}
final UrlEntity[] urlEntities = entities.getUrlEntities();
if (urlEntities != null) {
for (final UrlEntity url : urlEntities) {
final String expanded = url.getExpandedUrl();
final ParcelableMedia media = PreviewMediaExtractor.fromLink(expanded);
if (media != null) {
list.add(media);
}
}
}
return list.toArray(new ParcelableMedia[list.size()]);
}
public static ParcelableMedia fromMediaEntity(MediaEntity entity) {
final ParcelableMedia media = new ParcelableMedia();
final String mediaUrl = InternalTwitterContentUtils.getMediaUrl(entity);
media.url = mediaUrl;
media.media_url = mediaUrl;
media.preview_url = mediaUrl;
media.page_url = entity.getExpandedUrl();
media.type = ParcelableMediaUtils.getTypeInt(entity.getType());
media.alt_text = entity.getAltText();
final MediaEntity.Size size = entity.getSizes().get(MediaEntity.ScaleType.LARGE);
if (size != null) {
media.width = size.getWidth();
media.height = size.getHeight();
} else {
media.width = 0;
media.height = 0;
}
media.video_info = ParcelableMedia.VideoInfo.fromMediaEntityInfo(entity.getVideoInfo());
return media;
}
@Nullable
public static ParcelableMedia[] fromMediaUpdates(@Nullable final ParcelableMediaUpdate[] mediaUpdates) {
if (mediaUpdates == null) return null;
final ParcelableMedia[] media = new ParcelableMedia[mediaUpdates.length];
for (int i = 0, j = mediaUpdates.length; i < j; i++) {
final ParcelableMediaUpdate mediaUpdate = mediaUpdates[i];
media[i] = new ParcelableMedia(mediaUpdate);
}
return media;
}
@Nullable
public static ParcelableMedia[] fromStatus(@NonNull final Status status, UserKey accountKey,
String accountType) {
final ParcelableMedia[] fromEntities = fromEntities(status);
final ParcelableMedia[] fromAttachments = fromAttachments(status);
final ParcelableMedia[] fromCard = fromCard(status.getCard(), status.getUrlEntities(),
status.getMediaEntities(), status.getExtendedMediaEntities(), accountKey,
accountType);
final ParcelableMedia[] fromPhoto = fromPhoto(status);
final ParcelableMedia[] merged = new ParcelableMedia[fromCard.length +
fromAttachments.length + fromEntities.length + fromPhoto.length];
TwidereArrayUtils.mergeArray(merged, fromEntities, fromAttachments, fromCard, fromPhoto);
return merged;
}
@NonNull
private static ParcelableMedia[] fromPhoto(Status status) {
Photo photo = status.getPhoto();
if (photo == null) return new ParcelableMedia[0];
final ParcelableMedia media = new ParcelableMedia();
media.type = ParcelableMedia.Type.IMAGE;
media.url = photo.getUrl();
media.page_url = photo.getUrl();
media.media_url = photo.getLargeUrl();
media.preview_url = photo.getImageUrl();
return new ParcelableMedia[]{media};
}
@NonNull
private static ParcelableMedia[] fromAttachments(@NonNull Status status) {
final Attachment[] attachments = status.getAttachments();
if (attachments == null) return new ParcelableMedia[0];
final ParcelableMedia[] temp = new ParcelableMedia[attachments.length];
final String externalUrl = status.getExternalUrl();
int i = 0;
for (Attachment attachment : attachments) {
final String mimeType = attachment.getMimetype();
if (mimeType == null) continue;
ParcelableMedia media = new ParcelableMedia();
if (mimeType.startsWith("image/")) {
media.type = ParcelableMedia.Type.IMAGE;
} else if (mimeType.startsWith("video/")) {
media.type = ParcelableMedia.Type.VIDEO;
} else {
// https://github.com/TwidereProject/Twidere-Android/issues/729
// Skip unsupported attachment
continue;
}
media.width = attachment.getWidth();
media.height = attachment.getHeight();
media.url = TextUtils.isEmpty(externalUrl) ? attachment.getUrl() : externalUrl;
media.page_url = TextUtils.isEmpty(externalUrl) ? attachment.getUrl() : externalUrl;
media.media_url = attachment.getUrl();
media.preview_url = attachment.getLargeThumbUrl();
temp[i++] = media;
}
return ArrayUtils.subarray(temp, 0, i);
}
@NonNull
private static ParcelableMedia[] fromCard(@Nullable CardEntity card,
@Nullable UrlEntity[] urlEntities, @Nullable MediaEntity[] mediaEntities,
@Nullable MediaEntity[] extendedMediaEntities, UserKey accountKey, String accountType) {
if (card == null) return new ParcelableMedia[0];
final String name = card.getName();
if ("animated_gif".equals(name) || "player".equals(name)) {
final ParcelableMedia media = new ParcelableMedia();
final CardEntity.BindingValue playerStreamUrl = card.getBindingValue("player_stream_url");
media.card = ParcelableCardEntityUtils.INSTANCE.fromCardEntity(card, accountKey,
accountType);
CardEntity.StringValue appUrlResolved = (CardEntity.StringValue) card.getBindingValue("app_url_resolved");
media.url = checkUrl(appUrlResolved) ? appUrlResolved.getValue() : card.getUrl();
if ("animated_gif".equals(name)) {
media.media_url = ((CardEntity.StringValue) playerStreamUrl).getValue();
media.type = ParcelableMedia.Type.CARD_ANIMATED_GIF;
} else if (playerStreamUrl instanceof CardEntity.StringValue) {
media.media_url = ((CardEntity.StringValue) playerStreamUrl).getValue();
media.type = ParcelableMedia.Type.VIDEO;
} else {
CardEntity.StringValue playerUrl = (CardEntity.StringValue) card.getBindingValue("player_url");
if (playerUrl != null) {
media.media_url = playerUrl.getValue();
}
media.type = ParcelableMedia.Type.EXTERNAL_PLAYER;
}
final CardEntity.BindingValue playerImage = card.getBindingValue("player_image");
if (playerImage instanceof CardEntity.ImageValue) {
media.preview_url = ((CardEntity.ImageValue) playerImage).getUrl();
media.width = ((CardEntity.ImageValue) playerImage).getWidth();
media.height = ((CardEntity.ImageValue) playerImage).getHeight();
}
final CardEntity.BindingValue playerWidth = card.getBindingValue("player_width");
final CardEntity.BindingValue playerHeight = card.getBindingValue("player_height");
if (playerWidth instanceof CardEntity.StringValue && playerHeight instanceof CardEntity.StringValue) {
media.width = NumberUtils.toInt(((CardEntity.StringValue) playerWidth).getValue(), -1);
media.height = NumberUtils.toInt(((CardEntity.StringValue) playerHeight).getValue(), -1);
}
writeLinkInfo(media, urlEntities, mediaEntities, extendedMediaEntities);
return new ParcelableMedia[]{media};
} else if ("summary_large_image".equals(name)) {
final CardEntity.BindingValue photoImageFullSize = card.getBindingValue("photo_image_full_size");
if (!(photoImageFullSize instanceof CardEntity.ImageValue))
return new ParcelableMedia[0];
final ParcelableMedia media = new ParcelableMedia();
media.url = card.getUrl();
media.card = ParcelableCardEntityUtils.INSTANCE.fromCardEntity(card, accountKey,
accountType);
media.type = ParcelableMedia.Type.IMAGE;
media.media_url = ((CardEntity.ImageValue) photoImageFullSize).getUrl();
media.width = ((CardEntity.ImageValue) photoImageFullSize).getWidth();
media.height = ((CardEntity.ImageValue) photoImageFullSize).getHeight();
media.open_browser = true;
final CardEntity.BindingValue summaryPhotoImage = card.getBindingValue("summary_photo_image");
if (summaryPhotoImage instanceof CardEntity.ImageValue) {
media.preview_url = ((CardEntity.ImageValue) summaryPhotoImage).getUrl();
}
return new ParcelableMedia[]{media};
}
return new ParcelableMedia[0];
}
private static void writeLinkInfo(ParcelableMedia media, UrlEntity[]... entities) {
if (entities == null) return;
for (UrlEntity[] array : entities) {
if (array == null) continue;
for (UrlEntity entity : array) {
if (entity.getUrl().equals(media.url)) {
media.page_url = entity.getExpandedUrl();
if (media.page_url == null) {
media.page_url = media.url;
}
break;
}
}
}
}
private static boolean checkUrl(CardEntity.StringValue value) {
if (value == null) return false;
final String valueString = value.getValue();
return valueString != null && (valueString.startsWith("http://")
|| valueString.startsWith("https://"));
}
public static int getTypeInt(String type) {
switch (type) {
case MediaEntity.Type.PHOTO:
return ParcelableMedia.Type.IMAGE;
case MediaEntity.Type.VIDEO:
return ParcelableMedia.Type.VIDEO;
case MediaEntity.Type.ANIMATED_GIF:
return ParcelableMedia.Type.ANIMATED_GIF;
}
return ParcelableMedia.Type.UNKNOWN;
}
@NonNull
public static ParcelableMedia image(final String url) {
ParcelableMedia media = new ParcelableMedia();
media.type = ParcelableMedia.Type.IMAGE;
media.url = url;
media.media_url = url;
media.preview_url = url;
return media;
}
public static boolean hasPlayIcon(@ParcelableMedia.Type int type) {
switch (type) {
case ParcelableMedia.Type.VIDEO:
case ParcelableMedia.Type.ANIMATED_GIF:
case ParcelableMedia.Type.CARD_ANIMATED_GIF:
case ParcelableMedia.Type.EXTERNAL_PLAYER:
return true;
default:
return false;
}
}
public static ParcelableMedia findByUrl(@Nullable ParcelableMedia[] media, @Nullable String url) {
if (media == null || url == null) return null;
for (ParcelableMedia item : media) {
if (url.equals(item.url)) return item;
}
return null;
}
@Nullable
public static ParcelableMedia[] getPrimaryMedia(ParcelableStatus status) {
if (status.is_quote && ArrayUtils.isEmpty(status.media)) {
return status.quoted_media;
} else {
return status.media;
}
}
public static ParcelableMedia[] getAllMedia(ParcelableStatus status) {
ParcelableMedia[] result = new ParcelableMedia[TwidereArrayUtils.arraysLength(status.media,
status.quoted_media)];
TwidereArrayUtils.mergeArray(result, status.media, status.quoted_media);
return result;
}
}

View File

@ -1,37 +0,0 @@
package org.mariotaku.twidere.preference;
import android.content.Context;
import android.support.v7.preference.EditTextPreference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.util.AttributeSet;
import org.mariotaku.twidere.fragment.ThemedEditTextPreferenceDialogFragmentCompat;
import org.mariotaku.twidere.preference.iface.IDialogPreference;
/**
* Created by mariotaku on 16/3/15.
*/
public class ThemedEditTextPreference extends EditTextPreference implements IDialogPreference {
public ThemedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ThemedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ThemedEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ThemedEditTextPreference(Context context) {
super(context);
}
@Override
public void displayDialog(PreferenceFragmentCompat fragment) {
ThemedEditTextPreferenceDialogFragmentCompat df = ThemedEditTextPreferenceDialogFragmentCompat.newInstance(getKey());
df.setTargetFragment(fragment, 0);
df.show(fragment.getFragmentManager(), getKey());
}
}

View File

@ -81,9 +81,8 @@ public class InternalTwitterContentUtils {
status.retweeted_by_user_key, status.quoted_user_key, filterRTs);
}
@Nullable
public static String getBestBannerUrl(@Nullable final String baseUrl, final int width) {
if (baseUrl == null) return null;
@NonNull
public static String getBestBannerUrl(@NonNull final String baseUrl, final int width) {
final String type = getBestBannerType(width);
final String authority = UriUtils.getAuthority(baseUrl);
return authority != null && authority.endsWith(".twimg.com") ? baseUrl + "/" + type : baseUrl;

View File

@ -19,11 +19,18 @@
package org.mariotaku.twidere.extension.model
import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.util.InternalTwitterContentUtils
fun ParcelableUser.getBestProfileBanner(width: Int): String? {
return InternalTwitterContentUtils.getBestBannerUrl(profile_banner_url, width)
return profile_banner_url?.let {
InternalTwitterContentUtils.getBestBannerUrl(it, width)
} ?: if (USER_TYPE_FANFOU_COM == key.host) {
profile_background_url
} else {
null
}
}
val ParcelableUser.urlPreferred: String? get() = url_expanded?.takeIf(String::isNotEmpty) ?: url

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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
*/
package org.mariotaku.twidere.fragment
import android.content.Context
import android.os.Bundle
import android.support.v7.preference.EditTextPreference
import android.support.v7.preference.PreferenceDialogFragmentCompat
import android.view.View
import android.widget.EditText
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.view.ChameleonTextView
class ThemedEditTextPreferenceDialogFragmentCompat : ThemedPreferenceDialogFragmentCompat() {
private lateinit var editText: EditText
override fun needInputMethod(): Boolean {
return true
}
override fun onCreateDialogView(context: Context?): View {
val view = super.onCreateDialogView(context)
editText = view.findViewById(android.R.id.edit) as EditText
val appearance = ChameleonTextView.Appearance()
val theme = Chameleon.getOverrideTheme(context, context)
appearance.backgroundTintColor = theme.colorAccent
ChameleonTextView.Appearance.apply(editText, appearance)
return view
}
override fun onBindDialogView(view: View) {
super.onBindDialogView(view)
val preference = preference as EditTextPreference
editText.setText(preference.text)
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
val value = editText.text.toString()
val preference = preference as EditTextPreference
if (preference.callChangeListener(value)) {
preference.text = value
}
}
}
companion object {
fun newInstance(key: String): ThemedEditTextPreferenceDialogFragmentCompat {
val fragment = ThemedEditTextPreferenceDialogFragmentCompat()
val args = Bundle()
args.putString(PreferenceDialogFragmentCompat.ARG_KEY, key)
fragment.arguments = args
return fragment
}
}
}

View File

@ -106,6 +106,7 @@ import org.mariotaku.twidere.extension.applyTheme
import org.mariotaku.twidere.extension.loadOriginalProfileImage
import org.mariotaku.twidere.extension.loadProfileBanner
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.extension.model.getBestProfileBanner
import org.mariotaku.twidere.extension.model.urlPreferred
import org.mariotaku.twidere.fragment.AbsStatusesFragment.StatusesFragmentDelegate
import org.mariotaku.twidere.fragment.UserTimelineFragment.UserTimelineFragmentDelegate
@ -1223,9 +1224,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
preferences[newDocumentApiKey], preferences[displaySensitiveContentsKey])
}
R.id.profileBanner -> {
val bannerUrl = ParcelableUserUtils.getProfileBannerUrl(user) ?: return
val url = getBestBannerUrl(bannerUrl,
Integer.MAX_VALUE)
val url = user.getBestProfileBanner(Integer.MAX_VALUE) ?: return
val profileBanner = ParcelableMediaUtils.image(url)
profileBanner.type = ParcelableMedia.Type.IMAGE
val media = arrayOf(profileBanner)

View File

@ -24,8 +24,7 @@ object ParcelableCardEntityUtils {
sISOFormat.timeZone = TimeZone.getTimeZone("UTC")
}
fun fromCardEntity(card: CardEntity?, accountKey: UserKey?, accountType: String?): ParcelableCardEntity? {
if (card == null) return null
fun fromCardEntity(card: CardEntity, accountKey: UserKey, accountType: String): ParcelableCardEntity? {
val obj = ParcelableCardEntity()
obj.name = card.name
obj.url = card.url

View File

@ -0,0 +1,246 @@
package org.mariotaku.twidere.model.util
import android.text.TextUtils
import org.apache.commons.lang3.ArrayUtils
import org.apache.commons.lang3.math.NumberUtils
import org.mariotaku.ktextension.addAllTo
import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.microblog.library.twitter.model.*
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.util.InternalTwitterContentUtils
import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor
/**
* Created by mariotaku on 16/2/13.
*/
object ParcelableMediaUtils {
fun fromEntities(entities: EntitySupport): Array<ParcelableMedia> {
val list = ArrayList<ParcelableMedia>()
val mediaEntities: Array<MediaEntity>?
if (entities is ExtendedEntitySupport) {
val extendedMediaEntities = entities.extendedMediaEntities
mediaEntities = extendedMediaEntities ?: entities.mediaEntities
} else {
mediaEntities = entities.mediaEntities
}
if (mediaEntities != null) {
for (media in mediaEntities) {
val mediaURL = InternalTwitterContentUtils.getMediaUrl(media)
if (mediaURL != null) {
list.add(ParcelableMediaUtils.fromMediaEntity(media))
}
}
}
val urlEntities = entities.urlEntities
if (urlEntities != null) {
for (url in urlEntities) {
val expanded = url.expandedUrl
val media = PreviewMediaExtractor.fromLink(expanded)
if (media != null) {
list.add(media)
}
}
}
return list.toTypedArray()
}
fun fromMediaEntity(entity: MediaEntity): ParcelableMedia {
val media = ParcelableMedia()
val mediaUrl = InternalTwitterContentUtils.getMediaUrl(entity)
media.url = mediaUrl
media.media_url = mediaUrl
media.preview_url = mediaUrl
media.page_url = entity.expandedUrl
media.type = ParcelableMediaUtils.getTypeInt(entity.type)
media.alt_text = entity.altText
val size = entity.sizes[MediaEntity.ScaleType.LARGE]
if (size != null) {
media.width = size.width
media.height = size.height
} else {
media.width = 0
media.height = 0
}
media.video_info = ParcelableMedia.VideoInfo.fromMediaEntityInfo(entity.videoInfo)
return media
}
fun fromStatus(status: Status, accountKey: UserKey, accountType: String): Array<ParcelableMedia>? {
return fromEntities(status) + fromAttachments(status) + fromCard(status.card,
status.urlEntities, status.mediaEntities, status.extendedMediaEntities, accountKey,
accountType) + fromPhoto(status)
}
private fun fromPhoto(status: Status): Array<ParcelableMedia> {
val photo = status.photo ?: return emptyArray()
val media = ParcelableMedia()
media.type = ParcelableMedia.Type.IMAGE
media.url = photo.url
media.page_url = photo.url
media.media_url = photo.largeUrl
media.preview_url = photo.imageUrl
return arrayOf(media)
}
private fun fromAttachments(status: Status): Array<ParcelableMedia> {
val attachments = status.attachments ?: return emptyArray()
val temp = arrayOfNulls<ParcelableMedia>(attachments.size)
val externalUrl = status.externalUrl
var i = 0
for (attachment in attachments) {
val mimeType = attachment.mimetype ?: continue
val media = ParcelableMedia()
if (mimeType.startsWith("image/")) {
media.type = ParcelableMedia.Type.IMAGE
} else if (mimeType.startsWith("video/")) {
media.type = ParcelableMedia.Type.VIDEO
} else {
// https://github.com/TwidereProject/Twidere-Android/issues/729
// Skip unsupported attachment
continue
}
media.width = attachment.width
media.height = attachment.height
media.url = if (TextUtils.isEmpty(externalUrl)) attachment.url else externalUrl
media.page_url = if (TextUtils.isEmpty(externalUrl)) attachment.url else externalUrl
media.media_url = attachment.url
media.preview_url = attachment.largeThumbUrl
temp[i++] = media
}
return ArrayUtils.subarray<ParcelableMedia>(temp, 0, i)
}
private fun fromCard(card: CardEntity?, urlEntities: Array<UrlEntity>?,
mediaEntities: Array<MediaEntity>?, extendedMediaEntities: Array<MediaEntity>?,
accountKey: UserKey, accountType: String): Array<ParcelableMedia> {
if (card == null) return emptyArray()
val name = card.name
if ("animated_gif" == name || "player" == name) {
val media = ParcelableMedia()
val playerStreamUrl = card.getBindingValue("player_stream_url")
media.card = ParcelableCardEntityUtils.fromCardEntity(card, accountKey,
accountType)
val appUrlResolved = card.getBindingValue("app_url_resolved") as CardEntity.StringValue
media.url = if (checkUrl(appUrlResolved)) appUrlResolved.value else card.url
if ("animated_gif" == name) {
media.media_url = (playerStreamUrl as CardEntity.StringValue).value
media.type = ParcelableMedia.Type.CARD_ANIMATED_GIF
} else if (playerStreamUrl is CardEntity.StringValue) {
media.media_url = playerStreamUrl.value
media.type = ParcelableMedia.Type.VIDEO
} else {
val playerUrl = card.getBindingValue("player_url") as? CardEntity.StringValue
if (playerUrl != null) {
media.media_url = playerUrl.value
}
media.type = ParcelableMedia.Type.EXTERNAL_PLAYER
}
val playerImage = card.getBindingValue("player_image")
if (playerImage is CardEntity.ImageValue) {
media.preview_url = playerImage.url
media.width = playerImage.width
media.height = playerImage.height
}
val playerWidth = card.getBindingValue("player_width")
val playerHeight = card.getBindingValue("player_height")
if (playerWidth is CardEntity.StringValue && playerHeight is CardEntity.StringValue) {
media.width = NumberUtils.toInt(playerWidth.value, -1)
media.height = NumberUtils.toInt(playerHeight.value, -1)
}
writeLinkInfo(media, urlEntities, mediaEntities, extendedMediaEntities)
return arrayOf(media)
} else if ("summary_large_image" == name) {
val photoImageFullSize = card.getBindingValue("photo_image_full_size") as? CardEntity.ImageValue ?: return emptyArray()
val media = ParcelableMedia()
media.url = card.url
media.card = ParcelableCardEntityUtils.fromCardEntity(card, accountKey,
accountType)
media.type = ParcelableMedia.Type.IMAGE
media.media_url = photoImageFullSize.url
media.width = photoImageFullSize.width
media.height = photoImageFullSize.height
media.open_browser = true
val summaryPhotoImage = card.getBindingValue("summary_photo_image")
if (summaryPhotoImage is CardEntity.ImageValue) {
media.preview_url = summaryPhotoImage.url
}
return arrayOf(media)
}
return emptyArray()
}
private fun writeLinkInfo(media: ParcelableMedia, vararg entities: Array<out UrlEntity>?) {
entities.forEach { array ->
if (array == null) return@forEach
for (entity in array) {
if (entity.url == media.url) {
media.page_url = entity.expandedUrl
if (media.page_url == null) {
media.page_url = media.url
}
break
}
}
}
}
private fun checkUrl(value: CardEntity.StringValue?): Boolean {
if (value == null) return false
val valueString = value.value
return valueString != null && (valueString.startsWith("http://") || valueString.startsWith("https://"))
}
fun getTypeInt(type: String): Int {
when (type) {
MediaEntity.Type.PHOTO -> return ParcelableMedia.Type.IMAGE
MediaEntity.Type.VIDEO -> return ParcelableMedia.Type.VIDEO
MediaEntity.Type.ANIMATED_GIF -> return ParcelableMedia.Type.ANIMATED_GIF
}
return ParcelableMedia.Type.UNKNOWN
}
fun image(url: String): ParcelableMedia {
val media = ParcelableMedia()
media.type = ParcelableMedia.Type.IMAGE
media.url = url
media.media_url = url
media.preview_url = url
return media
}
fun hasPlayIcon(@ParcelableMedia.Type type: Int): Boolean {
when (type) {
ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF,
ParcelableMedia.Type.CARD_ANIMATED_GIF, ParcelableMedia.Type.EXTERNAL_PLAYER -> return true
else -> return false
}
}
fun findByUrl(media: Array<ParcelableMedia>?, url: String?): ParcelableMedia? {
if (media == null || url == null) return null
for (item in media) {
if (url == item.url) return item
}
return null
}
fun getPrimaryMedia(status: ParcelableStatus): Array<ParcelableMedia>? {
if (status.is_quote && status.media.isNullOrEmpty()) {
return status.quoted_media
} else {
return status.media
}
}
fun getAllMedia(status: ParcelableStatus): Array<ParcelableMedia> {
val result = ArrayList<ParcelableMedia>()
status.media?.addAllTo(result)
status.quoted_media?.addAllTo(result)
return result.toTypedArray()
}
}

View File

@ -163,9 +163,11 @@ object ParcelableStatusUtils {
result.is_possibly_sensitive = status.isPossiblySensitive
result.mentions = ParcelableUserMentionUtils.fromUserMentionEntities(user,
status.userMentionEntities)
result.card = ParcelableCardEntityUtils.fromCardEntity(status.card, accountKey, accountType)
result.card = status.card?.let {
ParcelableCardEntityUtils.fromCardEntity(it, accountKey, accountType)
}
result.card_name = result.card?.name
result.place_full_name = getPlaceFullName(status)
result.card_name = if (result.card != null) result.card!!.name else null
result.lang = status.lang
return result

View File

@ -3,7 +3,6 @@ package org.mariotaku.twidere.model.util
import android.text.TextUtils
import org.mariotaku.ktextension.isNotNullOrEmpty
import org.mariotaku.microblog.library.twitter.model.User
import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM
import org.mariotaku.twidere.extension.model.api.getProfileImageOfSize
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableUser
@ -19,7 +18,18 @@ import org.mariotaku.twidere.util.UserColorNameManager
*/
object ParcelableUserUtils {
fun fromUser(user: User, accountKey: UserKey?, accountType: String?, position: Long = 0,
fun fromUser(user: User, accountKey: UserKey, accountType: String, position: Long = 0,
profileImageSize: String = "normal"): ParcelableUser {
return fromUserInternal(user, accountKey, accountType, position, profileImageSize)
}
fun fromUser(user: User, accountType: String, position: Long = 0,
profileImageSize: String = "normal"): ParcelableUser {
return fromUserInternal(user, null, accountType, position, profileImageSize)
}
private fun fromUserInternal(user: User, accountKey: UserKey?, accountType: String?, position: Long = 0,
profileImageSize: String = "normal"): ParcelableUser {
val urlEntities = user.urlEntities
val obj = ParcelableUser()
@ -78,11 +88,11 @@ object ParcelableUserUtils {
return obj
}
fun fromUsers(users: Array<User>?, accountKey: UserKey?, accountType: String?,
fun fromUsers(users: Array<User>, accountKey: UserKey, accountType: String,
profileImageSize: String = "normal"): Array<ParcelableUser>? {
return users?.map {
return users.map {
fromUser(it, accountKey, accountType, profileImageSize = profileImageSize)
}?.toTypedArray()
}.toTypedArray()
}
fun parseColor(colorString: String?): Int {
@ -94,14 +104,6 @@ object ParcelableUserUtils {
return ParseUtils.parseColor(str, 0)
}
fun getProfileBannerUrl(user: ParcelableUser): String? {
if (!TextUtils.isEmpty(user.profile_banner_url)) return user.profile_banner_url
if (USER_TYPE_FANFOU_COM == user.key.host) {
return user.profile_background_url
}
return null
}
fun updateExtraInformation(user: ParcelableUser, account: AccountDetails,
manager: UserColorNameManager) {
user.account_color = account.color

View File

@ -0,0 +1,40 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 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.preference
import android.content.Context
import android.support.v7.preference.EditTextPreference
import android.support.v7.preference.PreferenceFragmentCompat
import android.util.AttributeSet
import org.mariotaku.twidere.fragment.ThemedEditTextPreferenceDialogFragmentCompat
import org.mariotaku.twidere.preference.iface.IDialogPreference
/**
* Created by mariotaku on 16/3/15.
*/
class ThemedEditTextPreference(context: Context, attrs: AttributeSet? = null) : EditTextPreference(context, attrs), IDialogPreference {
override fun displayDialog(fragment: PreferenceFragmentCompat) {
val df = ThemedEditTextPreferenceDialogFragmentCompat.newInstance(key)
df.setTargetFragment(fragment, 0)
df.show(fragment.fragmentManager, key)
}
}

View File

@ -35,8 +35,7 @@ object ContentValuesCreator {
fun createCachedUser(user: User, accountType: String, profileImageSize: String = "normal"): ContentValues {
return ObjectCursor.valuesCreatorFrom(ParcelableUser::class.java)
.create(ParcelableUserUtils.fromUser(user, null, accountType,
profileImageSize = profileImageSize))
.create(ParcelableUserUtils.fromUser(user, accountType, profileImageSize = profileImageSize))
}
fun createFilteredUser(status: ParcelableStatus): ContentValues {

View File

@ -158,7 +158,9 @@ class CardPollViewController : ContainerView.ViewController() {
card.account_key, true) ?: return null
val caps = details.newMicroBlogInstance(context, cls = TwitterCaps::class.java)
try {
val cardEntity = caps.sendPassThrough(cardDataMap).card
val cardEntity = caps.sendPassThrough(cardDataMap).card ?: run {
return null
}
return ParcelableCardEntityUtils.fromCardEntity(cardEntity,
card.account_key, details.type)
} catch (e: MicroBlogException) {

View File

@ -27,6 +27,8 @@ import kotlinx.android.synthetic.main.list_item_draft.view.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.extension.model.getActionName
import org.mariotaku.twidere.model.Draft
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableMediaUpdate
import org.mariotaku.twidere.model.draft.StatusObjectExtras
import org.mariotaku.twidere.model.util.ParcelableMediaUtils
import org.mariotaku.twidere.util.DataStoreUtils
@ -48,7 +50,7 @@ class DraftViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
Draft.Action.SEND_DIRECT_MESSAGE, Draft.Action.SEND_DIRECT_MESSAGE_COMPAT,
Draft.Action.UPDATE_STATUS, Draft.Action.UPDATE_STATUS_COMPAT_1,
Draft.Action.UPDATE_STATUS_COMPAT_2, Draft.Action.REPLY, Draft.Action.QUOTE -> {
val media = ParcelableMediaUtils.fromMediaUpdates(draft.media)
val media = draft.media?.map(::ParcelableMedia)?.toTypedArray()
mediaPreviewContainer.visibility = View.VISIBLE
mediaPreviewContainer.displayMedia(requestManager = requestManager,
media = media)

View File

@ -142,7 +142,7 @@ class UserViewHolder(
profileImageView.visibility = View.GONE
}
if (twitter.isUpdatingRelationship(user.account_key, user.key)) {
if (user.account_key != null && twitter.isUpdatingRelationship(user.account_key, user.key)) {
processingRequestProgress.visibility = View.VISIBLE
actionsContainer.visibility = View.GONE
} else {