parent
0077388c65
commit
41233a837b
54 changed files with 1266 additions and 1042 deletions
|
@ -312,9 +312,7 @@ public final class AccountActivity extends BaseActivity implements ActionButtonA
|
|||
getSupportActionBar().setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
boolean useCustomTabs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean("customTabs", false);
|
||||
LinkHelper.setClickableText(note, account.note, null, useCustomTabs, new LinkListener() {
|
||||
LinkHelper.setClickableText(note, account.note, null, new LinkListener() {
|
||||
@Override
|
||||
public void onViewTag(String tag) {
|
||||
Intent intent = new Intent(AccountActivity.this, ViewTagActivity.class);
|
||||
|
|
|
@ -78,7 +78,7 @@ import com.keylesspalace.tusky.adapter.MentionAutoCompleteAdapter;
|
|||
import com.keylesspalace.tusky.db.TootDao;
|
||||
import com.keylesspalace.tusky.db.TootEntity;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Media;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.fragment.ComposeOptionsFragment;
|
||||
import com.keylesspalace.tusky.network.ProgressRequestBody;
|
||||
|
@ -1274,9 +1274,9 @@ public final class ComposeActivity extends BaseActivity
|
|||
|
||||
item.uploadRequest = mastodonApi.uploadMedia(body);
|
||||
|
||||
item.uploadRequest.enqueue(new Callback<Media>() {
|
||||
item.uploadRequest.enqueue(new Callback<Attachment>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<Media> call, @NonNull retrofit2.Response<Media> response) {
|
||||
public void onResponse(@NonNull Call<Attachment> call, @NonNull retrofit2.Response<Attachment> response) {
|
||||
if (response.isSuccessful()) {
|
||||
onUploadSuccess(item, response.body());
|
||||
} else {
|
||||
|
@ -1286,14 +1286,14 @@ public final class ComposeActivity extends BaseActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Media> call, @NonNull Throwable t) {
|
||||
public void onFailure(@NonNull Call<Attachment> call, @NonNull Throwable t) {
|
||||
Log.d(TAG, "Upload request failed. " + t.getMessage());
|
||||
onUploadFailure(item, call.isCanceled());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onUploadSuccess(final QueuedMedia item, Media media) {
|
||||
private void onUploadSuccess(final QueuedMedia item, Attachment media) {
|
||||
item.id = media.id;
|
||||
item.preview.setProgress(-1);
|
||||
item.readyStage = QueuedMedia.ReadyStage.UPLOADED;
|
||||
|
@ -1460,7 +1460,7 @@ public final class ComposeActivity extends BaseActivity
|
|||
ProgressImageView preview;
|
||||
Uri uri;
|
||||
String id;
|
||||
Call<Media> uploadRequest;
|
||||
Call<Attachment> uploadRequest;
|
||||
URLSpan uploadUrl;
|
||||
ReadyStage readyStage;
|
||||
byte[] content;
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.app.SearchableInfo;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
|
@ -150,8 +151,7 @@ public class SearchActivity extends BaseActivity implements SearchView.OnQueryTe
|
|||
}
|
||||
|
||||
searchView.setOnQueryTextListener(this);
|
||||
searchView.setFocusable(false);
|
||||
searchView.setFocusableInTouchMode(false);
|
||||
searchView.requestFocus();
|
||||
|
||||
searchView.setMaxWidth(Integer.MAX_VALUE);
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ public class SearchActivity extends BaseActivity implements SearchView.OnQueryTe
|
|||
clearResults();
|
||||
Callback<SearchResults> callback = new Callback<SearchResults>() {
|
||||
@Override
|
||||
public void onResponse(Call<SearchResults> call, Response<SearchResults> response) {
|
||||
public void onResponse(@NonNull Call<SearchResults> call, @NonNull Response<SearchResults> response) {
|
||||
if (response.isSuccessful()) {
|
||||
SearchResults results = response.body();
|
||||
if (results.accounts != null && results.accounts.length > 0 || results.hashtags != null && results.hashtags.length > 0) {
|
||||
|
@ -175,7 +175,7 @@ public class SearchActivity extends BaseActivity implements SearchView.OnQueryTe
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<SearchResults> call, Throwable t) {
|
||||
public void onFailure(@NonNull Call<SearchResults> call, @NonNull Throwable t) {
|
||||
onSearchFailure();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.content.Context;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
@ -26,7 +27,6 @@ import android.text.SpannableStringBuilder;
|
|||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -38,13 +38,18 @@ import android.widget.ToggleButton;
|
|||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.DateUtils;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.view.RoundedTransformation;
|
||||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||
|
@ -126,13 +131,17 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
case FAVOURITE:
|
||||
case REBLOG: {
|
||||
StatusNotificationViewHolder holder = (StatusNotificationViewHolder) viewHolder;
|
||||
holder.setMessage(type, concreteNotificaton.getAccount().getDisplayName(),
|
||||
concreteNotificaton.getStatusViewData());
|
||||
StatusViewData.Concrete statusViewData = concreteNotificaton.getStatusViewData();
|
||||
holder.setDisplayName(statusViewData.getUserFullName());
|
||||
holder.setUsername(statusViewData.getNickname());
|
||||
holder.setCreatedAt(statusViewData.getCreatedAt());
|
||||
|
||||
holder.setMessage(concreteNotificaton, statusListener);
|
||||
holder.setupButtons(notificationActionListener,
|
||||
concreteNotificaton.getAccount().id,
|
||||
concreteNotificaton.getId());
|
||||
holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(),
|
||||
concreteNotificaton.getId());
|
||||
concreteNotificaton.getAccount().avatar);
|
||||
break;
|
||||
}
|
||||
case FOLLOW: {
|
||||
|
@ -220,6 +229,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
void onViewAccount(String id);
|
||||
|
||||
void onViewStatusForNotificationId(String notificationId);
|
||||
|
||||
void onExpandedChange(boolean expanded, int position);
|
||||
|
||||
}
|
||||
|
||||
private static class FollowViewHolder extends RecyclerView.ViewHolder {
|
||||
|
@ -270,30 +282,32 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private static class StatusNotificationViewHolder extends RecyclerView.ViewHolder
|
||||
implements View.OnClickListener, ToggleButton.OnCheckedChangeListener {
|
||||
private final TextView message;
|
||||
private final ImageView icon;
|
||||
private final TextView displayName;
|
||||
private final TextView username;
|
||||
private final TextView timestampInfo;
|
||||
private final TextView statusContent;
|
||||
private final ViewGroup container;
|
||||
private final ImageView statusAvatar;
|
||||
private final ImageView notificationAvatar;
|
||||
private final ViewGroup topBar;
|
||||
private final View contentWarningBar;
|
||||
private final TextView contentWarningDescriptionTextView;
|
||||
private final ToggleButton contentWarningButton;
|
||||
|
||||
private String accountId;
|
||||
private String notificationId;
|
||||
private NotificationActionListener listener;
|
||||
private NotificationActionListener notificationActionListener;
|
||||
private StatusViewData.Concrete statusViewData;
|
||||
|
||||
StatusNotificationViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
message = itemView.findViewById(R.id.notification_text);
|
||||
icon = itemView.findViewById(R.id.notification_icon);
|
||||
message = itemView.findViewById(R.id.notification_top_text);
|
||||
displayName = itemView.findViewById(R.id.status_display_name);
|
||||
username = itemView.findViewById(R.id.status_username);
|
||||
timestampInfo = itemView.findViewById(R.id.status_timestamp_info);
|
||||
statusContent = itemView.findViewById(R.id.notification_content);
|
||||
container = itemView.findViewById(R.id.notification_container);
|
||||
statusAvatar = itemView.findViewById(R.id.notification_status_avatar);
|
||||
notificationAvatar = itemView.findViewById(R.id.notification_notification_avatar);
|
||||
topBar = itemView.findViewById(R.id.notification_top_bar);
|
||||
contentWarningBar = itemView.findViewById(R.id.notification_content_warning_bar);
|
||||
contentWarningDescriptionTextView = itemView.findViewById(R.id.notification_content_warning_description);
|
||||
contentWarningButton = itemView.findViewById(R.id.notification_content_warning_button);
|
||||
|
@ -303,33 +317,77 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
notificationAvatar.setColorFilter(darkerFilter, PorterDuff.Mode.MULTIPLY);
|
||||
|
||||
container.setOnClickListener(this);
|
||||
topBar.setOnClickListener(this);
|
||||
message.setOnClickListener(this);
|
||||
statusContent.setOnClickListener(this);
|
||||
contentWarningButton.setOnCheckedChangeListener(this);
|
||||
}
|
||||
|
||||
void setMessage(Notification.Type type, String displayName,
|
||||
StatusViewData.Concrete status) {
|
||||
this.statusViewData = status;
|
||||
private void setDisplayName(String name) {
|
||||
displayName.setText(name);
|
||||
}
|
||||
|
||||
private void setUsername(String name) {
|
||||
Context context = username.getContext();
|
||||
String format = context.getString(R.string.status_username_format);
|
||||
String usernameText = String.format(format, name);
|
||||
username.setText(usernameText);
|
||||
}
|
||||
|
||||
private void setCreatedAt(@Nullable Date createdAt) {
|
||||
// This is the visible timestampInfo.
|
||||
String readout;
|
||||
/* This one is for screen-readers. Frequently, they would mispronounce timestamps like "17m"
|
||||
* as 17 meters instead of minutes. */
|
||||
CharSequence readoutAloud;
|
||||
if (createdAt != null) {
|
||||
long then = createdAt.getTime();
|
||||
long now = new Date().getTime();
|
||||
readout = DateUtils.getRelativeTimeSpanString(timestampInfo.getContext(), then, now);
|
||||
readoutAloud = android.text.format.DateUtils.getRelativeTimeSpanString(then, now,
|
||||
android.text.format.DateUtils.SECOND_IN_MILLIS,
|
||||
android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE);
|
||||
} else {
|
||||
// unknown minutes~
|
||||
readout = "?m";
|
||||
readoutAloud = "? minutes";
|
||||
}
|
||||
timestampInfo.setText(readout);
|
||||
timestampInfo.setContentDescription(readoutAloud);
|
||||
}
|
||||
|
||||
void setMessage(NotificationViewData.Concrete notificationViewData, LinkListener listener) {
|
||||
this.statusViewData = notificationViewData.getStatusViewData();
|
||||
|
||||
String displayName = notificationViewData.getAccount().getDisplayName();
|
||||
Notification.Type type = notificationViewData.getType();
|
||||
|
||||
Context context = message.getContext();
|
||||
String format;
|
||||
Drawable icon;
|
||||
switch (type) {
|
||||
default:
|
||||
case FAVOURITE: {
|
||||
icon.setImageResource(R.drawable.ic_star_24dp);
|
||||
icon.setColorFilter(ContextCompat.getColor(context,
|
||||
R.color.status_favourite_button_marked_dark));
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_star_24dp);
|
||||
if (icon != null) {
|
||||
icon.setColorFilter(ContextCompat.getColor(context,
|
||||
R.color.status_favourite_button_marked_dark), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
format = context.getString(R.string.notification_favourite_format);
|
||||
break;
|
||||
}
|
||||
case REBLOG: {
|
||||
icon.setImageResource(R.drawable.ic_repeat_24dp);
|
||||
icon.setColorFilter(ContextCompat.getColor(context,
|
||||
R.color.color_accent_dark));
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_repeat_24dp);
|
||||
if(icon != null) {
|
||||
icon.setColorFilter(ContextCompat.getColor(context,
|
||||
R.color.color_accent_dark), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
|
||||
format = context.getString(R.string.notification_reblog_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
message.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
|
||||
String wholeMessage = String.format(format, displayName);
|
||||
final SpannableStringBuilder str = new SpannableStringBuilder(wholeMessage);
|
||||
str.setSpan(new StyleSpan(Typeface.BOLD), 0, displayName.length(),
|
||||
|
@ -338,12 +396,12 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText());
|
||||
contentWarningBar.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
|
||||
setupContentAndSpoiler(false);
|
||||
setupContentAndSpoiler(notificationViewData, listener);
|
||||
}
|
||||
|
||||
void setupButtons(final NotificationActionListener listener, final String accountId,
|
||||
final String notificationId) {
|
||||
this.listener = listener;
|
||||
this.notificationActionListener = listener;
|
||||
this.accountId = accountId;
|
||||
this.notificationId = notificationId;
|
||||
}
|
||||
|
@ -362,11 +420,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
if (notificationAvatarUrl == null || notificationAvatarUrl.isEmpty()) {
|
||||
notificationAvatar.setVisibility(View.GONE);
|
||||
notificationAvatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
notificationAvatar.setVisibility(View.VISIBLE);
|
||||
Picasso.with(context)
|
||||
.load(notificationAvatarUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.fit()
|
||||
.transform(new RoundedTransformation(7, 0))
|
||||
.into(notificationAvatar);
|
||||
|
@ -377,46 +435,48 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.notification_container:
|
||||
if (listener != null) listener.onViewStatusForNotificationId(notificationId);
|
||||
case R.id.notification_content:
|
||||
if (notificationActionListener != null) notificationActionListener.onViewStatusForNotificationId(notificationId);
|
||||
break;
|
||||
case R.id.notification_top_bar:
|
||||
if (listener != null) listener.onViewAccount(accountId);
|
||||
case R.id.notification_top_text:
|
||||
if (notificationActionListener != null) notificationActionListener.onViewAccount(accountId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupContentAndSpoiler(boolean shouldShowContentIfSpoiler) {
|
||||
private void setupContentAndSpoiler(NotificationViewData.Concrete notificationViewData, final LinkListener listener) {
|
||||
|
||||
boolean shouldShowContentIfSpoiler = notificationViewData.isExpanded();
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText());
|
||||
CharSequence content;
|
||||
if (!shouldShowContentIfSpoiler && hasSpoiler) {
|
||||
if (statusViewData.getMentions() != null &&
|
||||
statusViewData.getMentions().length > 0) {
|
||||
// If there is a content warning and mentions we're alternating between
|
||||
// showing mentions and showing full content. As mentions are plain text we
|
||||
// have to construct URLSpans ourselves.
|
||||
SpannableStringBuilder contentBuilder = new SpannableStringBuilder();
|
||||
for (Status.Mention mention : statusViewData.getMentions()) {
|
||||
int start = contentBuilder.length() > 0 ? contentBuilder.length() - 1 : 0;
|
||||
contentBuilder.append('@');
|
||||
contentBuilder.append(mention.username);
|
||||
contentBuilder.append(' ');
|
||||
contentBuilder.setSpan(new URLSpan(mention.url), start,
|
||||
mention.username.length() + 1, 0);
|
||||
}
|
||||
content = contentBuilder;
|
||||
} else {
|
||||
content = null;
|
||||
}
|
||||
statusContent.setVisibility(View.GONE);
|
||||
} else {
|
||||
content = statusViewData.getContent();
|
||||
statusContent.setVisibility(View.VISIBLE);
|
||||
}
|
||||
statusContent.setText(content);
|
||||
contentWarningDescriptionTextView.setText(statusViewData.getSpoilerText());
|
||||
|
||||
Spanned content = statusViewData.getContent();
|
||||
List<Status.Emoji> emojis = statusViewData.getEmojis();
|
||||
|
||||
Spanned emojifiedText = CustomEmojiHelper.emojifyText(content, emojis, statusContent);
|
||||
|
||||
LinkHelper.setClickableText(statusContent, emojifiedText, statusViewData.getMentions(), listener);
|
||||
|
||||
|
||||
Spanned emojifiedContentWarning =
|
||||
CustomEmojiHelper.emojifyString(statusViewData.getSpoilerText(), statusViewData.getEmojis(), contentWarningDescriptionTextView);
|
||||
contentWarningDescriptionTextView.setText(emojifiedContentWarning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
setupContentAndSpoiler(isChecked);
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
notificationActionListener.onExpandedChange(isChecked, getAdapterPosition());
|
||||
}
|
||||
if (isChecked) {
|
||||
statusContent.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
statusContent.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.content.res.AppCompatResources;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageButton;
|
||||
|
@ -24,26 +17,24 @@ import android.widget.TextView;
|
|||
import android.widget.ToggleButton;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.DateUtils;
|
||||
import com.keylesspalace.tusky.util.HtmlUtils;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||
import com.keylesspalace.tusky.view.RoundedTransformation;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.squareup.picasso.Callback;
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
import com.varunest.sparkbutton.SparkButton;
|
||||
import com.varunest.sparkbutton.SparkEventListener;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||
abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||
private View container;
|
||||
private TextView displayName;
|
||||
private TextView username;
|
||||
|
@ -58,23 +49,26 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private ImageView mediaPreview1;
|
||||
private ImageView mediaPreview2;
|
||||
private ImageView mediaPreview3;
|
||||
private View sensitiveMediaWarning;
|
||||
private ImageView mediaOverlay0;
|
||||
private ImageView mediaOverlay1;
|
||||
private ImageView mediaOverlay2;
|
||||
private ImageView mediaOverlay3;
|
||||
private TextView sensitiveMediaWarning;
|
||||
private View sensitiveMediaShow;
|
||||
private View videoIndicator;
|
||||
private TextView mediaLabel;
|
||||
private View contentWarningBar;
|
||||
private TextView contentWarningDescription;
|
||||
private ToggleButton contentWarningButton;
|
||||
|
||||
ImageView avatar;
|
||||
TextView timestamp;
|
||||
TextView timestampInfo;
|
||||
|
||||
StatusBaseViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
container = itemView.findViewById(R.id.status_container);
|
||||
displayName = itemView.findViewById(R.id.status_display_name);
|
||||
username = itemView.findViewById(R.id.status_username);
|
||||
timestamp = itemView.findViewById(R.id.status_timestamp);
|
||||
timestampInfo = itemView.findViewById(R.id.status_timestamp_info);
|
||||
content = itemView.findViewById(R.id.status_content);
|
||||
avatar = itemView.findViewById(R.id.status_avatar);
|
||||
replyButton = itemView.findViewById(R.id.status_reply);
|
||||
|
@ -87,15 +81,20 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
mediaPreview1 = itemView.findViewById(R.id.status_media_preview_1);
|
||||
mediaPreview2 = itemView.findViewById(R.id.status_media_preview_2);
|
||||
mediaPreview3 = itemView.findViewById(R.id.status_media_preview_3);
|
||||
mediaOverlay0 = itemView.findViewById(R.id.status_media_overlay_0);
|
||||
mediaOverlay1 = itemView.findViewById(R.id.status_media_overlay_1);
|
||||
mediaOverlay2 = itemView.findViewById(R.id.status_media_overlay_2);
|
||||
mediaOverlay3 = itemView.findViewById(R.id.status_media_overlay_3);
|
||||
sensitiveMediaWarning = itemView.findViewById(R.id.status_sensitive_media_warning);
|
||||
sensitiveMediaShow = itemView.findViewById(R.id.status_sensitive_media_button);
|
||||
videoIndicator = itemView.findViewById(R.id.status_video_indicator);
|
||||
mediaLabel = itemView.findViewById(R.id.status_media_label);
|
||||
contentWarningBar = itemView.findViewById(R.id.status_content_warning_bar);
|
||||
contentWarningDescription = itemView.findViewById(R.id.status_content_warning_description);
|
||||
contentWarningButton = itemView.findViewById(R.id.status_content_warning_button);
|
||||
}
|
||||
|
||||
protected abstract int getMediaPreviewHeight(Context context);
|
||||
|
||||
private void setDisplayName(String name) {
|
||||
displayName.setText(name);
|
||||
}
|
||||
|
@ -107,44 +106,11 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
username.setText(usernameText);
|
||||
}
|
||||
|
||||
private Callback spanCallback = new Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
content.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
}
|
||||
};
|
||||
|
||||
private void setContent(Spanned content, Status.Mention[] mentions, List<Status.Emoji> emojis,
|
||||
StatusActionListener listener) {
|
||||
Context context = this.content.getContext();
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(content);
|
||||
if (!emojis.isEmpty()) {
|
||||
CharSequence text = builder.subSequence(0, builder.length());
|
||||
for (Status.Emoji emoji : emojis) {
|
||||
CharSequence pattern = new StringBuilder(":").append(emoji.getShortcode()).append(':');
|
||||
Matcher matcher = Pattern.compile(pattern.toString()).matcher(text);
|
||||
while (matcher.find()) {
|
||||
// We keep a span as a Picasso target, because Picasso keeps weak reference to
|
||||
// the target so an anonymous class would likely be garbage collected.
|
||||
EmojiSpan span = new EmojiSpan(context);
|
||||
span.setCallback(spanCallback);
|
||||
builder.setSpan(span, matcher.start(), matcher.end(), 0);
|
||||
Picasso.with(container.getContext())
|
||||
.load(emoji.getUrl())
|
||||
.into(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
Spanned emojifiedText = CustomEmojiHelper.emojifyText(content, emojis, this.content);
|
||||
|
||||
/* Redirect URLSpan's in the status content to the listener for viewing tag pages and
|
||||
* account pages. */
|
||||
boolean useCustomTabs =
|
||||
PreferenceManager.getDefaultSharedPreferences(context).getBoolean("customTabs", false);
|
||||
LinkHelper.setClickableText(this.content, builder, mentions, useCustomTabs, listener);
|
||||
LinkHelper.setClickableText(this.content, emojifiedText, mentions, listener);
|
||||
}
|
||||
|
||||
void setAvatar(String url, @Nullable String rebloggedUrl) {
|
||||
|
@ -160,7 +126,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
protected void setCreatedAt(@Nullable Date createdAt) {
|
||||
// This is the visible timestamp.
|
||||
// This is the visible timestampInfo.
|
||||
String readout;
|
||||
/* This one is for screen-readers. Frequently, they would mispronounce timestamps like "17m"
|
||||
* as 17 meters instead of minutes. */
|
||||
|
@ -168,7 +134,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
if (createdAt != null) {
|
||||
long then = createdAt.getTime();
|
||||
long now = new Date().getTime();
|
||||
readout = DateUtils.getRelativeTimeSpanString(timestamp.getContext(), then, now);
|
||||
readout = DateUtils.getRelativeTimeSpanString(timestampInfo.getContext(), then, now);
|
||||
readoutAloud = android.text.format.DateUtils.getRelativeTimeSpanString(then, now,
|
||||
android.text.format.DateUtils.SECOND_IN_MILLIS,
|
||||
android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE);
|
||||
|
@ -177,8 +143,18 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
readout = "?m";
|
||||
readoutAloud = "? minutes";
|
||||
}
|
||||
timestamp.setText(readout);
|
||||
timestamp.setContentDescription(readoutAloud);
|
||||
timestampInfo.setText(readout);
|
||||
timestampInfo.setContentDescription(readoutAloud);
|
||||
}
|
||||
|
||||
|
||||
private void setIsReply(boolean isReply) {
|
||||
if(isReply) {
|
||||
replyButton.setImageResource(R.drawable.ic_reply_all_24dp);
|
||||
} else {
|
||||
replyButton.setImageResource(R.drawable.ic_reply_24dp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setReblogged(boolean reblogged) {
|
||||
|
@ -214,11 +190,14 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
favouriteButton.setChecked(favourited);
|
||||
}
|
||||
|
||||
private void setMediaPreviews(final Status.MediaAttachment[] attachments, boolean sensitive,
|
||||
final StatusActionListener listener, boolean showingSensitive) {
|
||||
private void setMediaPreviews(final Attachment[] attachments, boolean sensitive,
|
||||
final StatusActionListener listener, boolean showingContent) {
|
||||
final ImageView[] previews = {
|
||||
mediaPreview0, mediaPreview1, mediaPreview2, mediaPreview3
|
||||
};
|
||||
final ImageView[] overlays = {
|
||||
mediaOverlay0, mediaOverlay1, mediaOverlay2, mediaOverlay3
|
||||
};
|
||||
Context context = mediaPreview0.getContext();
|
||||
|
||||
int mediaPreviewUnloadedId =
|
||||
|
@ -234,6 +213,13 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
for (int i = 0; i < n; i++) {
|
||||
String previewUrl = attachments[i].previewUrl;
|
||||
String description = attachments[i].description;
|
||||
|
||||
if(TextUtils.isEmpty(description)) {
|
||||
previews[i].setContentDescription(context.getString(R.string.action_view_media));
|
||||
} else {
|
||||
previews[i].setContentDescription(description);
|
||||
}
|
||||
|
||||
previews[i].setVisibility(View.VISIBLE);
|
||||
|
||||
|
@ -246,9 +232,11 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
.into(previews[i]);
|
||||
}
|
||||
|
||||
final Status.MediaAttachment.Type type = attachments[i].type;
|
||||
if (type == Status.MediaAttachment.Type.VIDEO | type == Status.MediaAttachment.Type.GIFV) {
|
||||
videoIndicator.setVisibility(View.VISIBLE);
|
||||
final Attachment.Type type = attachments[i].type;
|
||||
if (type == Attachment.Type.VIDEO | type == Attachment.Type.GIFV) {
|
||||
overlays[i].setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
overlays[i].setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (urls[i] == null || urls[i].isEmpty()) {
|
||||
|
@ -262,34 +250,56 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(n <= 2) {
|
||||
previews[0].getLayoutParams().height = getMediaPreviewHeight(context)*2;
|
||||
previews[1].getLayoutParams().height = getMediaPreviewHeight(context)*2;
|
||||
} else {
|
||||
previews[0].getLayoutParams().height = getMediaPreviewHeight(context);
|
||||
previews[1].getLayoutParams().height = getMediaPreviewHeight(context);
|
||||
previews[2].getLayoutParams().height = getMediaPreviewHeight(context);
|
||||
previews[3].getLayoutParams().height = getMediaPreviewHeight(context);
|
||||
}
|
||||
}
|
||||
SharedPreferences pm = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Boolean isAlwayShowSensitive = pm.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
if (sensitive && (!isAlwayShowSensitive)) {
|
||||
sensitiveMediaWarning.setVisibility(showingSensitive ? View.GONE : View.VISIBLE);
|
||||
sensitiveMediaShow.setVisibility(showingSensitive ? View.VISIBLE : View.GONE);
|
||||
sensitiveMediaShow.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
listener.onContentHiddenChange(false, getAdapterPosition());
|
||||
}
|
||||
v.setVisibility(View.GONE);
|
||||
sensitiveMediaWarning.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
sensitiveMediaWarning.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
listener.onContentHiddenChange(true, getAdapterPosition());
|
||||
}
|
||||
v.setVisibility(View.GONE);
|
||||
sensitiveMediaShow.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
String hiddenContentText;
|
||||
if(sensitive) {
|
||||
hiddenContentText = context.getString(R.string.status_sensitive_media_template,
|
||||
context.getString(R.string.status_sensitive_media_title),
|
||||
context.getString(R.string.status_sensitive_media_directions));
|
||||
|
||||
} else {
|
||||
hiddenContentText = context.getString(R.string.status_sensitive_media_template,
|
||||
context.getString(R.string.status_media_hidden_title),
|
||||
context.getString(R.string.status_sensitive_media_directions));
|
||||
}
|
||||
|
||||
sensitiveMediaWarning.setText(HtmlUtils.fromHtml(hiddenContentText));
|
||||
|
||||
sensitiveMediaWarning.setVisibility(showingContent ? View.GONE : View.VISIBLE);
|
||||
sensitiveMediaShow.setVisibility(showingContent ? View.VISIBLE : View.GONE);
|
||||
sensitiveMediaShow.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
listener.onContentHiddenChange(false, getAdapterPosition());
|
||||
}
|
||||
v.setVisibility(View.GONE);
|
||||
sensitiveMediaWarning.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
sensitiveMediaWarning.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
listener.onContentHiddenChange(true, getAdapterPosition());
|
||||
}
|
||||
v.setVisibility(View.GONE);
|
||||
sensitiveMediaShow.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Hide any of the placeholder previews beyond the ones set.
|
||||
for (int i = n; i < Status.MAX_MEDIA_ATTACHMENTS; i++) {
|
||||
previews[i].setVisibility(View.GONE);
|
||||
|
@ -297,7 +307,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
private static String getLabelTypeText(Context context, Status.MediaAttachment.Type type) {
|
||||
private static String getLabelTypeText(Context context, Attachment.Type type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case IMAGE:
|
||||
|
@ -309,7 +319,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
@DrawableRes
|
||||
private static int getLabelIcon(Status.MediaAttachment.Type type) {
|
||||
private static int getLabelIcon(Attachment.Type type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case IMAGE:
|
||||
|
@ -320,7 +330,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private void setMediaLabel(Status.MediaAttachment[] attachments, boolean sensitive,
|
||||
private void setMediaLabel(Attachment[] attachments, boolean sensitive,
|
||||
final StatusActionListener listener) {
|
||||
if (attachments.length == 0) {
|
||||
mediaLabel.setVisibility(View.GONE);
|
||||
|
@ -349,7 +359,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
for (int i = 0; i < n; i++) {
|
||||
urls[i] = attachments[i].url;
|
||||
}
|
||||
final Status.MediaAttachment.Type type = attachments[0].type;
|
||||
final Attachment.Type type = attachments[0].type;
|
||||
mediaLabel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -363,14 +373,17 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
sensitiveMediaShow.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setSpoilerText(String spoilerText, final boolean expanded,
|
||||
final StatusActionListener listener) {
|
||||
contentWarningDescription.setText(spoilerText);
|
||||
private void setSpoilerText(String spoilerText, List<Status.Emoji> emojis,
|
||||
final boolean expanded, final StatusActionListener listener) {
|
||||
CharSequence emojiSpoiler =
|
||||
CustomEmojiHelper.emojifyString(spoilerText, emojis, contentWarningDescription);
|
||||
contentWarningDescription.setText(emojiSpoiler);
|
||||
contentWarningBar.setVisibility(View.VISIBLE);
|
||||
contentWarningButton.setChecked(expanded);
|
||||
contentWarningButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
contentWarningDescription.invalidate();
|
||||
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
|
||||
listener.onExpandedChange(isChecked, getAdapterPosition());
|
||||
}
|
||||
|
@ -478,21 +491,19 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
setDisplayName(status.getUserFullName());
|
||||
setUsername(status.getNickname());
|
||||
setCreatedAt(status.getCreatedAt());
|
||||
setIsReply(status.getInReplyToId() != null);
|
||||
setContent(status.getContent(), status.getMentions(), status.getEmojis(), listener);
|
||||
setAvatar(status.getAvatar(), status.getRebloggedAvatar());
|
||||
setReblogged(status.isReblogged());
|
||||
setFavourited(status.isFavourited());
|
||||
Status.MediaAttachment[] attachments = status.getAttachments();
|
||||
Attachment[] attachments = status.getAttachments();
|
||||
boolean sensitive = status.isSensitive();
|
||||
if (mediaPreviewEnabled) {
|
||||
setMediaPreviews(attachments, sensitive, listener, status.isShowingSensitiveContent());
|
||||
/* A status without attachments is sometimes still marked sensitive, so it's necessary
|
||||
* to check both whether there are any attachments and if it's marked sensitive. */
|
||||
if (!sensitive || attachments.length == 0) {
|
||||
hideSensitiveMediaWarning();
|
||||
}
|
||||
setMediaPreviews(attachments, sensitive, listener, status.isShowingContent());
|
||||
|
||||
if (attachments.length == 0) {
|
||||
videoIndicator.setVisibility(View.GONE);
|
||||
hideSensitiveMediaWarning();
|
||||
// videoIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
// Hide the unused label.
|
||||
mediaLabel.setVisibility(View.GONE);
|
||||
|
@ -504,7 +515,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
mediaPreview2.setVisibility(View.GONE);
|
||||
mediaPreview3.setVisibility(View.GONE);
|
||||
hideSensitiveMediaWarning();
|
||||
videoIndicator.setVisibility(View.GONE);
|
||||
// videoIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setupButtons(listener, status.getSenderId());
|
||||
|
@ -512,66 +523,9 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
if (status.getSpoilerText() == null || status.getSpoilerText().isEmpty()) {
|
||||
hideSpoilerText();
|
||||
} else {
|
||||
setSpoilerText(status.getSpoilerText(), status.isExpanded(), listener);
|
||||
setSpoilerText(status.getSpoilerText(), status.getEmojis(), status.isExpanded(), listener);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmojiSpan extends ReplacementSpan implements Target {
|
||||
|
||||
private @Nullable
|
||||
Drawable imageDrawable;
|
||||
private WeakReference<Callback> callbackWeakReference;
|
||||
private Context context;
|
||||
|
||||
EmojiSpan(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
this.callbackWeakReference = new WeakReference<>(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end,
|
||||
@Nullable Paint.FontMetricsInt fm) {
|
||||
return (int) (paint.getTextSize()*1.2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x,
|
||||
int top, int y, int bottom, @NonNull Paint paint) {
|
||||
if (imageDrawable == null) return;
|
||||
canvas.save();
|
||||
|
||||
int emojiSize = (int) (paint.getTextSize() * 1.1);
|
||||
imageDrawable.setBounds(0, 0, emojiSize, emojiSize);
|
||||
|
||||
int transY = bottom - imageDrawable.getBounds().bottom;
|
||||
transY -= paint.getFontMetricsInt().descent/2;
|
||||
canvas.translate(x, transY);
|
||||
imageDrawable.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||
// I hope using resources from application context is okay
|
||||
// It's probably better than keeping activity alive. My assumption is that resources are
|
||||
// only needed to look up the density which is really unlikely to change with
|
||||
// configuration
|
||||
imageDrawable = new BitmapDrawable(context.getResources(), bitmap);
|
||||
if (callbackWeakReference != null) {
|
||||
Callback cb = callbackWeakReference.get();
|
||||
if (cb != null) cb.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable errorDrawable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable placeHolderDrawable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.keylesspalace.tusky.adapter;
|
|||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
|
@ -19,7 +18,7 @@ import com.keylesspalace.tusky.R;
|
|||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomTabURLSpan;
|
||||
import com.keylesspalace.tusky.util.CustomURLSpan;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
@ -30,7 +29,6 @@ import java.util.Date;
|
|||
class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||
private TextView reblogs;
|
||||
private TextView favourites;
|
||||
private TextView application;
|
||||
private LinearLayout cardView;
|
||||
private LinearLayout cardInfo;
|
||||
private ImageView cardImage;
|
||||
|
@ -42,7 +40,6 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
super(view);
|
||||
reblogs = view.findViewById(R.id.status_reblogs);
|
||||
favourites = view.findViewById(R.id.status_favourites);
|
||||
application = view.findViewById(R.id.status_application);
|
||||
cardView = view.findViewById(R.id.card_view);
|
||||
cardInfo = view.findViewById(R.id.card_info);
|
||||
cardImage = view.findViewById(R.id.card_image);
|
||||
|
@ -51,36 +48,36 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
cardUrl = view.findViewById(R.id.card_link);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaPreviewHeight(Context context) {
|
||||
return context.getResources().getDimensionPixelSize(R.dimen.status_detail_media_preview_height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCreatedAt(@Nullable Date createdAt) {
|
||||
if (createdAt != null) {
|
||||
DateFormat dateFormat = android.text.format.DateFormat.getMediumDateFormat(
|
||||
timestamp.getContext());
|
||||
timestamp.setText(dateFormat.format(createdAt));
|
||||
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT);
|
||||
timestampInfo.setText(dateFormat.format(createdAt));
|
||||
} else {
|
||||
timestamp.setText("");
|
||||
timestampInfo.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
private void setApplication(@Nullable Status.Application app) {
|
||||
if (app == null) {
|
||||
application.setText("");
|
||||
} else if (app.website != null) {
|
||||
URLSpan span;
|
||||
Context context = application.getContext();
|
||||
boolean useCustomTabs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getBoolean("customTabs", true);
|
||||
if (useCustomTabs) {
|
||||
span = new CustomTabURLSpan(app.website);
|
||||
if (app != null) {
|
||||
|
||||
timestampInfo.append(" • ");
|
||||
|
||||
if (app.website != null) {
|
||||
URLSpan span = new CustomURLSpan(app.website);
|
||||
|
||||
SpannableStringBuilder text = new SpannableStringBuilder(app.name);
|
||||
text.setSpan(span, 0, app.name.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
timestampInfo.append(text);
|
||||
timestampInfo.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
} else {
|
||||
span = new URLSpan(app.website);
|
||||
timestampInfo.append(app.name);
|
||||
}
|
||||
SpannableStringBuilder text = new SpannableStringBuilder(app.name);
|
||||
text.setSpan(span, 0, app.name.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
application.setText(text);
|
||||
application.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
} else {
|
||||
application.setText(app.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,14 +31,12 @@ import com.varunest.sparkbutton.helpers.Utils;
|
|||
|
||||
public class StatusViewHolder extends StatusBaseViewHolder {
|
||||
private ImageView avatarReblog;
|
||||
private View rebloggedBar;
|
||||
private TextView rebloggedByDisplayName;
|
||||
private TextView rebloggedBar;
|
||||
|
||||
StatusViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
avatarReblog = itemView.findViewById(R.id.status_avatar_reblog);
|
||||
rebloggedBar = itemView.findViewById(R.id.status_reblogged_bar);
|
||||
rebloggedByDisplayName = itemView.findViewById(R.id.status_reblogged);
|
||||
rebloggedBar = itemView.findViewById(R.id.status_reblogged);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,6 +64,11 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMediaPreviewHeight(Context context) {
|
||||
return context.getResources().getDimensionPixelSize(R.dimen.status_media_preview_height);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled) {
|
||||
|
@ -90,10 +93,10 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
private void setRebloggedByDisplayName(String name) {
|
||||
Context context = rebloggedByDisplayName.getContext();
|
||||
Context context = rebloggedBar.getContext();
|
||||
String format = context.getString(R.string.status_boosted_format);
|
||||
String boostedText = String.format(format, name);
|
||||
rebloggedByDisplayName.setText(boostedText);
|
||||
rebloggedBar.setText(boostedText);
|
||||
rebloggedBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
|
@ -38,8 +37,6 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
private boolean mediaPreviewEnabled;
|
||||
private int detailedStatusPosition;
|
||||
|
||||
private Card detailedStatusCard;
|
||||
|
||||
public ThreadAdapter(StatusActionListener listener) {
|
||||
this.statusActionListener = listener;
|
||||
this.statuses = new ArrayList<>();
|
||||
|
@ -155,4 +152,8 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
detailedStatusPosition = position;
|
||||
}
|
||||
}
|
||||
|
||||
public int getDetailedStatusPosition() {
|
||||
return detailedStatusPosition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Tusky 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 Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.entity;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Attachment {
|
||||
public String id;
|
||||
|
||||
public String url;
|
||||
|
||||
@SerializedName("preview_url")
|
||||
public String previewUrl;
|
||||
|
||||
@SerializedName("text_url")
|
||||
public String textUrl;
|
||||
|
||||
public Type type;
|
||||
|
||||
public String description;
|
||||
|
||||
public static class Meta {
|
||||
public MediaProperties original;
|
||||
public MediaProperties small;
|
||||
}
|
||||
|
||||
public static class MediaProperties {
|
||||
public int width;
|
||||
public int height;
|
||||
public float aspect;
|
||||
}
|
||||
|
||||
@JsonAdapter(MediaTypeDeserializer.class)
|
||||
public enum Type {
|
||||
@SerializedName("image")
|
||||
IMAGE,
|
||||
@SerializedName("gifv")
|
||||
GIFV,
|
||||
@SerializedName("video")
|
||||
VIDEO,
|
||||
@SerializedName("unknown")
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
static class MediaTypeDeserializer implements JsonDeserializer<Type> {
|
||||
@Override
|
||||
public Type deserialize(JsonElement json, java.lang.reflect.Type classOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
switch(json.toString()) {
|
||||
case "\"image\"":
|
||||
return Type.IMAGE;
|
||||
case "\"gifv\"":
|
||||
return Type.GIFV;
|
||||
case "\"video\"":
|
||||
return Type.VIDEO;
|
||||
default:
|
||||
return Type.UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Tusky 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 Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.entity;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class Media {
|
||||
public String id;
|
||||
|
||||
public String type;
|
||||
|
||||
public String url;
|
||||
|
||||
@SerializedName("preview_url")
|
||||
public String previewUrl;
|
||||
|
||||
@SerializedName("text_url")
|
||||
public String textUrl;
|
||||
}
|
|
@ -17,10 +17,6 @@ package com.keylesspalace.tusky.entity;
|
|||
|
||||
import android.text.Spanned;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Date;
|
||||
|
@ -137,7 +133,7 @@ public class Status {
|
|||
}
|
||||
|
||||
@SerializedName("media_attachments")
|
||||
public MediaAttachment[] attachments;
|
||||
public Attachment[] attachments;
|
||||
|
||||
public Mention[] mentions;
|
||||
|
||||
|
@ -159,48 +155,6 @@ public class Status {
|
|||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
|
||||
public static class MediaAttachment {
|
||||
@com.google.gson.annotations.JsonAdapter(MediaTypeDeserializer.class)
|
||||
public enum Type {
|
||||
@SerializedName("image")
|
||||
IMAGE,
|
||||
@SerializedName("gifv")
|
||||
GIFV,
|
||||
@SerializedName("video")
|
||||
VIDEO,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
public String url;
|
||||
|
||||
@SerializedName("preview_url")
|
||||
public String previewUrl;
|
||||
|
||||
@SerializedName("text_url")
|
||||
public String textUrl;
|
||||
|
||||
@SerializedName("remote_url")
|
||||
public String remoteUrl;
|
||||
|
||||
public Type type;
|
||||
|
||||
static class MediaTypeDeserializer implements JsonDeserializer<Type> {
|
||||
@Override
|
||||
public Type deserialize(JsonElement json, java.lang.reflect.Type classOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
switch(json.toString()) {
|
||||
case "\"image\"":
|
||||
return Type.IMAGE;
|
||||
case "\"gifv\"":
|
||||
return Type.GIFV;
|
||||
case "\"video\"":
|
||||
return Type.VIDEO;
|
||||
default:
|
||||
return Type.UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mention {
|
||||
public String id;
|
||||
|
|
|
@ -34,6 +34,7 @@ import com.keylesspalace.tusky.BaseActivity
|
|||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.ViewMediaActivity
|
||||
import com.keylesspalace.tusky.ViewVideoActivity
|
||||
import com.keylesspalace.tusky.entity.Attachment
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.view.SquareImageView
|
||||
|
@ -86,7 +87,7 @@ class AccountMediaFragment : BaseFragment() {
|
|||
body?.let { fetched ->
|
||||
statuses.addAll(0, fetched)
|
||||
// flatMap requires iterable but I don't want to box each array into list
|
||||
val result = mutableListOf<Status.MediaAttachment>()
|
||||
val result = mutableListOf<Attachment>()
|
||||
for (status in fetched) {
|
||||
result.addAll(status.attachments)
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ class AccountMediaFragment : BaseFragment() {
|
|||
statuses.addAll(fetched)
|
||||
Log.d(TAG, "now there are ${statuses.size} statuses")
|
||||
// flatMap requires iterable but I don't want to box each array into list
|
||||
val result = mutableListOf<Status.MediaAttachment>()
|
||||
val result = mutableListOf<Attachment>()
|
||||
for (status in fetched) {
|
||||
result.addAll(status.attachments)
|
||||
}
|
||||
|
@ -190,12 +191,12 @@ class AccountMediaFragment : BaseFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun viewMedia(items: List<Status.MediaAttachment>, currentIndex: Int, view: View?) {
|
||||
private fun viewMedia(items: List<Attachment>, currentIndex: Int, view: View?) {
|
||||
val urls = items.map { it.url }.toTypedArray()
|
||||
val type = items[currentIndex].type
|
||||
|
||||
when (type) {
|
||||
Status.MediaAttachment.Type.IMAGE -> {
|
||||
Attachment.Type.IMAGE -> {
|
||||
val intent = Intent(context, ViewMediaActivity::class.java)
|
||||
intent.putExtra("urls", urls)
|
||||
intent.putExtra("urlIndex", currentIndex)
|
||||
|
@ -208,12 +209,12 @@ class AccountMediaFragment : BaseFragment() {
|
|||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
Status.MediaAttachment.Type.GIFV, Status.MediaAttachment.Type.VIDEO -> {
|
||||
Attachment.Type.GIFV, Attachment.Type.VIDEO -> {
|
||||
val intent = Intent(context, ViewVideoActivity::class.java)
|
||||
intent.putExtra("url", urls[currentIndex])
|
||||
startActivity(intent)
|
||||
}
|
||||
Status.MediaAttachment.Type.UNKNOWN, null -> {
|
||||
Attachment.Type.UNKNOWN, null -> {
|
||||
}/* Intentionally do nothing. This case is here is to handle when new attachment
|
||||
* types are added to the API before code is added here to handle them. So, the
|
||||
* best fallback is to just show the preview and ignore requests to view them. */
|
||||
|
@ -229,16 +230,16 @@ class AccountMediaFragment : BaseFragment() {
|
|||
|
||||
var baseItemColor = Color.BLACK
|
||||
|
||||
private val items = mutableListOf<Status.MediaAttachment>()
|
||||
private val items = mutableListOf<Attachment>()
|
||||
private val itemBgBaseHSV = FloatArray(3)
|
||||
private val random = Random()
|
||||
|
||||
fun addTop(newItems: List<Status.MediaAttachment>) {
|
||||
fun addTop(newItems: List<Attachment>) {
|
||||
items.addAll(0, newItems)
|
||||
notifyItemRangeInserted(0, newItems.size)
|
||||
}
|
||||
|
||||
fun addBottom(newItems: List<Status.MediaAttachment>) {
|
||||
fun addBottom(newItems: List<Attachment>) {
|
||||
if (newItems.isEmpty()) return
|
||||
|
||||
val oldLen = items.size
|
||||
|
|
|
@ -42,6 +42,7 @@ import com.keylesspalace.tusky.NotificationPullJobCreator;
|
|||
import com.keylesspalace.tusky.adapter.FooterViewHolder;
|
||||
import com.keylesspalace.tusky.adapter.NotificationsAdapter;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||
|
@ -108,6 +109,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
private int bottomFetches;
|
||||
private String bottomId;
|
||||
private String topId;
|
||||
private boolean alwaysShowSensitiveMedia;
|
||||
|
||||
// Each element is either a Notification for loading data or a Placeholder
|
||||
private final PairedList<Either<Placeholder, Notification>, NotificationViewData> notifications
|
||||
|
@ -116,7 +118,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
public NotificationViewData apply(Either<Placeholder, Notification> input) {
|
||||
if (input.isRight()) {
|
||||
Notification notification = input.getAsRight();
|
||||
return ViewDataUtils.notificationToViewData(notification);
|
||||
return ViewDataUtils.notificationToViewData(notification, alwaysShowSensitiveMedia);
|
||||
} else {
|
||||
return new NotificationViewData.Placeholder(false);
|
||||
}
|
||||
|
@ -155,6 +157,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
adapter = new NotificationsAdapter(this, this);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||
getActivity());
|
||||
alwaysShowSensitiveMedia = preferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
boolean mediaPreviewEnabled = preferences.getBoolean("mediaPreviewEnabled", true);
|
||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
@ -273,13 +276,19 @@ public class NotificationsFragment extends SFragment implements
|
|||
if (status.reblog != null) {
|
||||
status.reblog.reblogged = reblog;
|
||||
}
|
||||
// Java's type inference *eyeroll*
|
||||
notifications.set(position,
|
||||
Either.<Placeholder, Notification>right(notification));
|
||||
|
||||
adapter.updateItemWithNotify(position, notifications.getPairedItem(position), true);
|
||||
NotificationViewData.Concrete viewdata = (NotificationViewData.Concrete)notifications.getPairedItem(position);
|
||||
|
||||
adapter.notifyItemChanged(position);
|
||||
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData());
|
||||
viewDataBuilder.setReblogged(reblog);
|
||||
|
||||
NotificationViewData.Concrete newViewData = new NotificationViewData.Concrete(
|
||||
viewdata.getType(), viewdata.getId(), viewdata.getAccount(),
|
||||
viewDataBuilder.createStatusViewData(), viewdata.isExpanded());
|
||||
|
||||
notifications.setPairedItem(position, newViewData);
|
||||
|
||||
adapter.updateItemWithNotify(position, newViewData, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,12 +314,19 @@ public class NotificationsFragment extends SFragment implements
|
|||
status.reblog.favourited = favourite;
|
||||
}
|
||||
|
||||
notifications.set(position,
|
||||
Either.<Placeholder, Notification>right(notification));
|
||||
NotificationViewData.Concrete viewdata = (NotificationViewData.Concrete)notifications.getPairedItem(position);
|
||||
|
||||
adapter.updateItemWithNotify(position, notifications.getPairedItem(position), true);
|
||||
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData());
|
||||
viewDataBuilder.setFavourited(favourite);
|
||||
|
||||
NotificationViewData.Concrete newViewData = new NotificationViewData.Concrete(
|
||||
viewdata.getType(), viewdata.getId(), viewdata.getAccount(),
|
||||
viewDataBuilder.createStatusViewData(), viewdata.isExpanded());
|
||||
|
||||
notifications.setPairedItem(position, newViewData);
|
||||
|
||||
adapter.updateItemWithNotify(position, newViewData, true);
|
||||
|
||||
adapter.notifyItemChanged(position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,7 +344,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onViewMedia(String[] urls, int urlIndex, Status.MediaAttachment.Type type,
|
||||
public void onViewMedia(String[] urls, int urlIndex, Attachment.Type type,
|
||||
View view) {
|
||||
super.viewMedia(urls, urlIndex, type, view);
|
||||
}
|
||||
|
@ -354,7 +370,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
.setIsExpanded(expanded)
|
||||
.createStatusViewData();
|
||||
NotificationViewData notificationViewData = new NotificationViewData.Concrete(old.getType(),
|
||||
old.getId(), old.getAccount(), statusViewData);
|
||||
old.getId(), old.getAccount(), statusViewData, expanded);
|
||||
notifications.setPairedItem(position, notificationViewData);
|
||||
adapter.updateItemWithNotify(position, notificationViewData, false);
|
||||
}
|
||||
|
@ -368,7 +384,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
.setIsShowingSensitiveContent(isShowing)
|
||||
.createStatusViewData();
|
||||
NotificationViewData notificationViewData = new NotificationViewData.Concrete(old.getType(),
|
||||
old.getId(), old.getAccount(), statusViewData);
|
||||
old.getId(), old.getAccount(), statusViewData, old.isExpanded());
|
||||
notifications.setPairedItem(position, notificationViewData);
|
||||
adapter.updateItemWithNotify(position, notificationViewData, false);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import com.keylesspalace.tusky.ViewMediaActivity;
|
|||
import com.keylesspalace.tusky.ViewTagActivity;
|
||||
import com.keylesspalace.tusky.ViewThreadActivity;
|
||||
import com.keylesspalace.tusky.ViewVideoActivity;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Relationship;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.AdapterItemRemover;
|
||||
|
@ -259,7 +260,7 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
|
|||
popup.show();
|
||||
}
|
||||
|
||||
protected void viewMedia(String[] urls, int urlIndex, Status.MediaAttachment.Type type,
|
||||
protected void viewMedia(String[] urls, int urlIndex, Attachment.Type type,
|
||||
@Nullable View view) {
|
||||
switch (type) {
|
||||
case IMAGE: {
|
||||
|
|
|
@ -40,6 +40,7 @@ import com.keylesspalace.tusky.BuildConfig;
|
|||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.adapter.FooterViewHolder;
|
||||
import com.keylesspalace.tusky.adapter.TimelineAdapter;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
|
@ -108,13 +109,16 @@ public class TimelineFragment extends SFragment implements
|
|||
private String bottomId;
|
||||
@Nullable
|
||||
private String topId;
|
||||
|
||||
private boolean alwaysShowSensitiveMedia;
|
||||
|
||||
private PairedList<Either<Placeholder, Status>, StatusViewData> statuses =
|
||||
new PairedList<>(new Function<Either<Placeholder, Status>, StatusViewData>() {
|
||||
@Override
|
||||
public StatusViewData apply(Either<Placeholder, Status> input) {
|
||||
Status status = input.getAsRightOrNull();
|
||||
if (status != null) {
|
||||
return ViewDataUtils.statusToViewData(status);
|
||||
return ViewDataUtils.statusToViewData(status, alwaysShowSensitiveMedia);
|
||||
} else {
|
||||
return new StatusViewData.Placeholder(false);
|
||||
}
|
||||
|
@ -150,7 +154,7 @@ public class TimelineFragment extends SFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Bundle arguments = getArguments();
|
||||
kind = Kind.valueOf(arguments.getString(KIND_ARG));
|
||||
|
@ -179,6 +183,7 @@ public class TimelineFragment extends SFragment implements
|
|||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||
getActivity());
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
alwaysShowSensitiveMedia = preferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
boolean mediaPreviewEnabled = preferences.getBoolean("mediaPreviewEnabled", true);
|
||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
@ -402,7 +407,7 @@ public class TimelineFragment extends SFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onViewMedia(String[] urls, int urlIndex, Status.MediaAttachment.Type type,
|
||||
public void onViewMedia(String[] urls, int urlIndex, Attachment.Type type,
|
||||
View view) {
|
||||
super.viewMedia(urls, urlIndex, type, view);
|
||||
}
|
||||
|
@ -462,6 +467,10 @@ public class TimelineFragment extends SFragment implements
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "alwaysShowSensitiveMedia": {
|
||||
//it is ok if only newly loaded statuses are affected, no need to fully refresh
|
||||
alwaysShowSensitiveMedia = sharedPreferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
package com.keylesspalace.tusky.fragment;
|
||||
|
||||
import android.arch.core.util.Function;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -23,7 +24,6 @@ import android.preference.PreferenceManager;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
|
@ -37,6 +37,7 @@ import android.view.ViewGroup;
|
|||
import com.keylesspalace.tusky.BuildConfig;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.adapter.ThreadAdapter;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.entity.StatusContext;
|
||||
|
@ -66,11 +67,17 @@ public class ViewThreadFragment extends SFragment implements
|
|||
private String thisThreadsStatusId;
|
||||
private TimelineReceiver timelineReceiver;
|
||||
private Card card;
|
||||
private boolean alwaysShowSensitiveMedia;
|
||||
|
||||
private int statusIndex = 0;
|
||||
|
||||
private final PairedList<Status, StatusViewData.Concrete> statuses =
|
||||
new PairedList<>(ViewDataUtils.statusMapper());
|
||||
private PairedList<Status, StatusViewData.Concrete> statuses =
|
||||
new PairedList<>(new Function<Status, StatusViewData.Concrete>() {
|
||||
@Override
|
||||
public StatusViewData.Concrete apply(Status input) {
|
||||
return ViewDataUtils.statusToViewData(input, alwaysShowSensitiveMedia);
|
||||
}
|
||||
});
|
||||
|
||||
public static ViewThreadFragment newInstance(String id) {
|
||||
Bundle arguments = new Bundle();
|
||||
|
@ -82,7 +89,7 @@ public class ViewThreadFragment extends SFragment implements
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false);
|
||||
|
||||
|
@ -96,15 +103,19 @@ public class ViewThreadFragment extends SFragment implements
|
|||
recyclerView.setLayoutManager(layoutManager);
|
||||
DividerItemDecoration divider = new DividerItemDecoration(
|
||||
context, layoutManager.getOrientation());
|
||||
Drawable drawable = ThemeUtils.getDrawable(context, R.attr.status_divider_drawable,
|
||||
Drawable dividerDrawable = ThemeUtils.getDrawable(context, R.attr.status_divider_drawable,
|
||||
R.drawable.status_divider_dark);
|
||||
divider.setDrawable(drawable);
|
||||
divider.setDrawable(dividerDrawable);
|
||||
recyclerView.addItemDecoration(divider);
|
||||
|
||||
Drawable threadLineDrawable = ThemeUtils.getDrawable(context, R.attr.conversation_thread_line_drawable,
|
||||
R.drawable.conversation_thread_line_dark);
|
||||
recyclerView.addItemDecoration(new ConversationLineItemDecoration(context,
|
||||
ContextCompat.getDrawable(context, R.drawable.conversation_divider_dark)));
|
||||
threadLineDrawable));
|
||||
adapter = new ThreadAdapter(this);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||
getActivity());
|
||||
alwaysShowSensitiveMedia = preferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
boolean mediaPreviewEnabled = preferences.getBoolean("mediaPreviewEnabled", true);
|
||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
@ -157,10 +168,16 @@ public class ViewThreadFragment extends SFragment implements
|
|||
if (status.reblog != null) {
|
||||
status.reblog.reblogged = reblog;
|
||||
}
|
||||
// create new viewData as side effect
|
||||
statuses.set(position, status);
|
||||
|
||||
adapter.setItem(position, statuses.getPairedItem(position), true);
|
||||
StatusViewData.Concrete viewdata = statuses.getPairedItem(position);
|
||||
|
||||
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder((viewdata));
|
||||
viewDataBuilder.setReblogged(reblog);
|
||||
|
||||
StatusViewData.Concrete newViewData = viewDataBuilder.createStatusViewData();
|
||||
|
||||
statuses.setPairedItem(position, newViewData);
|
||||
adapter.setItem(position, newViewData, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,9 +201,16 @@ public class ViewThreadFragment extends SFragment implements
|
|||
if (status.reblog != null) {
|
||||
status.reblog.favourited = favourite;
|
||||
}
|
||||
// create new viewData as side effect
|
||||
statuses.set(position, status);
|
||||
adapter.setItem(position, statuses.getPairedItem(position), true);
|
||||
|
||||
StatusViewData.Concrete viewdata = statuses.getPairedItem(position);
|
||||
|
||||
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder((viewdata));
|
||||
viewDataBuilder.setFavourited(favourite);
|
||||
|
||||
StatusViewData.Concrete newViewData = viewDataBuilder.createStatusViewData();
|
||||
|
||||
statuses.setPairedItem(position, newViewData);
|
||||
adapter.setItem(position, newViewData, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +228,7 @@ public class ViewThreadFragment extends SFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onViewMedia(String[] urls, int urlIndex, Status.MediaAttachment.Type type,
|
||||
public void onViewMedia(String[] urls, int urlIndex, Attachment.Type type,
|
||||
View view) {
|
||||
super.viewMedia(urls, urlIndex, type, view);
|
||||
}
|
||||
|
@ -367,6 +391,7 @@ public class ViewThreadFragment extends SFragment implements
|
|||
public void onClick(View v) {
|
||||
sendThreadRequest(id);
|
||||
sendStatusRequest(id);
|
||||
sendCardRequest(id);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
|
@ -392,6 +417,7 @@ public class ViewThreadFragment extends SFragment implements
|
|||
.setCard(card)
|
||||
.createStatusViewData();
|
||||
}
|
||||
statuses.setPairedItem(i, viewData);
|
||||
adapter.addItem(i, viewData);
|
||||
return i;
|
||||
}
|
||||
|
@ -432,6 +458,8 @@ public class ViewThreadFragment extends SFragment implements
|
|||
viewData = new StatusViewData.Builder(viewData)
|
||||
.setCard(card)
|
||||
.createStatusViewData();
|
||||
statuses.setPairedItem(statusIndex, viewData);
|
||||
|
||||
}
|
||||
adapter.addItem(statusIndex, viewData);
|
||||
}
|
||||
|
|
|
@ -17,14 +17,14 @@ package com.keylesspalace.tusky.interfaces;
|
|||
|
||||
import android.view.View;
|
||||
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
|
||||
public interface StatusActionListener extends LinkListener {
|
||||
void onReply(int position);
|
||||
void onReblog(final boolean reblog, final int position);
|
||||
void onFavourite(final boolean favourite, final int position);
|
||||
void onMore(View view, final int position);
|
||||
void onViewMedia(String[] urls, int index, Status.MediaAttachment.Type type, View view);
|
||||
void onViewMedia(String[] urls, int index, Attachment.Type type, View view);
|
||||
void onViewThread(int position);
|
||||
void onOpenReblog(int position);
|
||||
void onExpandedChange(boolean expanded, int position);
|
||||
|
|
|
@ -20,8 +20,8 @@ import android.support.annotation.Nullable;
|
|||
import com.keylesspalace.tusky.entity.AccessToken;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.AppCredentials;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Media;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Profile;
|
||||
import com.keylesspalace.tusky.entity.Relationship;
|
||||
|
@ -80,7 +80,7 @@ public interface MastodonApi {
|
|||
|
||||
@Multipart
|
||||
@POST("api/v1/media")
|
||||
Call<Media> uploadMedia(@Part MultipartBody.Part file);
|
||||
Call<Attachment> uploadMedia(@Part MultipartBody.Part file);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("api/v1/statuses")
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Tusky 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 Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.SpannedString;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CustomEmojiHelper {
|
||||
|
||||
/**
|
||||
* replaces emoji shortcodes in a text with EmojiSpans
|
||||
* @param text the text containing custom emojis
|
||||
* @param emojis a list of the custom emojis
|
||||
* @param textView a reference to the textView the emojis will be shown in
|
||||
* @return the text with the shortcodes replaced by EmojiSpans
|
||||
*/
|
||||
public static Spanned emojifyText(Spanned text, List<Status.Emoji> emojis, final TextView textView) {
|
||||
|
||||
if (!emojis.isEmpty()) {
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(text);
|
||||
for (Status.Emoji emoji : emojis) {
|
||||
CharSequence pattern = new StringBuilder(":").append(emoji.getShortcode()).append(':');
|
||||
Matcher matcher = Pattern.compile(pattern.toString()).matcher(text);
|
||||
while (matcher.find()) {
|
||||
// We keep a span as a Picasso target, because Picasso keeps weak reference to
|
||||
// the target so an anonymous class would likely be garbage collected.
|
||||
EmojiSpan span = new EmojiSpan(textView);
|
||||
builder.setSpan(span, matcher.start(), matcher.end(), 0);
|
||||
Picasso.with(textView.getContext())
|
||||
.load(emoji.getUrl())
|
||||
.into(span);
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static Spanned emojifyString(String string, List<Status.Emoji> emojis, final TextView textView) {
|
||||
return emojifyText(new SpannedString(string), emojis, textView);
|
||||
}
|
||||
|
||||
|
||||
public static class EmojiSpan extends ReplacementSpan implements Target {
|
||||
|
||||
private @Nullable Drawable imageDrawable;
|
||||
private WeakReference<TextView> textViewWeakReference;
|
||||
|
||||
EmojiSpan(TextView textView) {
|
||||
this.textViewWeakReference = new WeakReference<>(textView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end,
|
||||
@Nullable Paint.FontMetricsInt fm) {
|
||||
|
||||
/* update FontMetricsInt or otherwise span does not get drawn when
|
||||
it covers the whole text */
|
||||
Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
|
||||
if (fm != null) {
|
||||
fm.top = metrics.top;
|
||||
fm.ascent = metrics.ascent;
|
||||
fm.descent = metrics.descent;
|
||||
fm.bottom = metrics.bottom;
|
||||
}
|
||||
|
||||
return (int) (paint.getTextSize()*1.2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x,
|
||||
int top, int y, int bottom, @NonNull Paint paint) {
|
||||
if (imageDrawable == null) return;
|
||||
canvas.save();
|
||||
|
||||
int emojiSize = (int) (paint.getTextSize() * 1.1);
|
||||
imageDrawable.setBounds(0, 0, emojiSize, emojiSize);
|
||||
|
||||
int transY = bottom - imageDrawable.getBounds().bottom;
|
||||
transY -= paint.getFontMetricsInt().descent/2;
|
||||
canvas.translate(x, transY);
|
||||
imageDrawable.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||
TextView textView = textViewWeakReference.get();
|
||||
if(textView != null) {
|
||||
imageDrawable = new BitmapDrawable(textView.getContext().getResources(), bitmap);
|
||||
textView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable errorDrawable) {}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable placeHolderDrawable) {}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.View;
|
||||
|
||||
public class CustomTabURLSpan extends URLSpan {
|
||||
public CustomTabURLSpan(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
private CustomTabURLSpan(Parcel src) {
|
||||
super(src);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<CustomTabURLSpan> CREATOR = new Parcelable.Creator<CustomTabURLSpan>() {
|
||||
|
||||
@Override
|
||||
public CustomTabURLSpan createFromParcel(Parcel source) {
|
||||
return new CustomTabURLSpan(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomTabURLSpan[] newArray(int size) {
|
||||
return new CustomTabURLSpan[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Uri uri = Uri.parse(getURL());
|
||||
LinkHelper.openLinkInCustomTab(uri, view.getContext());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.View;
|
||||
|
||||
public class CustomURLSpan extends URLSpan {
|
||||
public CustomURLSpan(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
private CustomURLSpan(Parcel src) {
|
||||
super(src);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<CustomURLSpan> CREATOR = new Parcelable.Creator<CustomURLSpan>() {
|
||||
|
||||
@Override
|
||||
public CustomURLSpan createFromParcel(Parcel source) {
|
||||
return new CustomURLSpan(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomURLSpan[] newArray(int size) {
|
||||
return new CustomURLSpan[size];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
LinkHelper.openLink(getURL(), view.getContext());
|
||||
}
|
||||
|
||||
@Override public void updateDrawState(TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import android.support.customtabs.CustomTabsIntent;
|
|||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.URLSpan;
|
||||
|
@ -63,12 +64,11 @@ public class LinkHelper {
|
|||
* @param view the returned text will be put in
|
||||
* @param content containing text with mentions, links, or hashtags
|
||||
* @param mentions any '@' mentions which are known to be in the content
|
||||
* @param useCustomTabs whether to use custom tabs when opening web links
|
||||
* @param listener to notify about particular spans that are clicked
|
||||
*/
|
||||
public static void setClickableText(TextView view, Spanned content,
|
||||
@Nullable Status.Mention[] mentions, boolean useCustomTabs,
|
||||
final LinkListener listener) {
|
||||
@Nullable Status.Mention[] mentions, final LinkListener listener) {
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(content);
|
||||
URLSpan[] urlSpans = content.getSpans(0, content.length(), URLSpan.class);
|
||||
for (URLSpan span : urlSpans) {
|
||||
|
@ -83,17 +83,21 @@ public class LinkHelper {
|
|||
public void onClick(View widget) {
|
||||
listener.onViewTag(tag);
|
||||
}
|
||||
@Override public void updateDrawState(TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
};
|
||||
builder.removeSpan(span);
|
||||
builder.setSpan(newSpan, start, end, flags);
|
||||
} else if (text.charAt(0) == '@' && mentions != null) {
|
||||
} else if (text.charAt(0) == '@' && mentions != null && mentions.length > 0) {
|
||||
String accountUsername = text.subSequence(1, text.length()).toString();
|
||||
/* There may be multiple matches for users on different instances with the same
|
||||
* username. If a match has the same domain we know it's for sure the same, but if
|
||||
* that can't be found then just go with whichever one matched last. */
|
||||
String id = null;
|
||||
for (Status.Mention mention : mentions) {
|
||||
if (mention.localUsername.equals(accountUsername)) {
|
||||
if (mention.localUsername.equalsIgnoreCase(accountUsername)) {
|
||||
id = mention.id;
|
||||
if (mention.url.contains(getDomain(span.getURL()))) {
|
||||
break;
|
||||
|
@ -107,12 +111,16 @@ public class LinkHelper {
|
|||
public void onClick(View widget) {
|
||||
listener.onViewAccount(accountId);
|
||||
}
|
||||
@Override public void updateDrawState(TextPaint ds) {
|
||||
super.updateDrawState(ds);
|
||||
ds.setUnderlineText(false);
|
||||
}
|
||||
};
|
||||
builder.removeSpan(span);
|
||||
builder.setSpan(newSpan, start, end, flags);
|
||||
}
|
||||
} else if (useCustomTabs) {
|
||||
ClickableSpan newSpan = new CustomTabURLSpan(span.getURL());
|
||||
} else {
|
||||
ClickableSpan newSpan = new CustomURLSpan(span.getURL());
|
||||
builder.removeSpan(span);
|
||||
builder.setSpan(newSpan, start, end, flags);
|
||||
}
|
||||
|
|
|
@ -85,9 +85,7 @@ public class OkHttpUtils {
|
|||
|
||||
@NonNull
|
||||
public static OkHttpClient getCompatibleClient() {
|
||||
OkHttpClient client = getCompatibleClientBuilder().build();
|
||||
Log.d(TAG, client.connectTimeoutMillis()+" "+client.readTimeoutMillis()+" "+client.writeTimeoutMillis());
|
||||
return client;
|
||||
return getCompatibleClientBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.arch.core.util.Function;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
|
@ -23,16 +22,14 @@ import com.keylesspalace.tusky.entity.Status;
|
|||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by charlag on 12/07/2017.
|
||||
*/
|
||||
|
||||
public final class ViewDataUtils {
|
||||
@Nullable
|
||||
public static StatusViewData.Concrete statusToViewData(@Nullable Status status) {
|
||||
public static StatusViewData.Concrete statusToViewData(@Nullable Status status,
|
||||
boolean alwaysShowSensitiveMedia) {
|
||||
if (status == null) return null;
|
||||
Status visibleStatus = status.reblog == null ? status : status.reblog;
|
||||
return new StatusViewData.Builder().setId(status.id)
|
||||
|
@ -51,6 +48,7 @@ public final class ViewDataUtils {
|
|||
.setNickname(visibleStatus.account.username)
|
||||
.setRebloggedAvatar(status.reblog == null ? null : status.account.avatar)
|
||||
.setSensitive(visibleStatus.sensitive)
|
||||
.setIsShowingSensitiveContent(alwaysShowSensitiveMedia || !visibleStatus.sensitive)
|
||||
.setSpoilerText(visibleStatus.spoilerText)
|
||||
.setRebloggedByUsername(status.reblog == null ? null : status.account.username)
|
||||
.setUserFullName(visibleStatus.account.getDisplayName())
|
||||
|
@ -62,37 +60,9 @@ public final class ViewDataUtils {
|
|||
.createStatusViewData();
|
||||
}
|
||||
|
||||
public static List<StatusViewData> statusListToViewDataList(List<Status> statuses) {
|
||||
List<StatusViewData> viewDatas = new ArrayList<>(statuses.size());
|
||||
for (Status s : statuses) {
|
||||
viewDatas.add(statusToViewData(s));
|
||||
}
|
||||
return viewDatas;
|
||||
}
|
||||
|
||||
public static Function<Status, StatusViewData.Concrete> statusMapper() {
|
||||
return statusMapper;
|
||||
}
|
||||
|
||||
public static NotificationViewData.Concrete notificationToViewData(Notification notification) {
|
||||
public static NotificationViewData.Concrete notificationToViewData(Notification notification, boolean alwaysShowSensitiveData) {
|
||||
return new NotificationViewData.Concrete(notification.type, notification.id, notification.account,
|
||||
statusToViewData(notification.status));
|
||||
statusToViewData(notification.status, alwaysShowSensitiveData), false);
|
||||
}
|
||||
|
||||
public static List<NotificationViewData> notificationListToViewDataList(
|
||||
List<Notification> notifications) {
|
||||
List<NotificationViewData> viewDatas = new ArrayList<>(notifications.size());
|
||||
for (Notification n : notifications) {
|
||||
viewDatas.add(notificationToViewData(n));
|
||||
}
|
||||
return viewDatas;
|
||||
}
|
||||
|
||||
private static final Function<Status, StatusViewData.Concrete> statusMapper =
|
||||
new Function<Status, StatusViewData.Concrete>() {
|
||||
@Override
|
||||
public StatusViewData.Concrete apply(Status input) {
|
||||
return ViewDataUtils.statusToViewData(input);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public class ConversationLineItemDecoration extends RecyclerView.ItemDecoration
|
|||
|
||||
int position = parent.getChildAdapterPosition(child);
|
||||
ThreadAdapter adapter = (ThreadAdapter) parent.getAdapter();
|
||||
|
||||
StatusViewData.Concrete current = adapter.getItem(position);
|
||||
int dividerTop, dividerBottom;
|
||||
if (current != null) {
|
||||
|
@ -59,25 +60,17 @@ public class ConversationLineItemDecoration extends RecyclerView.ItemDecoration
|
|||
dividerTop = child.getTop() + avatarMargin;
|
||||
}
|
||||
StatusViewData.Concrete below = adapter.getItem(position + 1);
|
||||
if (below != null && current.getId().equals(below.getInReplyToId())) {
|
||||
if (below != null && current.getId().equals(below.getInReplyToId()) &&
|
||||
adapter.getDetailedStatusPosition() != position) {
|
||||
dividerBottom = child.getBottom();
|
||||
} else {
|
||||
dividerBottom = child.getTop() + avatarMargin;
|
||||
}
|
||||
} else {
|
||||
dividerTop = child.getTop();
|
||||
if (i == 0) {
|
||||
dividerTop += avatarMargin;
|
||||
}
|
||||
if (i == childCount - 1) {
|
||||
dividerBottom = child.getTop() + avatarMargin;
|
||||
} else {
|
||||
dividerBottom = child.getBottom();
|
||||
}
|
||||
}
|
||||
|
||||
divider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
|
||||
divider.draw(c);
|
||||
divider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
|
||||
divider.draw(c);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,13 +38,15 @@ public abstract class NotificationViewData {
|
|||
private final String id;
|
||||
private final Account account;
|
||||
private final StatusViewData.Concrete statusViewData;
|
||||
private final boolean isExpanded;
|
||||
|
||||
public Concrete(Notification.Type type, String id, Account account,
|
||||
StatusViewData.Concrete statusViewData) {
|
||||
StatusViewData.Concrete statusViewData, boolean isExpanded) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.account = account;
|
||||
this.statusViewData = statusViewData;
|
||||
this.isExpanded = isExpanded;
|
||||
}
|
||||
|
||||
public Notification.Type getType() {
|
||||
|
@ -62,6 +64,10 @@ public abstract class NotificationViewData {
|
|||
public StatusViewData.Concrete getStatusViewData() {
|
||||
return statusViewData;
|
||||
}
|
||||
|
||||
public boolean isExpanded() {
|
||||
return isExpanded;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Placeholder extends NotificationViewData {
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.keylesspalace.tusky.viewdata;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.text.Spanned;
|
||||
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
|
||||
|
@ -45,14 +46,14 @@ public abstract class StatusViewData {
|
|||
@Nullable
|
||||
private final String spoilerText;
|
||||
private final Status.Visibility visibility;
|
||||
private final Status.MediaAttachment[] attachments;
|
||||
private final Attachment[] attachments;
|
||||
@Nullable
|
||||
private final String rebloggedByUsername;
|
||||
@Nullable
|
||||
private final String rebloggedAvatar;
|
||||
private final boolean isSensitive;
|
||||
private final boolean isExpanded;
|
||||
private final boolean isShowingSensitiveContent;
|
||||
private final boolean isShowingContent;
|
||||
private final String userFullName;
|
||||
private final String nickname;
|
||||
private final String avatar;
|
||||
|
@ -72,9 +73,9 @@ public abstract class StatusViewData {
|
|||
private final Card card;
|
||||
|
||||
public Concrete(String id, Spanned content, boolean reblogged, boolean favourited,
|
||||
@Nullable String spoilerText, Status.Visibility visibility, Status.MediaAttachment[] attachments,
|
||||
@Nullable String spoilerText, Status.Visibility visibility, Attachment[] attachments,
|
||||
@Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded,
|
||||
boolean isShowingSensitiveWarning, String userFullName, String nickname, String avatar,
|
||||
boolean isShowingContent, String userFullName, String nickname, String avatar,
|
||||
Date createdAt, String reblogsCount, String favouritesCount, @Nullable String inReplyToId,
|
||||
@Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled,
|
||||
Status.Application application, List<Status.Emoji> emojis, @Nullable Card card) {
|
||||
|
@ -89,7 +90,7 @@ public abstract class StatusViewData {
|
|||
this.rebloggedAvatar = rebloggedAvatar;
|
||||
this.isSensitive = sensitive;
|
||||
this.isExpanded = isExpanded;
|
||||
this.isShowingSensitiveContent = isShowingSensitiveWarning;
|
||||
this.isShowingContent = isShowingContent;
|
||||
this.userFullName = userFullName;
|
||||
this.nickname = nickname;
|
||||
this.avatar = avatar;
|
||||
|
@ -130,7 +131,7 @@ public abstract class StatusViewData {
|
|||
return visibility;
|
||||
}
|
||||
|
||||
public Status.MediaAttachment[] getAttachments() {
|
||||
public Attachment[] getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
|
@ -147,8 +148,8 @@ public abstract class StatusViewData {
|
|||
return isExpanded;
|
||||
}
|
||||
|
||||
public boolean isShowingSensitiveContent() {
|
||||
return isShowingSensitiveContent;
|
||||
public boolean isShowingContent() {
|
||||
return isShowingContent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -232,12 +233,12 @@ public abstract class StatusViewData {
|
|||
private boolean favourited;
|
||||
private String spoilerText;
|
||||
private Status.Visibility visibility;
|
||||
private Status.MediaAttachment[] attachments;
|
||||
private Attachment[] attachments;
|
||||
private String rebloggedByUsername;
|
||||
private String rebloggedAvatar;
|
||||
private boolean isSensitive;
|
||||
private boolean isExpanded;
|
||||
private boolean isShowingSensitiveContent;
|
||||
private boolean isShowingContent;
|
||||
private String userFullName;
|
||||
private String nickname;
|
||||
private String avatar;
|
||||
|
@ -267,7 +268,7 @@ public abstract class StatusViewData {
|
|||
rebloggedAvatar = viewData.rebloggedAvatar;
|
||||
isSensitive = viewData.isSensitive;
|
||||
isExpanded = viewData.isExpanded;
|
||||
isShowingSensitiveContent = viewData.isShowingSensitiveContent;
|
||||
isShowingContent = viewData.isShowingContent;
|
||||
userFullName = viewData.userFullName;
|
||||
nickname = viewData.nickname;
|
||||
avatar = viewData.avatar;
|
||||
|
@ -313,7 +314,7 @@ public abstract class StatusViewData {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setAttachments(Status.MediaAttachment[] attachments) {
|
||||
public Builder setAttachments(Attachment[] attachments) {
|
||||
this.attachments = attachments;
|
||||
return this;
|
||||
}
|
||||
|
@ -339,7 +340,7 @@ public abstract class StatusViewData {
|
|||
}
|
||||
|
||||
public Builder setIsShowingSensitiveContent(boolean isShowingSensitiveContent) {
|
||||
this.isShowingSensitiveContent = isShowingSensitiveContent;
|
||||
this.isShowingContent = isShowingSensitiveContent;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -414,7 +415,7 @@ public abstract class StatusViewData {
|
|||
|
||||
return new StatusViewData.Concrete(id, content, reblogged, favourited, spoilerText, visibility,
|
||||
attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
|
||||
isShowingSensitiveContent, userFullName, nickname, avatar, createdAt, reblogsCount,
|
||||
isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount,
|
||||
favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application,
|
||||
emojis, card);
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size android:width="2dp" />
|
||||
<solid android:color="@color/color_primary_dark_dark" />
|
||||
</shape>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size android:width="4dp" />
|
||||
<solid android:color="@color/status_divider_dark" />
|
||||
</shape>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size android:width="4dp" />
|
||||
<solid android:color="@color/status_divider_light" />
|
||||
</shape>
|
|
@ -1,9 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/status_favourite_button_dark"
|
||||
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/status_favourite_button_dark"
|
||||
android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/status_favourite_button_light"
|
||||
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/status_favourite_button_light"
|
||||
android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||
</vector>
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/toolbar_icon_dark"
|
||||
android:fillColor="@color/color_accent_dark"
|
||||
android:pathData="M15,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM6,10L6,7L4,7v3L1,10v2h3v3h2v-3h3v-2L6,10zM15,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="48dp"
|
||||
android:width="48dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:autoMirrored="true">
|
||||
<path android:fillColor="#FFF" android:pathData="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M10,16.5L16,12L10,7.5V16.5Z" />
|
||||
</vector>
|
8
app/src/main/res/drawable/ic_play_indicator_dark.xml
Normal file
8
app/src/main/res/drawable/ic_play_indicator_dark.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<vector android:height="48dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillAlpha="1" android:fillColor="#1a1c23"
|
||||
android:pathData="M21.282,12A9.282,9.282 0,0 1,12 21.282,9.282 9.282,0 0,1 2.718,12 9.282,9.282 0,0 1,12 2.718,9.282 9.282,0 0,1 21.282,12Z"
|
||||
android:strokeAlpha="1" android:strokeColor="#00000000"
|
||||
android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="8"/>
|
||||
<path android:fillAlpha="1" android:fillColor="#2b90d9" android:pathData="M10,16.5l6,-4.5 -6,-4.5v9zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||
</vector>
|
15
app/src/main/res/drawable/ic_play_indicator_light.xml
Normal file
15
app/src/main/res/drawable/ic_play_indicator_light.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#ffff"
|
||||
android:pathData="M21.282,12A9.282,9.282 0,0 1,12 21.282,9.282 9.282,0 0,1 2.718,12 9.282,9.282 0,0 1,12 2.718,9.282 9.282,0 0,1 21.282,12Z" />
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#2b90d9"
|
||||
android:pathData="M10,16.5l6,-4.5 -6,-4.5v9zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z" />
|
||||
</vector>
|
4
app/src/main/res/drawable/ic_reblog_dark_18dp.xml
Normal file
4
app/src/main/res/drawable/ic_reblog_dark_18dp.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="18dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#9baec8" android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/>
|
||||
</vector>
|
4
app/src/main/res/drawable/ic_reblog_light_18dp.xml
Normal file
4
app/src/main/res/drawable/ic_reblog_light_18dp.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="18dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#5f636f" android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/>
|
||||
</vector>
|
|
@ -1,10 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:autoMirrored="true">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="@color/toolbar_icon_dark"
|
||||
android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z"/>
|
||||
android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z" />
|
||||
</vector>
|
||||
|
|
10
app/src/main/res/drawable/ic_reply_all_24dp.xml
Normal file
10
app/src/main/res/drawable/ic_reply_all_24dp.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="@color/toolbar_icon_dark"
|
||||
android:pathData="M7,8L7,5l-7,7 7,7v-3l-4,-4 4,-4zM13,9L13,5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z" />
|
||||
</vector>
|
|
@ -132,36 +132,36 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/account_note"
|
||||
tools:text="3000 Followers"
|
||||
android:background="@android:color/transparent"
|
||||
android:textColor="@color/account_tab_font_color"
|
||||
app:layout_constraintHorizontal_bias="0"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/account_note"
|
||||
tools:text="3000 Followers" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/following_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/account_tab_font_color"
|
||||
app:layout_constraintBottom_toBottomOf="@id/followers_tv"
|
||||
app:layout_constraintEnd_toStartOf="@id/statuses_btn"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toEndOf="@id/followers_tv"
|
||||
app:layout_constraintTop_toTopOf="@id/followers_tv"
|
||||
tools:text="500 Following"
|
||||
android:textColor="@color/account_tab_font_color" />
|
||||
tools:text="500 Following" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statuses_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toEndOf="@id/following_tv"
|
||||
android:textColor="@color/account_tab_font_color"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/followers_tv"
|
||||
tools:text="3000 Posts"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
android:textColor="@color/account_tab_font_color"/>
|
||||
app:layout_constraintStart_toEndOf="@id/following_tv"
|
||||
app:layout_constraintTop_toTopOf="@id/followers_tv"
|
||||
tools:text="3000 Posts" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
|
@ -192,7 +192,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
app:tabSelectedTextColor="?attr/colorAccent" >
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabSelectedTextColor="?attr/colorAccent">
|
||||
|
||||
<android.support.design.widget.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -89,7 +89,8 @@
|
|||
android:ems="10"
|
||||
android:gravity="start|top"
|
||||
android:hint="@string/hint_compose"
|
||||
android:inputType="text|textMultiLine|textCapSentences" />
|
||||
android:inputType="text|textMultiLine|textCapSentences"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -1,87 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
* This is the for follow notifications, the layout for the follows/following listings on account
|
||||
* pages are instead in item_account.xml.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="10dp"
|
||||
android:orientation="vertical">
|
||||
android:paddingLeft="14dp"
|
||||
android:paddingRight="14dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:id="@+id/notification_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_height="wrap_content">
|
||||
android:drawableLeft="@drawable/ic_person_add_24dp"
|
||||
android:drawablePadding="10dp"
|
||||
android:drawableStart="@drawable/ic_person_add_24dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="28dp"
|
||||
android:paddingStart="28dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="Someone followed you" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/follow_icon"
|
||||
app:srcCompat="@drawable/ic_person_add_24dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:contentDescription="@null" />
|
||||
<ImageView
|
||||
android:id="@+id/notification_avatar"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/notification_text"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:scaleType="fitCenter" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:layout_centerVertical="true"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_toEndOf="@id/follow_icon"
|
||||
android:layout_toRightOf="@id/follow_icon" />
|
||||
<TextView
|
||||
android:id="@+id/notification_display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/notification_text"
|
||||
android:layout_toEndOf="@id/notification_avatar"
|
||||
android:layout_toRightOf="@id/notification_avatar"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal|bold"
|
||||
tools:text="Test User" />
|
||||
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/notification_username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/notification_display_name"
|
||||
android:layout_toEndOf="@id/notification_avatar"
|
||||
android:layout_toRightOf="@id/notification_avatar"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="\@testuser" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:id="@+id/notification_avatar"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:contentDescription="@string/action_view_profile" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_toEndOf="@id/notification_avatar"
|
||||
android:layout_toRightOf="@id/notification_avatar">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/notification_display_name"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal|bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/notification_username"
|
||||
android:textColor="?android:textColorSecondary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
|
@ -5,48 +5,31 @@
|
|||
android:id="@+id/status_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
android:paddingLeft="14dp"
|
||||
android:paddingRight="14dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/status_reblogged_bar"
|
||||
<TextView
|
||||
android:id="@+id/status_reblogged"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="@dimen/status_reblogged_bar_top_padding"
|
||||
android:drawableLeft="?attr/status_reblog_small_drawable"
|
||||
android:drawablePadding="6dp"
|
||||
android:drawableStart="?attr/status_reblog_small_drawable"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_reblogged_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingStart="24dp"
|
||||
android:tint="?android:textColorTertiary"
|
||||
app:srcCompat="@drawable/ic_repeat_24dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_reblogged"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorTertiary" />
|
||||
|
||||
</LinearLayout>
|
||||
android:paddingLeft="38dp"
|
||||
android:paddingStart="38dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="ConnyDuck boosted" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_below="@+id/status_reblogged_bar"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_below="@+id/status_reblogged"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@drawable/avatar_default" />
|
||||
|
@ -67,54 +50,51 @@
|
|||
android:id="@+id/status_name_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/status_reblogged_bar"
|
||||
android:layout_below="@+id/status_reblogged"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="@dimen/status_avatar_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_timestamp"
|
||||
android:id="@+id/status_display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="@dimen/status_display_name_right_padding"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="@dimen/status_display_name_right_padding"
|
||||
android:paddingStart="0dp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal|bold"
|
||||
tools:text="Ente" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/status_display_name"
|
||||
android:layout_toLeftOf="@+id/status_timestamp_info"
|
||||
android:layout_toRightOf="@id/status_display_name"
|
||||
android:layout_toStartOf="@+id/status_timestamp_info"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="\@Entenhausen" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_timestamp_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="?android:textColorSecondary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/status_timestamp"
|
||||
android:layout_toStartOf="@id/status_timestamp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="@dimen/status_display_name_right_padding"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="@dimen/status_display_name_right_padding"
|
||||
android:paddingStart="0dp"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal|bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary" />
|
||||
|
||||
</LinearLayout>
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="13:37" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -134,6 +114,7 @@
|
|||
android:id="@+id/status_content_warning_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
|
||||
<ToggleButton
|
||||
|
@ -166,163 +147,177 @@
|
|||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:focusable="true"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
tools:text="This is a status" />
|
||||
|
||||
<FrameLayout
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:id="@+id/status_media_preview_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/status_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginTop="4dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status_media_preview_0"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status_media_preview_1"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_0"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_1"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_2"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_3"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_sensitive_media_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:alpha="0.7"
|
||||
android:contentDescription="@null"
|
||||
android:padding="@dimen/status_sensitive_media_button_padding"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/status_media_preview_container"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_container"
|
||||
app:srcCompat="@drawable/ic_remove_red_eye_black_24dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_0"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:layout_marginRight="2dp"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:layout_marginRight="2dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_video_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:alpha="0.5"
|
||||
android:contentDescription="@null"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_play_48dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_sensitive_media_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:alpha="0.7"
|
||||
android:contentDescription="@null"
|
||||
android:padding="@dimen/status_sensitive_media_button_padding"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_remove_red_eye_black_24dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:id="@+id/status_sensitive_media_warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/sensitive_media_warning_background_color"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/status_sensitive_media_title"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/status_sensitive_media_directions"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_media_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/status_media_preview_container"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="2dp">
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/status_reply"
|
||||
style="?attr/image_button_style"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_reply"
|
||||
android:padding="4dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
app:srcCompat="@drawable/ic_reply_24dp" />
|
||||
|
||||
<Space
|
||||
|
@ -332,14 +327,12 @@
|
|||
|
||||
<com.varunest.sparkbutton.SparkButton
|
||||
android:id="@+id/status_reblog"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:clipToPadding="false"
|
||||
android:contentDescription="@string/action_reblog"
|
||||
android:padding="4dp"
|
||||
app:sparkbutton_activeImage="@drawable/reblog_active"
|
||||
app:sparkbutton_iconSize="28dp"
|
||||
app:sparkbutton_iconSize="24dp"
|
||||
app:sparkbutton_inActiveImage="?attr/status_reblog_inactive_drawable"
|
||||
app:sparkbutton_primaryColor="@color/status_reblog_button_marked_dark"
|
||||
app:sparkbutton_secondaryColor="@color/status_reblog_button_marked_light" />
|
||||
|
@ -351,14 +344,12 @@
|
|||
|
||||
<com.varunest.sparkbutton.SparkButton
|
||||
android:id="@+id/status_favourite"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
android:clipToPadding="false"
|
||||
android:contentDescription="@string/action_favourite"
|
||||
android:padding="4dp"
|
||||
app:sparkbutton_activeImage="?attr/status_favourite_active_drawable"
|
||||
app:sparkbutton_iconSize="28dp"
|
||||
app:sparkbutton_iconSize="24dp"
|
||||
app:sparkbutton_inActiveImage="?attr/status_favourite_inactive_drawable"
|
||||
app:sparkbutton_primaryColor="@color/status_favourite_button_marked_dark"
|
||||
app:sparkbutton_secondaryColor="@color/status_favourite_button_marked_light" />
|
||||
|
@ -371,17 +362,14 @@
|
|||
<ImageButton
|
||||
android:id="@+id/status_more"
|
||||
style="?attr/image_button_style"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_more"
|
||||
android:padding="4dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
app:srcCompat="@drawable/ic_more_horiz_24dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
|
@ -5,16 +5,16 @@
|
|||
android:id="@+id/status_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
android:paddingLeft="14dp"
|
||||
android:paddingRight="14dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:scaleType="fitCenter"
|
||||
tools:src="@drawable/avatar_default" />
|
||||
|
@ -22,11 +22,12 @@
|
|||
<LinearLayout
|
||||
android:id="@+id/status_name_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
|
@ -35,22 +36,19 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal|bold" />
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
android:textStyle="normal|bold"
|
||||
tools:text="Display Name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary" />
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="\@ConnyDuck\@mastodon.social" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -60,8 +58,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/status_name_bar"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:focusable="true"
|
||||
android:visibility="gone"
|
||||
app:paddingHorizontal="4dp">
|
||||
|
@ -70,7 +66,7 @@
|
|||
android:id="@+id/status_content_warning_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
|
||||
<ToggleButton
|
||||
|
@ -94,14 +90,10 @@
|
|||
android:id="@+id/status_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_below="@+id/status_content_warning_bar"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:focusable="true"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -110,8 +102,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/status_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar"
|
||||
android:background="?attr/card_background"
|
||||
android:clipChildren="true"
|
||||
android:orientation="vertical">
|
||||
|
@ -161,184 +151,171 @@
|
|||
android:textColor="?android:textColorTertiary" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:id="@+id/status_media_preview_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/card_view"
|
||||
android:layout_toEndOf="@+id/status_avatar"
|
||||
android:layout_toRightOf="@+id/status_avatar">
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginTop="4dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toStartOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status_media_preview_0"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status_media_preview_1"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_0"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_0"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_1"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_1"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_2"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_2"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_overlay_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scaleType="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintEnd_toEndOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintStart_toStartOf="@+id/status_media_preview_3"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_3"
|
||||
app:srcCompat="?attr/play_indicator_drawable"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_sensitive_media_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:alpha="0.7"
|
||||
android:contentDescription="@string/action_hide_media"
|
||||
android:padding="@dimen/status_sensitive_media_button_padding"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/status_media_preview_container"
|
||||
app:layout_constraintTop_toTopOf="@+id/status_media_preview_container"
|
||||
app:srcCompat="@drawable/ic_remove_red_eye_black_24dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_0"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:layout_marginRight="2dp"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:layout_marginRight="2dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_media_preview_3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/status_media_preview_height"
|
||||
android:layout_marginLeft="2dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/action_view_media"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_video_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:alpha="0.5"
|
||||
android:contentDescription="@null"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_play_48dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_sensitive_media_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:alpha="0.7"
|
||||
android:contentDescription="@null"
|
||||
android:padding="@dimen/status_sensitive_media_button_padding"
|
||||
android:visibility="gone"
|
||||
app:srcCompat="@drawable/ic_remove_red_eye_black_24dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:id="@+id/status_sensitive_media_warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/status_media_preview_top_margin"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?attr/sensitive_media_warning_background_color"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/status_sensitive_media_title"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/status_sensitive_media_directions"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
</LinearLayout>
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_media_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:includeFontPadding="false"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/status_info_bar"
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:id="@+id/status_timestamp_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/status_media_preview_container"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_toEndOf="@id/status_avatar"
|
||||
android:layout_toRightOf="@id/status_avatar"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_timestamp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:textColorTertiary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_application"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
</LinearLayout>
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textColor="?android:textColorTertiary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/status_info_bar"
|
||||
android:layout_toEndOf="@id/status_avatar"
|
||||
android:layout_toRightOf="@id/status_avatar"
|
||||
android:layout_below="@id/status_timestamp_info"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="2dp">
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="4dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/status_reply"
|
||||
|
@ -409,11 +386,6 @@
|
|||
android:padding="4dp"
|
||||
app:srcCompat="@drawable/ic_more_horiz_24dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
|
@ -6,37 +6,74 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
android:paddingLeft="14dp"
|
||||
android:paddingRight="14dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_top_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="8dp"
|
||||
android:drawablePadding="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="28dp"
|
||||
android:paddingStart="28dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="Someone favourited your status" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/notification_top_bar"
|
||||
android:id="@+id/status_name_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notification_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingStart="24dp"
|
||||
app:srcCompat="@drawable/ic_repeat_24dp" />
|
||||
android:layout_below="@+id/notification_top_text"
|
||||
android:layout_toEndOf="@+id/notification_status_avatar"
|
||||
android:layout_toRightOf="@+id/notification_status_avatar"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingTop="6dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_text"
|
||||
android:id="@+id/status_display_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/notification_icon"
|
||||
android:layout_toRightOf="@id/notification_icon"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="Someone favourited your status" />
|
||||
android:paddingEnd="@dimen/status_display_name_right_padding"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="@dimen/status_display_name_right_padding"
|
||||
android:paddingStart="0dp"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textStyle="normal|bold"
|
||||
tools:text="Ente" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/status_display_name"
|
||||
android:layout_toLeftOf="@+id/status_timestamp_info"
|
||||
android:layout_toRightOf="@id/status_display_name"
|
||||
android:layout_toStartOf="@+id/status_timestamp_info"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="\@Entenhausen" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_timestamp_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="13:37" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -44,7 +81,7 @@
|
|||
android:id="@+id/notification_content_warning_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/notification_top_bar"
|
||||
android:layout_below="@+id/status_name_bar"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_toEndOf="@+id/notification_status_avatar"
|
||||
android:layout_toRightOf="@+id/notification_status_avatar"
|
||||
|
@ -57,8 +94,9 @@
|
|||
android:id="@+id/notification_content_warning_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="Example CW text"/>
|
||||
tools:text="Example CW text" />
|
||||
|
||||
<ToggleButton
|
||||
android:id="@+id/notification_content_warning_button"
|
||||
|
@ -84,11 +122,10 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/notification_content_warning_bar"
|
||||
android:layout_toEndOf="@+id/notification_status_avatar"
|
||||
android:layout_toRightOf="@+id/notification_status_avatar"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingLeft="58dp"
|
||||
android:paddingRight="0dp"
|
||||
android:paddingStart="58dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
tools:text="Example status here" />
|
||||
|
||||
|
@ -96,11 +133,11 @@
|
|||
android:id="@+id/notification_status_avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_below="@id/notification_top_bar"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_below="@id/notification_top_text"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:paddingBottom="12dp"
|
||||
android:paddingRight="12dp"
|
||||
|
@ -114,9 +151,6 @@
|
|||
android:layout_height="24dp"
|
||||
android:layout_alignBottom="@+id/notification_status_avatar"
|
||||
android:layout_alignEnd="@id/notification_status_avatar"
|
||||
android:layout_alignRight="@id/notification_status_avatar"
|
||||
android:visibility="gone"
|
||||
tools:src="@color/accent"
|
||||
tools:visibility="visible" />
|
||||
android:layout_alignRight="@id/notification_status_avatar" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -33,8 +33,8 @@
|
|||
|
||||
<string name="status_username_format">\@%s</string>
|
||||
<string name="status_boosted_format">%s teilte</string>
|
||||
<string name="status_sensitive_media_title">Sensible Medien</string>
|
||||
<string name="status_sensitive_media_directions">Tippe um zu zeigen</string>
|
||||
<string name="status_sensitive_media_title">Heikle Inhalte</string>
|
||||
<string name="status_sensitive_media_directions">Zum Anzeigen tippen</string>
|
||||
<string name="status_content_warning_show_more">Zeige mehr</string>
|
||||
<string name="status_content_warning_show_less">Zeige weniger</string>
|
||||
|
||||
|
|
|
@ -36,8 +36,7 @@
|
|||
|
||||
<string name="status_username_format">\@%s</string>
|
||||
<string name="status_boosted_format">%s podbił</string>
|
||||
<string name="status_sensitive_media_title">Wrażliwe treści</string>
|
||||
<string name="status_sensitive_media_directions">Dotknij, aby wyświetlić</string>
|
||||
<string name="status_sensitive_media_title"><b>Wrażliwe treści</b>\nDotknij, aby wyświetlić</string>
|
||||
<string name="status_content_warning_show_more">Pokaż więcej</string>
|
||||
<string name="status_content_warning_show_less">Ukryj</string>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<attr name="toolbar_background_color" format="reference" />
|
||||
<attr name="toolbar_icon_tint" format="reference" />
|
||||
<attr name="image_button_style" format="reference" />
|
||||
<attr name="status_reblog_small_drawable" format="reference" />
|
||||
<attr name="status_reblog_inactive_drawable" format="reference" />
|
||||
<attr name="status_reblog_disabled_drawable" format="reference" />
|
||||
<attr name="status_reblog_direct_drawable" format="reference" />
|
||||
|
@ -23,6 +24,7 @@
|
|||
<attr name="sensitive_media_warning_background_color" format="reference|color" />
|
||||
<attr name="media_preview_unloaded_drawable" format="reference" />
|
||||
<attr name="status_divider_drawable" format="reference" />
|
||||
<attr name="conversation_thread_line_drawable" format="reference" />
|
||||
<attr name="tab_icon_selected_tint" format="reference|color" />
|
||||
<attr name="tab_page_margin_drawable" format="reference" />
|
||||
<attr name="account_header_background_color" format="reference|color" />
|
||||
|
@ -43,4 +45,6 @@
|
|||
<attr name="card_background" format="reference|color" />
|
||||
<attr name="card_image_background" format="reference|color" />
|
||||
|
||||
<attr name="play_indicator_drawable" format="reference" />
|
||||
|
||||
</resources>
|
|
@ -1,11 +1,12 @@
|
|||
<resources>
|
||||
<dimen name="status_display_name_right_padding">4dp</dimen>
|
||||
<dimen name="status_username_right_padding">4dp</dimen>
|
||||
<dimen name="status_avatar_padding">8dp</dimen>
|
||||
<dimen name="status_avatar_padding">10dp</dimen>
|
||||
<dimen name="status_reblogged_bar_top_padding">8dp</dimen>
|
||||
<dimen name="status_reblogged_icon_left_padding">40dp</dimen>
|
||||
<dimen name="status_media_preview_top_margin">4dp</dimen>
|
||||
<dimen name="status_media_preview_height">96dp</dimen>
|
||||
<dimen name="status_media_preview_height">100dp</dimen>
|
||||
<dimen name="status_detail_media_preview_height">130dp</dimen>
|
||||
<dimen name="footer_text_padding">8dp</dimen>
|
||||
<dimen name="compose_media_preview_margin">8dp</dimen>
|
||||
<dimen name="compose_media_preview_margin_bottom">0dp</dimen>
|
||||
|
@ -16,9 +17,9 @@
|
|||
<dimen name="notification_avatar_column_width">64dp</dimen>
|
||||
<dimen name="follow_icon_left_padding">40dp</dimen>
|
||||
<dimen name="account_note_margin">8dp</dimen>
|
||||
<dimen name="account_avatar_margin">8dp</dimen>
|
||||
<dimen name="account_avatar_margin">14dp</dimen>
|
||||
<dimen name="tab_page_margin">8dp</dimen>
|
||||
<dimen name="status_left_line_margin">38dp</dimen>
|
||||
<dimen name="status_left_line_margin">36dp</dimen>
|
||||
<dimen name="text_content_margin">16dp</dimen>
|
||||
<dimen name="status_sensitive_media_button_padding">5dp</dimen>
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
<string name="oauth_redirect_host" translatable="false">com.keylesspalace.tusky</string>
|
||||
<string name="preferences_file_key" translatable="false">com.keylesspalace.tusky.PREFERENCES</string>
|
||||
|
||||
<string name="status_sensitive_media_template"><b>%1$s</b><br>%2$s</string>
|
||||
|
||||
<string-array name="pull_notification_check_intervals" inputType="integer">
|
||||
<item>15</item>
|
||||
<item>20</item>
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
|
||||
<string name="status_username_format">\@%s</string>
|
||||
<string name="status_boosted_format">%s boosted</string>
|
||||
<string name="status_sensitive_media_title">Sensitive Media</string>
|
||||
<string name="status_sensitive_media_title">Sensitive content</string>
|
||||
<string name="status_media_hidden_title">Media hidden</string>
|
||||
<string name="status_sensitive_media_directions">Click to view</string>
|
||||
<string name="status_content_warning_show_more">Show More</string>
|
||||
<string name="status_content_warning_show_less">Show Less</string>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<!--Base Application Theme Styles (Dark)-->
|
||||
|
||||
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="colorPrimary">@color/color_primary_dark</item>
|
||||
<item name="colorPrimaryDark">@color/color_primary_dark_dark</item>
|
||||
<item name="colorAccent">@color/color_accent_dark</item>
|
||||
|
@ -40,6 +41,7 @@
|
|||
<item name="toolbar_background_color">@color/toolbar_background_dark</item>
|
||||
<item name="toolbar_icon_tint">@color/toolbar_icon_dark</item>
|
||||
<item name="image_button_style">@style/AppTheme.ImageButton.Dark</item>
|
||||
<item name="status_reblog_small_drawable">@drawable/ic_reblog_dark_18dp</item>
|
||||
<item name="status_reblog_inactive_drawable">@drawable/reblog_inactive_dark</item>
|
||||
<item name="status_reblog_disabled_drawable">@drawable/reblog_disabled_dark</item>
|
||||
<item name="status_reblog_direct_drawable">@drawable/reblog_direct_dark</item>
|
||||
|
@ -49,6 +51,7 @@
|
|||
<item name="sensitive_media_warning_background_color">@color/color_background_dark</item>
|
||||
<item name="media_preview_unloaded_drawable">@drawable/media_preview_unloaded_dark</item>
|
||||
<item name="status_divider_drawable">@drawable/status_divider_dark</item>
|
||||
<item name="conversation_thread_line_drawable">@drawable/conversation_thread_line_dark</item>
|
||||
<item name="tab_icon_selected_tint">@color/color_accent_dark</item>
|
||||
<item name="tab_page_margin_drawable">@drawable/tab_page_margin_dark</item>
|
||||
<item name="account_header_background_color">@color/account_header_background_dark</item>
|
||||
|
@ -81,6 +84,8 @@
|
|||
<item name="card_background">@drawable/card_frame_dark</item>
|
||||
<item name="card_image_background">@color/text_color_tertiary_dark</item>
|
||||
|
||||
<item name="play_indicator_drawable">@drawable/ic_play_indicator_dark</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.ImageButton.Dark" parent="@style/Widget.AppCompat.Button.Borderless.Colored">
|
||||
|
@ -101,6 +106,8 @@
|
|||
<!--Light Application Theme Styles-->
|
||||
|
||||
<style name="AppTheme.Light" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:textSize">15sp</item>
|
||||
|
||||
<item name="colorPrimary">@color/color_primary_light</item>
|
||||
<item name="colorPrimaryDark">@color/color_primary_dark_light</item>
|
||||
<item name="colorAccent">@color/color_accent_light</item>
|
||||
|
@ -122,6 +129,7 @@
|
|||
<item name="toolbar_background_color">@color/toolbar_background_light</item>
|
||||
<item name="toolbar_icon_tint">@color/toolbar_icon_light</item>
|
||||
<item name="image_button_style">@style/AppTheme.ImageButton.Light</item>
|
||||
<item name="status_reblog_small_drawable">@drawable/ic_reblog_light_18dp</item>
|
||||
<item name="status_reblog_inactive_drawable">@drawable/reblog_inactive_light</item>
|
||||
<item name="status_reblog_disabled_drawable">@drawable/reblog_disabled_light</item>
|
||||
<item name="status_reblog_direct_drawable">@drawable/reblog_direct_light</item>
|
||||
|
@ -131,6 +139,7 @@
|
|||
<item name="sensitive_media_warning_background_color">@color/sensitive_media_warning_background_light</item>
|
||||
<item name="media_preview_unloaded_drawable">@drawable/media_preview_unloaded_light</item>
|
||||
<item name="status_divider_drawable">@drawable/status_divider_light</item>
|
||||
<item name="conversation_thread_line_drawable">@drawable/conversation_thread_line_light</item>
|
||||
<item name="tab_icon_selected_tint">@color/color_accent_light</item>
|
||||
<item name="tab_page_margin_drawable">@drawable/tab_page_margin_light</item>
|
||||
<item name="account_header_background_color">@color/account_header_background_light</item>
|
||||
|
@ -163,6 +172,8 @@
|
|||
<item name="card_background">@drawable/card_frame_light</item>
|
||||
<item name="card_image_background">@color/text_color_tertiary_light</item>
|
||||
|
||||
<item name="play_indicator_drawable">@drawable/ic_play_indicator_light</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.ImageButton.Light" parent="Widget.AppCompat.Button.Borderless.Colored">
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:dependency="mediaPreviewEnabled"
|
||||
android:key="alwaysShowSensitiveMedia"
|
||||
android:title="@string/pref_title_alway_show_sensitive_media" />
|
||||
|
||||
|
|
Loading…
Reference in a new issue