From 112701dd866a68694f376b0dd7f6f50c2cb8594a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 31 Dec 2022 14:59:23 +0100 Subject: [PATCH 01/68] Improve interactions --- .../android/client/entities/api/Account.java | 6 +- .../client/entities/api/Announcement.java | 2 +- .../android/client/entities/api/Field.java | 4 +- .../android/client/entities/api/Poll.java | 2 +- .../android/client/entities/api/Status.java | 6 +- .../android/helper/SpannableHelper.java | 1019 +++++------------ 6 files changed, 297 insertions(+), 742 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java index 9c423554c..6631be8fd 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java @@ -115,7 +115,7 @@ public class Account implements Serializable { if (display_name == null || display_name.isEmpty()) { display_name = username; } - return SpannableHelper.convert(context, display_name, null, this, null, false, false, viewWeakReference); + return SpannableHelper.convert(context, display_name, null, this, null, viewWeakReference); } public synchronized Spannable getSpanDisplayName(Activity activity, WeakReference viewWeakReference) { @@ -126,11 +126,11 @@ public class Account implements Serializable { } public synchronized Spannable getSpanDisplayNameTitle(Context context, WeakReference viewWeakReference, String title) { - return SpannableHelper.convert(context, title, null, this, null, false, false, viewWeakReference); + return SpannableHelper.convert(context, title, null, this, null, viewWeakReference); } public synchronized Spannable getSpanNote(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, note, null, this, null, true, true, viewWeakReference); + return SpannableHelper.convert(context, note, null, this, null, viewWeakReference); } public static class AccountParams implements Serializable { diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java b/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java index 808ac6e5d..8bf18863b 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java @@ -56,7 +56,7 @@ public class Announcement { public synchronized Spannable getSpanContent(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, content, null, null, this, true, false, viewWeakReference); + return SpannableHelper.convert(context, content, null, null, this, viewWeakReference); } } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Field.java b/app/src/main/java/app/fedilab/android/client/entities/api/Field.java index af574ee32..f038740ec 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Field.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Field.java @@ -47,7 +47,7 @@ public class Field implements Serializable { if (verified_at != null && value != null) { value_span = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.verified_text)); } - Spannable spannable = SpannableHelper.convert(context, value, null, account, null, true, true, viewWeakReference); + Spannable spannable = SpannableHelper.convert(context, value, null, account, null, viewWeakReference); if (value_span != null && spannable != null) { spannable.setSpan(value_span, 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } @@ -57,7 +57,7 @@ public class Field implements Serializable { public synchronized Spannable getLabelSpan(Context context, Account account, WeakReference viewWeakReference) { - Spannable spannable = SpannableHelper.convert(context, name, null, account, null, true, true, viewWeakReference); + Spannable spannable = SpannableHelper.convert(context, name, null, account, null, viewWeakReference); if (name_span != null && spannable != null) { spannable.setSpan(name_span, 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java b/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java index cf0d1d8b9..98b161a94 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java @@ -61,7 +61,7 @@ public class Poll implements Serializable { public transient Spannable span_title; public Spannable getSpanTitle(Context context, Status status, WeakReference viewWeakReference) { - span_title = SpannableHelper.convert(context, title, status, null, null, false, false, viewWeakReference); + span_title = SpannableHelper.convert(context, title, status, null, null, viewWeakReference); return span_title; } } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index e6a030745..ecc2a07ed 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -134,21 +134,21 @@ public class Status implements Serializable, Cloneable { public synchronized Spannable getSpanContent(Context context, WeakReference viewWeakReference, Callback callback) { if (contentSpan == null) { - contentSpan = SpannableHelper.convert(context, content, this, null, null, true, false, viewWeakReference, callback); + contentSpan = SpannableHelper.convert(context, content, this, null, null, viewWeakReference, callback); } return contentSpan; } public synchronized Spannable getSpanSpoiler(Context context, WeakReference viewWeakReference, Callback callback) { if (contentSpoilerSpan == null) { - contentSpoilerSpan = SpannableHelper.convert(context, spoiler_text, this, null, null, true, false, viewWeakReference, callback); + contentSpoilerSpan = SpannableHelper.convert(context, spoiler_text, this, null, null, viewWeakReference, callback); } return contentSpoilerSpan; } public synchronized Spannable getSpanTranslate(Context context, WeakReference viewWeakReference, Callback callback) { if (contentTranslateSpan == null) { - contentTranslateSpan = SpannableHelper.convert(context, translationContent, this, null, null, true, false, viewWeakReference, callback); + contentTranslateSpan = SpannableHelper.convert(context, translationContent, this, null, null, viewWeakReference, callback); } return contentTranslateSpan; } diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 26cb125d9..4dc194443 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -52,12 +52,6 @@ import androidx.lifecycle.ViewModelStoreOwner; import androidx.preference.PreferenceManager; import com.bumptech.glide.Glide; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import java.io.IOException; import java.lang.ref.WeakReference; @@ -96,18 +90,16 @@ public class SpannableHelper { public static final String CLICKABLE_SPAN = "CLICKABLE_SPAN"; public static Spannable convert(Context context, String text, - Status status, Account account, Announcement announcement, - boolean convertHtml, boolean forceMentions, WeakReference viewWeakReference) { - return convert(context, text, status, account, announcement, convertHtml, forceMentions, viewWeakReference, null); + Status status, Account account, Announcement announcement, WeakReference viewWeakReference) { + return convert(context, text, status, account, announcement, viewWeakReference, null); } private static int linkColor; + public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, - boolean convertHtml, - boolean forceMentions, WeakReference viewWeakReference, Status.Callback callback) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); @@ -131,24 +123,125 @@ public class SpannableHelper { if (linkColor == 0) { linkColor = -1; } - SpannableString initialContent; - if (text == null) { - return null; + List mentions = new ArrayList<>(); + if (status != null) { + mentions.addAll(status.mentions); } - Document htmlContent = Jsoup.parse(text); - Elements mentionElements = htmlContent.select("a.mention"); - //We keep a reference to mentions - HashMap mentionsMap = new HashMap<>(); - if (mentionElements.size() > 0) { - for (int i = 0; i < mentionElements.size(); i++) { - Element mentionElement = mentionElements.get(i); - String href = mentionElement.attr("href"); - String mention = mentionElement.text(); - mentionsMap.put(mention, href); + text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)>(((?!([<])).)*))", "$2
$3
"); + text = text.trim().replaceAll("\\s{3}", "   "); + text = text.trim().replaceAll("\\s{2}", "  "); + SpannableString initialContent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); + else + initialContent = new SpannableString(Html.fromHtml(text)); + + //Get all links + SpannableStringBuilder content = new SpannableStringBuilder(initialContent); + URLSpan[] urls = content.getSpans(0, (content.length() - 1), URLSpan.class); + //Loop through links + for (URLSpan span : urls) { + String url = span.getURL(); + + + int start = content.getSpanStart(span); + int end = content.getSpanEnd(span); + content.removeSpan(span); + //Get the matching word associated to the URL + String word = content.subSequence(start, end).toString(); + if (word.startsWith("@") || word.startsWith("#")) { + content.setSpan(new LongClickableSpan() { + @Override + public void onLongClick(View textView) { + textView.setTag(CLICKABLE_SPAN); + if (word.startsWith("#") && BaseMainActivity.filterFetched && MainActivity.mainFilters != null) { + String tag = word.trim(); + if (!tag.startsWith("#")) { + tag = "#" + tag; + } + Filter fedilabFilter = null; + for (Filter filter : MainActivity.mainFilters) { + if (filter.title.equals(Helper.FEDILAB_MUTED_HASHTAGS)) { + fedilabFilter = filter; + break; + } + } + //Filter for Fedilab doesn't exist we have to create it + if (fedilabFilter == null) { + Filter.FilterParams filterParams = new Filter.FilterParams(); + filterParams.title = Helper.FEDILAB_MUTED_HASHTAGS; + filterParams.filter_action = "hide"; + filterParams.context = new ArrayList<>(); + filterParams.context.add("home"); + filterParams.context.add("public"); + filterParams.context.add("thread"); + filterParams.context.add("account"); + String finalTag = tag; + FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class); + filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) + .observe((LifecycleOwner) context, filter -> { + if (filter != null) { + MainActivity.mainFilters.add(filter); + addTagToFilter(context, finalTag, status, filter); + } + }); + } else { + addTagToFilter(context, tag, status, fedilabFilter); + } + } + } + + @Override + public void onClick(@NonNull View textView) { + textView.setTag(CLICKABLE_SPAN); + Intent intent; + Bundle b; + if (word.startsWith("#")) { + intent = new Intent(context, HashTagActivity.class); + b = new Bundle(); + b.putString(Helper.ARG_SEARCH_KEYWORD, word.trim()); + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } else if (word.startsWith("@")) { + intent = new Intent(context, ProfileActivity.class); + b = new Bundle(); + Mention targetedMention = null; + + for (Mention mention : mentions) { + if (word.compareToIgnoreCase("@" + mention.username) == 0) { + targetedMention = mention; + break; + } + } + if (targetedMention != null) { + b.putString(Helper.ARG_USER_ID, targetedMention.id); + } else { + b.putString(Helper.ARG_MENTION, word); + } + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + if (linkColor != -1) { + ds.setColor(linkColor); + } + } + + }, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } else { + makeLinks(context, content, url, start, end); } + replaceQuoteSpans(context, content); + emails(context, content); } - text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?\\/?>)>(((?!([<])).)*))", "$2
$3
"); Pattern imgPattern = Pattern.compile("]*src=\"([^\"]+)\"[^>]*>"); Matcher matcherImg = imgPattern.matcher(text); HashMap imagesToReplace = new LinkedHashMap<>(); @@ -160,57 +253,15 @@ public class SpannableHelper { text = text.replaceAll(Pattern.quote(matcherImg.group()), replacement); } - SpannableStringBuilder content; View view = viewWeakReference.get(); - List mentionList = null; List emojiList = null; if (status != null) { - mentionList = status.mentions; emojiList = status.emojis; } else if (account != null) { emojiList = account.emojis; } else if (announcement != null) { emojiList = announcement.emojis; } - //UrlDetails will contain links having a text different from the url - HashMap urlDetails = new HashMap<>(); - if (convertHtml) { - Matcher matcherALink = Helper.aLink.matcher(text); - - //We stock details - while (matcherALink.find()) { - String urlText = matcherALink.group(3); - String url = matcherALink.group(2); - if (urlText != null && urlText.startsWith(">")) { - urlText = urlText.substring(1); - } - if (url != null && urlText != null && !url.equalsIgnoreCase(urlText) && !urlText.contains("= Build.VERSION_CODES.N) - initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); - else - initialContent = new SpannableString(Html.fromHtml(text)); - - content = new SpannableStringBuilder(initialContent); - URLSpan[] urls = content.getSpans(0, (content.length() - 1), URLSpan.class); - for (URLSpan span : urls) { - content.removeSpan(span); - } - //Make tags, mentions, groups - interaction(context, content, status, mentionList, forceMentions, mentionsMap); - //Make all links - linkify(context, content, urlDetails); - linkifyURL(context, content, urlDetails); - emails(context, content); - gemini(context, content); - replaceQuoteSpans(context, content); - } else { - content = new SpannableStringBuilder(text); - } boolean animate = !sharedpreferences.getBoolean(context.getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false); CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(view)); content = customEmoji.makeEmoji(content, emojiList, animate, callback); @@ -234,542 +285,208 @@ public class SpannableHelper { return trimSpannable(new SpannableStringBuilder(content)); } - private static void linkify(Context context, SpannableStringBuilder content, HashMap urlDetails) { - //--- URLs ---- - Matcher matcherLink = Patterns.WEB_URL.matcher(content); - int offSetTruncate = 0; + private static void makeLinks(Context context, SpannableStringBuilder content, String url, int start, int end) { + String newUrl = url; + String newURL = Helper.transformURL(context, url); + //If URL has been transformed + if (newURL.compareTo(url) != 0) { + content.replace(start, end, newURL); + end = start + newURL.length(); + url = newURL; + } + if (url.length() > 30 && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("gimini://"))) { + newUrl = url.substring(0, 30); + newUrl += "…"; + content.replace(start, end, newUrl); + } + int matchEnd = start + newUrl.length(); + String finalUrl = url; + content.setSpan(new LongClickableSpan() { + @Override + public void onLongClick(View view) { + Context mContext = view.getContext(); + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); + PopupLinksBinding popupLinksBinding = PopupLinksBinding.inflate(LayoutInflater.from(context)); + dialogBuilder.setView(popupLinksBinding.getRoot()); + AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + popupLinksBinding.displayFullLink.setOnClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + builder.setMessage(finalUrl); + builder.setTitle(context.getString(R.string.display_full_link)); + builder.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) + .show(); + alertDialog.dismiss(); + }); + popupLinksBinding.shareLink.setOnClickListener(v -> { + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); + sendIntent.putExtra(Intent.EXTRA_TEXT, finalUrl); + sendIntent.setType("text/plain"); + sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Intent intentChooser = Intent.createChooser(sendIntent, context.getString(R.string.share_with)); + intentChooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intentChooser); + alertDialog.dismiss(); + }); + popupLinksBinding.openOtherApp.setOnClickListener(v -> { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(finalUrl)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(intent); + } catch (Exception e) { + Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + } + alertDialog.dismiss(); + }); - while (matcherLink.find()) { - int matchStart = matcherLink.start() - offSetTruncate; - int matchEnd = matchStart + matcherLink.group().length(); - if (matchEnd > content.toString().length()) { - matchEnd = content.toString().length(); - } + popupLinksBinding.copyLink.setOnClickListener(v -> { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, finalUrl); + if (clipboard != null) { + clipboard.setPrimaryClip(clip); + Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); + } + alertDialog.dismiss(); + }); - if (content.toString().length() < matchEnd || matchStart < 0 || matchStart > matchEnd) { - continue; - } + popupLinksBinding.checkRedirect.setOnClickListener(v -> { + try { - - final String url = content.toString().substring(matchStart, matchEnd); - if (urlDetails.containsKey(url)) { - continue; - } - - ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); - if (clickableSpans != null) { - for (ClickableSpan clickableSpan : clickableSpans) { - content.removeSpan(clickableSpan); - } - } - content.removeSpan(clickableSpans); - String newURL = Helper.transformURL(context, url); - //If URL has been transformed - if (newURL.compareTo(url) != 0) { - content.replace(matchStart, matchEnd, newURL); - offSetTruncate -= (newURL.length() - url.length()); - matchEnd = matchStart + newURL.length(); - } - - //Truncate URL if needed - //TODO: add an option to disable truncated URLs - String urlText = newURL; - if (newURL.length() > 30 && !urlDetails.containsKey(urlText) && !urlText.startsWith("gemini")) { - urlText = urlText.substring(0, 30); - urlText += "…"; - content.replace(matchStart, matchEnd, urlText); - matchEnd = matchStart + 31; - offSetTruncate += (newURL.length() - urlText.length()); - } - - - if (matchEnd <= content.length() && matchEnd >= matchStart) { - content.setSpan(new LongClickableSpan() { - @Override - public void onLongClick(View view) { - Context mContext = view.getContext(); - MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(mContext); - PopupLinksBinding popupLinksBinding = PopupLinksBinding.inflate(LayoutInflater.from(context)); - materialAlertDialogBuilder.setView(popupLinksBinding.getRoot()); - AlertDialog alertDialog = materialAlertDialogBuilder.create(); - alertDialog.show(); - String finalURl = newURL; - String uniqueUrl = newURL.endsWith("…") ? newURL : newURL + "…"; - if (urlDetails.containsValue(uniqueUrl)) { - finalURl = Helper.getKeyByValue(urlDetails, uniqueUrl); - } - if (finalURl == null) { - return; - } - if (finalURl.startsWith("http://")) { - finalURl = finalURl.replace("http://", "https://"); - } - String finalURl1 = finalURl; - popupLinksBinding.displayFullLink.setOnClickListener(v -> { - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setMessage(finalURl1); - builder.setTitle(context.getString(R.string.display_full_link)); - builder.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) - .show(); - alertDialog.dismiss(); - }); - popupLinksBinding.shareLink.setOnClickListener(v -> { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, finalURl1); - sendIntent.setType("text/plain"); - sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Intent intentChooser = Intent.createChooser(sendIntent, context.getString(R.string.share_with)); - intentChooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intentChooser); - alertDialog.dismiss(); - }); - - popupLinksBinding.openOtherApp.setOnClickListener(v -> { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(finalURl1)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + URL finalUrlCheck = new URL(finalUrl); + new Thread(() -> { try { - context.startActivity(intent); - } catch (Exception e) { - Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); - } - alertDialog.dismiss(); - }); - - popupLinksBinding.copyLink.setOnClickListener(v -> { - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, finalURl1); - if (clipboard != null) { - clipboard.setPrimaryClip(clip); - Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); - } - alertDialog.dismiss(); - }); - - popupLinksBinding.checkRedirect.setOnClickListener(v -> { - try { - - URL finalUrlCheck = new URL(finalURl1); - new Thread(() -> { - try { - String redirect = null; - HttpsURLConnection httpsURLConnection = (HttpsURLConnection) finalUrlCheck.openConnection(); - httpsURLConnection.setConnectTimeout(10 * 1000); - httpsURLConnection.setRequestProperty("http.keepAlive", "false"); - // httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); - httpsURLConnection.setRequestMethod("HEAD"); - httpsURLConnection.setInstanceFollowRedirects(false); - if (httpsURLConnection.getResponseCode() == 301 || httpsURLConnection.getResponseCode() == 302) { - Map> map = httpsURLConnection.getHeaderFields(); - for (Map.Entry> entry : map.entrySet()) { - if (entry.toString().toLowerCase().startsWith("location")) { - Matcher matcher = Patterns.WEB_URL.matcher(entry.toString()); - if (matcher.find()) { - redirect = matcher.group(1); - } - } + String redirect = null; + HttpsURLConnection httpsURLConnection = (HttpsURLConnection) finalUrlCheck.openConnection(); + httpsURLConnection.setConnectTimeout(10 * 1000); + httpsURLConnection.setRequestProperty("http.keepAlive", "false"); + //httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); + httpsURLConnection.setRequestMethod("HEAD"); + httpsURLConnection.setInstanceFollowRedirects(false); + if (httpsURLConnection.getResponseCode() == 301 || httpsURLConnection.getResponseCode() == 302) { + Map> map = httpsURLConnection.getHeaderFields(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.toString().toLowerCase().startsWith("location")) { + Matcher matcher = Patterns.WEB_URL.matcher(entry.toString()); + if (matcher.find()) { + redirect = matcher.group(1); } } - httpsURLConnection.getInputStream().close(); - if (redirect != null && redirect.compareTo(finalURl1) != 0) { - URL redirectURL = new URL(redirect); - String host = redirectURL.getHost(); - String protocol = redirectURL.getProtocol(); - if (protocol == null || host == null) { - redirect = null; - } - } - Handler mainHandler = new Handler(context.getMainLooper()); - String finalRedirect = redirect; - Runnable myRunnable = () -> { - AlertDialog.Builder builder1 = new AlertDialog.Builder(view.getContext()); - if (finalRedirect != null) { - builder1.setMessage(context.getString(R.string.redirect_detected, finalURl1, finalRedirect)); - builder1.setNegativeButton(R.string.copy_link, (dialog, which) -> { - ClipboardManager clipboard1 = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip1 = ClipData.newPlainText(Helper.CLIP_BOARD, finalRedirect); - if (clipboard1 != null) { - clipboard1.setPrimaryClip(clip1); - Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); - } - dialog.dismiss(); - }); - builder1.setNeutralButton(R.string.share_link, (dialog, which) -> { - Intent sendIntent1 = new Intent(Intent.ACTION_SEND); - sendIntent1.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent1.putExtra(Intent.EXTRA_TEXT, finalURl1); - sendIntent1.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent1, context.getString(R.string.share_with))); - dialog.dismiss(); - }); - } else { - builder1.setMessage(R.string.no_redirect); - } - builder1.setTitle(context.getString(R.string.check_redirect)); - builder1.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) - .show(); - - }; - mainHandler.post(myRunnable); - } catch (IOException e) { - e.printStackTrace(); } + } + httpsURLConnection.getInputStream().close(); + if (redirect != null && redirect.compareTo(finalUrl) != 0) { + URL redirectURL = new URL(redirect); + String host = redirectURL.getHost(); + String protocol = redirectURL.getProtocol(); + if (protocol == null || host == null) { + redirect = null; + } + } + Handler mainHandler = new Handler(context.getMainLooper()); + String finalRedirect = redirect; + Runnable myRunnable = () -> { + AlertDialog.Builder builder1 = new AlertDialog.Builder(view.getContext()); + if (finalRedirect != null) { + builder1.setMessage(context.getString(R.string.redirect_detected, finalUrl, finalRedirect)); + builder1.setNegativeButton(R.string.copy_link, (dialog, which) -> { + ClipboardManager clipboard1 = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip1 = ClipData.newPlainText(Helper.CLIP_BOARD, finalRedirect); + if (clipboard1 != null) { + clipboard1.setPrimaryClip(clip1); + Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); + } + dialog.dismiss(); + }); + builder1.setNeutralButton(R.string.share_link, (dialog, which) -> { + Intent sendIntent1 = new Intent(Intent.ACTION_SEND); + sendIntent1.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); + sendIntent1.putExtra(Intent.EXTRA_TEXT, finalUrl); + sendIntent1.setType("text/plain"); + context.startActivity(Intent.createChooser(sendIntent1, context.getString(R.string.share_with))); + dialog.dismiss(); + }); + } else { + builder1.setMessage(R.string.no_redirect); + } + builder1.setTitle(context.getString(R.string.check_redirect)); + builder1.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) + .show(); - }).start(); - } catch (MalformedURLException e) { + }; + mainHandler.post(myRunnable); + } catch (IOException e) { e.printStackTrace(); } - alertDialog.dismiss(); - }); - + }).start(); + } catch (MalformedURLException e) { + e.printStackTrace(); } - @Override - public void onClick(@NonNull View textView) { - String finalURl = newURL; - String finalURl2 = url; - String uniqueNewURL = newURL.endsWith("…") ? newURL : newURL + "…"; - if (urlDetails.containsValue(uniqueNewURL)) { - finalURl = Helper.getKeyByValue(urlDetails, uniqueNewURL); - } - String uniqueUrl = url.endsWith("…") ? url : url + "…"; - if (urlDetails.containsValue(uniqueUrl)) { - finalURl2 = Helper.getKeyByValue(urlDetails, uniqueUrl); - } - textView.setTag(CLICKABLE_SPAN); - Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); - Matcher matcherLink = null; - if (finalURl2 != null) { - matcherLink = link.matcher(finalURl2); - } - if (finalURl2 != null && matcherLink.find() && !finalURl2.contains("medium.com")) { - if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot - CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalURl2, new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { - Intent intent = new Intent(context, ContextActivity.class); - intent.putExtra(Helper.ARG_STATUS, status); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } + alertDialog.dismiss(); + }); - @Override - public void federatedAccount(Account account) { - } - }); - } else {//It's an account - CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { - } - - @Override - public void federatedAccount(Account account) { - Intent intent = new Intent(context, ProfileActivity.class); - Bundle b = new Bundle(); - b.putSerializable(Helper.ARG_ACCOUNT, account); - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - }); - } - } else { - Helper.openBrowser(context, finalURl); - } - - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - super.updateDrawState(ds); - if (linkColor != -1) { - ds.setColor(linkColor); - } - } - - }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } - } - } - private static void linkifyURL(Context context, SpannableStringBuilder content, HashMap urlDetails) { + @Override + public void onClick(@NonNull View textView) { - for (Map.Entry entry : urlDetails.entrySet()) { - String value = entry.getValue(); - if (value.startsWith("@") || value.startsWith("#")) { - continue; - } - SpannableString contentUrl; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - contentUrl = new SpannableString(Html.fromHtml(value, Html.FROM_HTML_MODE_LEGACY)); - else - contentUrl = new SpannableString(Html.fromHtml(value)); - if (contentUrl.toString().trim().isEmpty()) { - continue; - } - Pattern word = Pattern.compile(Pattern.quote(contentUrl.toString())); - Matcher matcherLink = word.matcher(content); - while (matcherLink.find()) { - String url = entry.getKey(); - int matchStart = matcherLink.start(); - int matchEnd = matchStart + matcherLink.group().length(); - if (matchEnd > content.toString().length()) { - matchEnd = content.toString().length(); - } - - if (content.toString().length() < matchEnd || matchStart < 0 || matchStart > matchEnd) { - continue; - } - - ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); - if (clickableSpans != null) { - for (ClickableSpan clickableSpan : clickableSpans) { - content.removeSpan(clickableSpan); - } - } - content.removeSpan(clickableSpans); - - if (matchEnd <= content.length()) { - content.setSpan(new LongClickableSpan() { - @Override - public void onLongClick(View view) { - Context mContext = view.getContext(); - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext); - PopupLinksBinding popupLinksBinding = PopupLinksBinding.inflate(LayoutInflater.from(context)); - dialogBuilder.setView(popupLinksBinding.getRoot()); - AlertDialog alertDialog = dialogBuilder.create(); - alertDialog.show(); - String finalURl = url; - if (urlDetails.containsValue(url)) { - finalURl = Helper.getKeyByValue(urlDetails, url); - } - String finalURl1 = finalURl; - popupLinksBinding.displayFullLink.setOnClickListener(v -> { - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setMessage(finalURl1); - builder.setTitle(context.getString(R.string.display_full_link)); - builder.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) - .show(); - alertDialog.dismiss(); - }); - popupLinksBinding.shareLink.setOnClickListener(v -> { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent.putExtra(Intent.EXTRA_TEXT, finalURl1); - sendIntent.setType("text/plain"); - sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Intent intentChooser = Intent.createChooser(sendIntent, context.getString(R.string.share_with)); - intentChooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intentChooser); - alertDialog.dismiss(); - }); - - popupLinksBinding.openOtherApp.setOnClickListener(v -> { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(finalURl1)); + textView.setTag(CLICKABLE_SPAN); + Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); + Matcher matcherLink = link.matcher(content); + if (matcherLink.find() && !finalUrl.contains("medium.com")) { + if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot + CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { + Intent intent = new Intent(context, ContextActivity.class); + intent.putExtra(Helper.ARG_STATUS, status); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(intent); - } catch (Exception e) { - Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show(); - } - alertDialog.dismiss(); - }); - - popupLinksBinding.copyLink.setOnClickListener(v -> { - ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText(Helper.CLIP_BOARD, finalURl1); - if (clipboard != null) { - clipboard.setPrimaryClip(clip); - Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); - } - alertDialog.dismiss(); - }); - - popupLinksBinding.checkRedirect.setOnClickListener(v -> { - try { - - URL finalUrlCheck = new URL(finalURl1); - new Thread(() -> { - try { - String redirect = null; - HttpsURLConnection httpsURLConnection = (HttpsURLConnection) finalUrlCheck.openConnection(); - httpsURLConnection.setConnectTimeout(10 * 1000); - httpsURLConnection.setRequestProperty("http.keepAlive", "false"); - //httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); - httpsURLConnection.setRequestMethod("HEAD"); - httpsURLConnection.setInstanceFollowRedirects(false); - if (httpsURLConnection.getResponseCode() == 301 || httpsURLConnection.getResponseCode() == 302) { - Map> map = httpsURLConnection.getHeaderFields(); - for (Map.Entry> entry : map.entrySet()) { - if (entry.toString().toLowerCase().startsWith("location")) { - Matcher matcher = Patterns.WEB_URL.matcher(entry.toString()); - if (matcher.find()) { - redirect = matcher.group(1); - } - } - } - } - httpsURLConnection.getInputStream().close(); - if (redirect != null && finalURl1 != null && redirect.compareTo(finalURl1) != 0) { - URL redirectURL = new URL(redirect); - String host = redirectURL.getHost(); - String protocol = redirectURL.getProtocol(); - if (protocol == null || host == null) { - redirect = null; - } - } - Handler mainHandler = new Handler(context.getMainLooper()); - String finalRedirect = redirect; - Runnable myRunnable = () -> { - AlertDialog.Builder builder1 = new AlertDialog.Builder(view.getContext()); - if (finalRedirect != null) { - builder1.setMessage(context.getString(R.string.redirect_detected, finalURl1, finalRedirect)); - builder1.setNegativeButton(R.string.copy_link, (dialog, which) -> { - ClipboardManager clipboard1 = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip1 = ClipData.newPlainText(Helper.CLIP_BOARD, finalRedirect); - if (clipboard1 != null) { - clipboard1.setPrimaryClip(clip1); - Toasty.info(context, context.getString(R.string.clipboard_url), Toast.LENGTH_LONG).show(); - } - dialog.dismiss(); - }); - builder1.setNeutralButton(R.string.share_link, (dialog, which) -> { - Intent sendIntent1 = new Intent(Intent.ACTION_SEND); - sendIntent1.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via)); - sendIntent1.putExtra(Intent.EXTRA_TEXT, finalURl1); - sendIntent1.setType("text/plain"); - context.startActivity(Intent.createChooser(sendIntent1, context.getString(R.string.share_with))); - dialog.dismiss(); - }); - } else { - builder1.setMessage(R.string.no_redirect); - } - builder1.setTitle(context.getString(R.string.check_redirect)); - builder1.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss()) - .show(); - - }; - mainHandler.post(myRunnable); - } catch (IOException e) { - e.printStackTrace(); - } - - }).start(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - - alertDialog.dismiss(); - }); - - } - - @Override - public void onClick(@NonNull View textView) { - String finalURl = url; - if (urlDetails.containsValue(url)) { - finalURl = Helper.getKeyByValue(urlDetails, url); + context.startActivity(intent); } - textView.setTag(CLICKABLE_SPAN); - Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); - Matcher matcherLink = null; - if (finalURl != null) { - matcherLink = link.matcher(finalURl); + @Override + public void federatedAccount(Account account) { } - if (finalURl != null && matcherLink.find() && !finalURl.contains("medium.com")) { - if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot - CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalURl, new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { - Intent intent = new Intent(context, ContextActivity.class); - intent.putExtra(Helper.ARG_STATUS, status); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - - @Override - public void federatedAccount(Account account) { - } - }); - } else {//It's an account - CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { - } - - @Override - public void federatedAccount(Account account) { - Intent intent = new Intent(context, ProfileActivity.class); - Bundle b = new Bundle(); - b.putSerializable(Helper.ARG_ACCOUNT, account); - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - }); - } - } else { - Helper.openBrowser(context, finalURl); + }); + } else {//It's an account + CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { } - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - super.updateDrawState(ds); - ds.setUnderlineText(false); - if (linkColor != -1) { - ds.setColor(linkColor); + @Override + public void federatedAccount(Account account) { + Intent intent = new Intent(context, ProfileActivity.class); + Bundle b = new Bundle(); + b.putSerializable(Helper.ARG_ACCOUNT, account); + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); } - } - }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + }); + } + } else { + Helper.openBrowser(context, finalUrl); } } - } - } - private static void gemini(Context context, Spannable content) { - // --- For all patterns defined in Helper class --- - Pattern pattern = Helper.geminiPattern; - Matcher matcher = pattern.matcher(content); - while (matcher.find()) { - int matchStart = matcher.start(); - int matchEnd = matcher.end(); - String geminiLink = content.toString().substring(matchStart, matchEnd); - if (matchStart >= 0 && matchEnd <= content.toString().length() && matchEnd >= matchStart) { - ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); - if (clickableSpans != null) { - for (ClickableSpan clickableSpan : clickableSpans) { - content.removeSpan(clickableSpan); - } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + if (linkColor != -1) { + ds.setColor(linkColor); } - content.removeSpan(clickableSpans); - content.setSpan(new ClickableSpan() { - @Override - public void onClick(@NonNull View textView) { - Helper.openBrowser(context, geminiLink); - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - super.updateDrawState(ds); - ds.setUnderlineText(false); - if (linkColor != -1) { - ds.setColor(linkColor); - } - } - }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } - } + }, start, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } + private static void emails(Context context, Spannable content) { // --- For all patterns defined in Helper class --- Pattern pattern = Helper.emailPattern; @@ -809,167 +526,6 @@ public class SpannableHelper { } } - private static void interaction(Context context, Spannable content, Status status, List mentions, boolean forceMentions, HashMap mentionsMap) { - // --- For all patterns defined in Helper class --- - for (Map.Entry entry : Helper.patternHashMap.entrySet()) { - Helper.PatternType patternType = entry.getKey(); - Pattern pattern = entry.getValue(); - Matcher matcher = pattern.matcher(content); - if (pattern == Helper.mentionPattern && mentions == null && !forceMentions) { - continue; - } else if (pattern == Helper.mentionLongPattern && mentions == null && !forceMentions) { - continue; - } - - while (matcher.find()) { - int matchStart = matcher.start(); - int matchEnd = matcher.end(); - String word = content.toString().substring(matchStart, matchEnd); - if (matchStart >= 0 && matchEnd <= content.toString().length() && matchEnd >= matchStart) { - URLSpan[] span = content.getSpans(matchStart, matchEnd, URLSpan.class); - content.removeSpan(span); - content.setSpan(new LongClickableSpan() { - @Override - public void onLongClick(View textView) { - textView.setTag(CLICKABLE_SPAN); - if (patternType == Helper.PatternType.TAG && BaseMainActivity.filterFetched && MainActivity.mainFilters != null) { - String tag = word.trim(); - if (!tag.startsWith("#")) { - tag = "#" + tag; - } - Filter fedilabFilter = null; - for (Filter filter : MainActivity.mainFilters) { - if (filter.title.equals(Helper.FEDILAB_MUTED_HASHTAGS)) { - fedilabFilter = filter; - break; - } - } - //Filter for Fedilab doesn't exist we have to create it - if (fedilabFilter == null) { - Filter.FilterParams filterParams = new Filter.FilterParams(); - filterParams.title = Helper.FEDILAB_MUTED_HASHTAGS; - filterParams.filter_action = "hide"; - filterParams.context = new ArrayList<>(); - filterParams.context.add("home"); - filterParams.context.add("public"); - filterParams.context.add("thread"); - filterParams.context.add("account"); - String finalTag = tag; - FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class); - filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) - .observe((LifecycleOwner) context, filter -> { - if (filter != null) { - MainActivity.mainFilters.add(filter); - addTagToFilter(context, finalTag, status, filter); - } - }); - } else { - addTagToFilter(context, tag, status, fedilabFilter); - } - } - } - - @Override - public void onClick(@NonNull View textView) { - textView.setTag(CLICKABLE_SPAN); - switch (patternType) { - case TAG: - Intent intent = new Intent(context, HashTagActivity.class); - Bundle b = new Bundle(); - b.putString(Helper.ARG_SEARCH_KEYWORD, word.trim()); - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - break; - case GROUP: - break; - case MENTION: - intent = new Intent(context, ProfileActivity.class); - b = new Bundle(); - Mention targetedMention = null; - String acct = null; - HashMap countUsername = new HashMap<>(); - //Mentions is retrieved with associated Mentions array - if (mentions != null) { - for (Mention mention : mentions) { - Integer count = countUsername.get(mention.username); - if (count == null) { - count = 0; - } - if (countUsername.containsKey(mention.username)) { - countUsername.put(mention.username, count + 1); - } else { - countUsername.put(mention.username, 1); - } - } - for (Mention mention : mentions) { - Integer count = countUsername.get(mention.username); - if (count == null) { - count = 0; - } - if (word.trim().compareToIgnoreCase("@" + mention.username) == 0 && count == 1) { - targetedMention = mention; - break; - } - } - } else if (mentionsMap.containsKey(word.trim())) {//Mentions will be find through its URL - URL url; - try { - url = new URL(mentionsMap.get(word.trim())); - acct = word.trim() + "@" + url.getHost(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - } - if (targetedMention != null) { - b.putString(Helper.ARG_USER_ID, targetedMention.id); - } else { - b.putString(Helper.ARG_MENTION, acct != null ? acct : word.trim()); - } - - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - break; - case MENTION_LONG: - intent = new Intent(context, ProfileActivity.class); - b = new Bundle(); - targetedMention = null; - if (mentions != null) { - for (Mention mention : mentions) { - if (word.trim().substring(1).compareToIgnoreCase("@" + mention.acct) == 0) { - targetedMention = mention; - break; - } - } - } - if (targetedMention != null) { - b.putString(Helper.ARG_USER_ID, targetedMention.id); - } else { - b.putString(Helper.ARG_MENTION, word.trim()); - } - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - break; - } - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - super.updateDrawState(ds); - ds.setUnderlineText(false); - if (linkColor != -1) { - ds.setColor(linkColor); - } - } - - }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - } - } - } - } - public static void addTagToFilter(Context context, String tag, Status status, Filter filter) { for (Filter.KeywordsAttributes keywords : filter.keywords) { if (keywords.keyword.equalsIgnoreCase(tag)) { @@ -1006,7 +562,6 @@ public class SpannableHelper { * * @param status {@link Status} - Status concerned by the spannable transformation * @param content String - text to convert, it can be content, spoiler, poll items, etc. - * @return Spannable string */ private static void convertOuich(@NonNull Status status, SpannableStringBuilder content) { From 818f32ffb52be8dd8f10698ab0966dc3c078d04d Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 31 Dec 2022 15:10:11 +0100 Subject: [PATCH 02/68] some fixes --- .../main/java/app/fedilab/android/helper/SpannableHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 4dc194443..2e3ba27a1 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -124,7 +124,7 @@ public class SpannableHelper { linkColor = -1; } List mentions = new ArrayList<>(); - if (status != null) { + if (status != null && status.mentions != null) { mentions.addAll(status.mentions); } text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)>(((?!([<])).)*))", "$2
$3
"); @@ -437,7 +437,7 @@ public class SpannableHelper { textView.setTag(CLICKABLE_SPAN); Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); - Matcher matcherLink = link.matcher(content); + Matcher matcherLink = link.matcher(finalUrl); if (matcherLink.find() && !finalUrl.contains("medium.com")) { if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() { From f81ba544a315fac1d587058b07ac66e2f8f03e13 Mon Sep 17 00:00:00 2001 From: claleb Date: Sat, 31 Dec 2022 16:50:31 +0100 Subject: [PATCH 03/68] Translated using Weblate (German) Currently translated at 21.2% (14 of 66 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/ Translation: Fedilab/description --- .../metadata/android/de/changelogs/457.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/457.txt diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/457.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/457.txt new file mode 100644 index 000000000..d1e371861 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/457.txt @@ -0,0 +1,14 @@ +Hinzugefügt: +- Zusätzliche Funktionen in den Einstellungen +- Anpassbare Einstellungen für zusätzliche Funktionen +- Unterstützung von Zitaten, Reaktionen mit Nachrichten +- Unterstützung von Textformaten (html, markdown, etc.) beim Verfassen + +Geändert: +- Kontextmenü bei langem Drücken eines Links +- Lesezeichen und Übersetzungsschaltflächen werden jetzt pro Konto angezeigt + +Behoben: +- CW funktioniert nicht mit Medien +- Medien werden bei älteren Instanzen nicht angezeigt +- Einige Abstürze From f976b6dd72f6ad812fac341438a0bf24401bec1b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 31 Dec 2022 18:12:31 +0100 Subject: [PATCH 04/68] Add Bubble timeline support --- .../endpoints/MastodonTimelinesService.java | 13 +++ .../android/client/entities/app/Timeline.java | 2 + .../android/helper/PinnedTimelineHelper.java | 92 +++++++------------ .../android/ui/drawer/ReorderTabAdapter.java | 4 + .../timeline/FragmentMastodonTimeline.java | 10 +- .../viewmodel/mastodon/TimelinesVM.java | 6 ++ .../drawable/ic_baseline_bubble_chart_24.xml | 16 ++++ app/src/main/res/values/strings.xml | 1 + 8 files changed, 84 insertions(+), 60 deletions(-) create mode 100644 app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java index 619bc92a7..a2c953dbb 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java @@ -53,6 +53,19 @@ public interface MastodonTimelinesService { @Query("limit") Integer limit ); + @GET("timelines/bubble") + Call> getBubble( + @Header("Authorization") String token, + @Query("only_media") Boolean only_media, + @Query("remote") Boolean remote, + @Query("with_muted") Boolean with_muted, + @Query("exclude_visibilities") List exclude_visibilities, + @Query("reply_visibility") String reply_visibility, + @Query("max_id") String max_id, + @Query("since_id") String since_id, + @Query("min_id") String min_id, + @Query("limit") Integer limit + ); @GET("trends/statuses") Call> getStatusTrends( diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java index 109a8790f..e3c5fa665 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java @@ -364,6 +364,8 @@ public class Timeline { LOCAL("LOCAL"), @SerializedName("PUBLIC") PUBLIC("PUBLIC"), + @SerializedName("BUBBLE") + BUBBLE("BUBBLE"), @SerializedName("CONTEXT") CONTEXT("CONTEXT"), @SerializedName("TAG") diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index e39da3142..2deefd41c 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -22,7 +22,6 @@ import static app.fedilab.android.BaseMainActivity.show_replies; import static app.fedilab.android.ui.pageadapter.FedilabPageAdapter.BOTTOM_TIMELINE_COUNT; import android.annotation.SuppressLint; -import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Editable; @@ -57,6 +56,7 @@ import java.util.regex.Pattern; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; +import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.entities.api.MastodonList; import app.fedilab.android.client.entities.app.BottomMenu; import app.fedilab.android.client.entities.app.Pinned; @@ -94,59 +94,6 @@ public class PinnedTimelineHelper { } - /** - * Returns the slug of the first loaded fragment - * - * @param context - Context - * @param pinned - {@link Pinned} - * @param bottomMenu - {@link BottomMenu} - * @return String - slug - */ - public static String firstTimelineSlug(Context context, Pinned pinned, BottomMenu bottomMenu) { - String slug = Timeline.TimeLineEnum.HOME.getValue(); - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); - boolean singleBar = sharedpreferences.getBoolean(context.getString(R.string.SET_USE_SINGLE_TOPBAR), false); - PinnedTimeline pinnedTimelineMin = null; - if (singleBar) { - if (pinned != null && pinned.pinnedTimelines != null) { - for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { - if (pinnedTimeline.displayed) { - if (pinnedTimelineMin == null) { - pinnedTimelineMin = pinnedTimeline; - } else if (pinnedTimelineMin.position > pinnedTimeline.position) { - pinnedTimelineMin = pinnedTimeline; - } - } - } - } - } else { - if (bottomMenu != null && bottomMenu.bottom_menu != null && bottomMenu.bottom_menu.size() > 0) { - BottomMenu.MenuItem menuItem = bottomMenu.bottom_menu.get(0); - return menuItem.item_menu_type.getValue(); - } - - } - String ident = null; - if (pinnedTimelineMin != null) { - if (pinnedTimelineMin.tagTimeline != null) { - ident = "@T@" + pinnedTimelineMin.tagTimeline.name; - if (pinnedTimelineMin.tagTimeline.isART) { - pinnedTimelineMin.type = Timeline.TimeLineEnum.ART; - } - } else if (pinnedTimelineMin.mastodonList != null) { - ident = "@l@" + pinnedTimelineMin.mastodonList.id; - } else if (pinnedTimelineMin.remoteInstance != null) { - if (pinnedTimelineMin.remoteInstance.type == RemoteInstance.InstanceType.NITTER) { - String remoteInstance = sharedpreferences.getString(context.getString(R.string.SET_NITTER_HOST), context.getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); - ident = "@R@" + remoteInstance; - } else { - ident = "@R@" + pinnedTimelineMin.remoteInstance.host; - } - } - slug = pinnedTimelineMin.type.getValue() + (ident != null ? "|" + ident : ""); - } - return slug; - } public synchronized static void redrawTopBarPinned(BaseMainActivity activity, ActivityMainBinding activityMainBinding, Pinned pinned, BottomMenu bottomMenu, List mastodonLists) { //Values must be initialized if there is no records in db @@ -159,8 +106,8 @@ public class PinnedTimelineHelper { pinned.pinnedTimelines = new ArrayList<>(); } //Set the slug of first visible fragment - String slugOfFirstFragment = PinnedTimelineHelper.firstTimelineSlug(activity, pinned, bottomMenu); - Helper.setSlugOfFirstFragment(activity, slugOfFirstFragment, currentUserID, currentInstance); + /*String slugOfFirstFragment = PinnedTimelineHelper.firstTimelineSlug(activity, pinned, bottomMenu); + Helper.setSlugOfFirstFragment(activity, slugOfFirstFragment, currentUserID, currentInstance);*/ SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity); boolean singleBar = sharedpreferences.getBoolean(activity.getString(R.string.SET_USE_SINGLE_TOPBAR), false); @@ -187,6 +134,7 @@ public class PinnedTimelineHelper { activityMainBinding.viewPager.setLayoutParams(params); List pinnedTimelines = pinned.pinnedTimelines; + boolean extraFeatures = sharedpreferences.getBoolean(activity.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false); if (singleBar) { boolean createDefaultAtTop = true; @@ -222,15 +170,40 @@ public class PinnedTimelineHelper { pinnedTimelineConversations.type = Timeline.TimeLineEnum.DIRECT; pinnedTimelineConversations.position = 4; pinned.pinnedTimelines.add(pinnedTimelineConversations); - try { new Pinned(activity).updatePinned(pinned); } catch (DBException e) { e.printStackTrace(); } } - } + if (extraFeatures) { + try { + Pinned pinnedAll = new Pinned(activity).getAllPinned(currentAccount); + boolean createDefaultBubbleAtTop = true; + for (PinnedTimeline pinnedTimeline : pinnedAll.pinnedTimelines) { + if (pinnedTimeline.type == Timeline.TimeLineEnum.BUBBLE) { + createDefaultBubbleAtTop = false; + break; + } + } + if (createDefaultBubbleAtTop) { + PinnedTimeline pinnedTimelineBubble = new PinnedTimeline(); + pinnedTimelineBubble.type = Timeline.TimeLineEnum.BUBBLE; + pinnedTimelineBubble.position = pinnedAll.pinnedTimelines != null ? pinnedAll.pinnedTimelines.size() : 0; + pinned.pinnedTimelines.add(pinnedTimelineBubble); + boolean exist = new Pinned(activity).pinnedExist(pinned); + if (exist) { + new Pinned(activity).updatePinned(pinned); + } else { + new Pinned(activity).insertPinned(pinned); + } + } + } catch (DBException e) { + e.printStackTrace(); + } + } + sortPositionAsc(pinnedTimelines); //Check if changes occurred, if mastodonLists is null it does need, because it is the first call to draw pinned boolean needRedraw = mastodonLists == null; @@ -421,6 +394,9 @@ public class PinnedTimelineHelper { case DIRECT: tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_mail_24); break; + case BUBBLE: + tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24); + break; } tab.setCustomView(tabCustomDefaultViewBinding.getRoot()); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java index 7665ca4e5..d23cb7a23 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java @@ -141,6 +141,10 @@ public class ReorderTabAdapter extends RecyclerView.Adapter all; public List any; @@ -961,6 +965,8 @@ public class TimelinesVM extends AndroidViewModel { public int limit = 40; public Boolean local; public List excludeType; + public List excludeVisibilities; + public String replyVisibility; public TimelineParams(@NonNull Timeline.TimeLineEnum timeLineEnum, @Nullable FragmentMastodonTimeline.DIRECTION timelineDirection, @Nullable String ident) { if (type != Timeline.TimeLineEnum.REMOTE) { diff --git a/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml b/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml new file mode 100644 index 000000000..86b72699d --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9e929584c..e3256ec44 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2174,4 +2174,5 @@ If your instance does not accept some extra features, you can hide these icons Display the \"Quote\" button Display \"Reactions\" buttons + Bubble \ No newline at end of file From 56e372a2f6d9ef32f8301d0c794b4e3b8b479557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Sun, 1 Jan 2023 04:50:23 +0100 Subject: [PATCH 05/68] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 99.6% (1017 of 1021 strings) Co-authored-by: Lukáš Jelínek Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/ Translation: Fedilab/Strings --- app/src/main/res/values-cs/strings.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 7b1e3eacc..53b785850 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -951,4 +951,14 @@ Klíč pro API překladače Verze Verze překladače + Viditelnost ikon + Můžete bezpečně skrýt tyto ikony v dolní oblasti, abyste získali více prostoru. Jsou k dispozici i v podnabídce. + Formát příspěvků + Ikony pro extra funkce + Pokud vaše instance nepodporuje některé extra funkce, můžete tyto ikony skýt + Zobrazit tlačítko „Citovat“ + Zobrazit tlačítko „Reakce“ + Povolením této volby se zobrazí extra funkce. Jsou určeny pro softwary sociálních sítí jako Pleroma, Akkoma nebo Glitch Social + Extra funkce + Formát příspěvků \ No newline at end of file From ec9e0dbbda774e125a47e83a3c6903290b25fefe Mon Sep 17 00:00:00 2001 From: claleb Date: Sun, 1 Jan 2023 04:50:23 +0100 Subject: [PATCH 06/68] Translated using Weblate (German) Currently translated at 100.0% (1021 of 1021 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/ Translation: Fedilab/Strings --- app/src/main/res/values-de/strings.xml | 315 +++++++++++++------------ 1 file changed, 163 insertions(+), 152 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 99c71d98e..f9615f7aa 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -41,7 +41,7 @@ Benutzername Entwürfe Favoriten - Neue Folgende + Neue Follower Erwähnungen Geteilte Beiträge Geteilte Beiträge anzeigen @@ -52,30 +52,30 @@ Startseite Lokale Zeitleiste Stummgeschaltete Nutzer - Blockierte Nutzer + Geblockte Nutzer Benachrichtigungen Folgeanfragen Einstellungen E-Mail senden - Geplante Nachrichten + Geplante Beiträge Die folgenden Informationen könnten das Profil des Nutzers unvollständig wiedergeben. Emoji einfügen Die App verfügt derzeit nicht über benutzerdefinierte Emojis. Bist Du sicher, dass Du Dich von @%1$s@%2$s abmelden möchtest\? - Keine Nachrichten zum Anzeigen - Diese Nachricht Deinen Favoriten hinzufügen\? - Diese Nachricht aus Ihren Favoriten entfernen\? - Diese Nachricht teilen\? - Geteilte Nachricht zurückziehen\? + Kein Beitrag zum Anzeigen + Diesen Beitrag Deinen Favoriten hinzufügen\? + Diesen Beitrag aus Deinen Favoriten entfernen\? + Diesen Beitrag teilen\? + Geteilten Beitrag zurückziehen\? Stummschalten - Sperren + Blockieren Melden Entfernen Kopieren Teilen Erwähnen - Zeitlich begrenzt stumm schalten + Zeitlich begrenzt stummschalten Löschen & neu entwerfen Lautlosmodus für dieses Konto aktivieren? @@ -120,11 +120,11 @@ %d Tage - Ein Fehler während der Auswahl ist aufgetreten! - Diese Datei löschen? - Deine Nachricht ist leer! - Die Nachricht wurde gesendet! - Vertrauliche Inhalte? + Bei der Medien-Auswahl ist ein Fehler aufgetreten! + Diese Datei entfernen\? + Dein Beitrag ist leer! + Der Beitrag wurde gesendet! + Sensibler Inhalt\? Keine Entwürfe vorhanden! Konto auswählen Konten auswählen @@ -141,48 +141,49 @@ Instanzensuche: - Keinen Nutzer gefunden - Keine Anfragen zu Folgen - Nachrichten + Kein Konto zum Anzeigen + Keine Folgeanfragen + Beiträge \n %1$s Folgt \n %1$s - Folgende \n %1$s + Follower +\n %1$s Ablehnen - Keine geplanten Nachrichten vorhanden! - Geplante Nachricht löschen\? - Die Nachricht wurde geplant! + Keine geplanten Beiträge zum Anzeigen! + Geplanten Beitrag löschen\? + Der Beitrag wurde geplant! Der geplante Termin muss in der Zukunft liegen! Die Dauer für die Stummschaltung sollte mehr als eine Minute betragen. - %1$s wurde bis %2$s lautlos geschaltet. -\n Du kannst die Stummschaltung für diese Person beenden, indem Du ihr Profil besuchst. - %1$s ist bis %2$s stumm geschaltet. + %1$s wurde bis %2$s stummgeschaltet. +\n Du kannst die Stummschaltung für dieses Konto beenden, indem Du die Profilseite besuchst. + %1$s ist bis %2$s stummgeschaltet. \n Hier antippen, um die Stummschaltung zu beenden. - Keine Benachrichtigungen + Keine Benachrichtigung zum Anzeigen hat dich erwähnt - hat eine neue Nachricht geschrieben + hat einen neuen Beitrag verfasst hat Deinen Beitrag geteilt hat Deinen Status favorisiert - folgt dir - fragte, dir zu folgen - Entferne alle Benachrichtigungen? + folgt Dir + fragt Dir zu folgen + Lösche alle Benachrichtigungen\? Alle Benachrichtigungen wurden gelöscht! - Folgende + Follower Fehler beim Laden der Client ID! - Konto wurde gesperrt! - Das Konto wurde entsperrt! - Nutzer wurde stumm geschaltet! + Das Konto wurde geblockt! + Das Konto wurde entblockt! + Das Konto wurde stummgeschaltet! Stummschaltung für dieses Konto aufgehoben! - Du folgst dem Nutzer! - Du folgst dem Nutzer nicht mehr! - Die Nachricht wurde geteilt! - Die Nachricht wird nicht länger geteilt! - Die Nachricht wurde Deinen Favoriten hinzugefügt! - Die Nachricht wurde aus Deinen Favoriten entfernt! + Du folgst dem Konto! + Du folgst dem Konto nicht mehr! + Der Beitrag wurde geteilt! + Der Beitrag wird nicht länger geteilt! + Der Beitrag wurde Deinen Favoriten hinzugefügt! + Der Beitrag wurde aus Deinen Favoriten entfernt! Es ist ein Fehler aufgetreten! Ein Fehler ist aufgetreten! Die Instanz hat keinen Autorisierungscode gesendet! Der Name der Instanz scheint ungültig zu sein! @@ -191,7 +192,7 @@ Keine Aktion kann durchgeführt werden Während der Übersetzung ist ein Fehler aufgetreten! - Anzahl der Nachrichten pro Ladevorgang + Anzahl der Beiträge pro Ladevorgang GIF Avatare deaktivieren Benachrichtigung wenn mir jemand folgt Benachrichtigung wenn jemand meinen Beitrag teilt @@ -199,14 +200,14 @@ Benachrichtigung wenn ich erwähnt werde Benachrichtigung wenn eine Umfrage beendet ist Benachrichtigung über neue Beiträge - Bestätigungsdialog vor dem Teilen anzeigen + Bestätigungsdialog vor dem Teilen eines Beitrags anzeigen Bestätigungsdialog vor dem Favorisieren anzeigen Benachrichtigen? - Leise Benachrichtigungen - NSFW Anzeigedauer (in Sekunden, 0 ≙ deaktiviert) - Timeout der Medienbeschreibung (Sekunden, 0 bedeutet aus) + Stille Benachrichtigungen + Anzeigedauer heikler Inhalte (NSFW) (Sekunden, 0 = deaktiviert) + Timeout der Medien-Beschreibung (Sekunden, 0 = deaktiviert) Benutzerdefiniertes Teilen - Ihre benutzerdefinierte Freigabeadresse … + Deine persönliche Freigabeadresse … Konto sperren Änderungen speichern Vorschaubilder anpassen @@ -214,7 +215,7 @@ und Benutze internen Browser In-App öffnen mit externem Browser - Inhaltswarnungen (CWs) automatisch einblenden + Inhaltswarnungen (CW) automatisch einblenden LED Farbe auswählen: Blau @@ -230,9 +231,9 @@ Stumm Stummschaltung beenden Anfrage gesendet - folgt dir + folgt Dir Ersten Buchstaben bei Antworten groß schreiben - Bildgröße verändern + Bildgröße ändern Videogröße ändern @@ -258,7 +259,7 @@ Zur Liste hinzufügen Liste löschen Neuer Listentitel - Das Konto wurde zur Liste hinzugefügt! + Das Konto wurde der Liste hinzugefügt! Du hast noch keine Listen! %1$s wurde verschoben nach %2$s @@ -270,7 +271,7 @@ Port Login Passwort - Nachricht-Details beim Teilen hinzufügen + Details des Beitrags beim Teilen hinzufügen Unterstütze die app auf Liberapay Es gibt einen Fehler im regulären Ausdruck! Es wurden keine Timelines in dieser Instanz gefunden! @@ -281,17 +282,17 @@ Auf Profil hervorheben Geteilte Beiträge von %s anzeigen Nicht mehr im Profil hervorheben - Direktnachrichten + Direktnachricht Filter Keine Filter vorhanden. Du kannst durch Klicken auf \"+\" neue Filter erstellen. Schlagwort oder Phrase Startseite Öffentliche Timeline Benachrichtigungen - Unterhaltungen - Wird unabhängig vom umgebenen Text oder Inhaltswarnung einer Nachricht verglichen + Unterhaltung + Wird unabhängig von der Groß-/Kleinschreibung in dem Text oder der Inhaltswarnung eines Beitrags verglichen Entfernen anstatt zu verstecken - Gefilterte Nachrichten werden unwiderruflich verschwinden, selbst wenn der Filter später entfernt wird + Gefilterte Beiträge werden unwiderruflich verschwinden, selbst wenn der Filter später entfernt wird Wenn das Schlüsselwort oder -phrase nur Buchstaben und Zahlen enthält, wird es nur angewendet werden, wenn es dem ganzen Wort entspricht Ganzes Wort Kontext filtern @@ -301,36 +302,36 @@ Filter aktualisieren Du hast noch keine Liste erstellt. Drücke auf den \"+\" Knopf um eine anzulegen. Versteckte Medien automatisch einblenden - Neuer Folgender - Neu geteilt + Neuer Follower + Neuer geteilter Beitrag Neuer Favorit Neue Erwähnung Umfrage beendet - Nachrichten-Sicherung + Sicherung der Beiträge Neue Beiträge - Medien Download + Medien-Download Klingelton auswählen Zeitfenster aktivieren - Möchtest Du %s wirklich sperren\? + Möchtest Du %s wirklich blockieren\? \n -\nEs werden keine Inhalte aus dieser Domain in einer öffentlichen Timeline oder in Deinen Benachrichtigungen angezeigt. Deine Follower aus dieser Domain werden entfernt. +\nDu wirst keine Inhalte mehr von dieser Domain in einer öffentlichen Timeline oder in Deinen Benachrichtigungen sehen. Deine Follower von dieser Domain werden entfernt. Blockiere Domäne - Die Domäne ist blockiert + Die Domäne ist geblockt Rufe entfernten Status ab Peertube Instanz Emoji One verwenden Information - Vorschau in allen Nachrichten anzeigen + Vorschau in allen Beiträgen anzeigen Konto-ID wurde in die Zwischenablage kopiert! Sprache ändern - Lange Nachrichten kürzen - Kürze Nachrichten mit mehr als x Zeilen. Null bedeutet deaktiviert. + Lange Beiträge kürzen + Kürze Beiträge mit mehr als \'x\' Zeilen. Null bedeutet deaktiviert. Mehr anzeigen Weniger anzeigen Dieser Hashtag existiert bereits! - Teilen des Beitrags planen - Teilen geplant! - Nichts geplant! + Planen eines geteilten Beitrags + Geteilter Beitrag ist geplant! + Keine geplanten Beiträge zum Anzeigen! Öffne Menü Profilbild Profilbanner @@ -340,7 +341,7 @@ Unterhaltung erweitern Benutzerdefinierte Emoji Auswahl Favicon - Medien zum Hinzufügen einer Beschreibung + Eine Beschreibung für Medien hinzufügen (für visuell eingeschränkte Personen) Nie 30 Minuten @@ -353,7 +354,7 @@ Sprachen Nur Medien - Heikle Inhalte anzeigen + Heikle Inhalte (NSFW) anzeigen Bot Pixelfed-Instanz Mastodon-Instanz @@ -370,8 +371,8 @@ Kategorie Beschreibung Teilen - Nachrichten (Server) - Nachrichten (Gerät) + Beiträge (Server) + Beiträge (Gerät) Timelines Benutzeroberfläche Kontakte @@ -393,7 +394,7 @@ endet um %s Abstimmen Eine Umfrage, in der Du abgestimmt hast, ist beendet - Eine Ihrer Umfragen wurde beendet + Eine Deiner Umfragen wurde beendet Kategorien Timeline verschieben Timeline ausblenden @@ -406,7 +407,7 @@ Medien immer als sensibel kennzeichnen GNU-Instanz Hashtags in Antworten übernehmen - Lange Drücken, um Medien zu speichern + Lange drücken, um Medien zu speichern Hashtags verwalten Anzeigename Emoji @@ -418,10 +419,10 @@ Grafik erfolgreich gespeichert! Grafik konnte nicht gespeichert werden Umfrageelement hinzufügen - Thema nicht mehr benachrichtigen - Thema erneut benachrichtigen - Nachrichten zu diesem Thema werden wieder benachrichtigt! - Nachrichten zu diesem Thema werden nicht mehr benachrichtigt + Unterhaltung stummschalten + Stummschaltung der Unterhaltung aufheben + Die Unterhaltung ist nicht länger stummgeschaltet! Du wirst wieder über Beiträge in dieser Unterhaltung informiert! + Die Unterhaltung ist stummgeschaltet! Du wirst nicht mehr über Beiträge in dieser Unterhaltung informiert Allgemein Regional Kunst @@ -439,7 +440,7 @@ Server-Regeln Nutzungsbedingungen Registrieren - Diese Instanz verwendet Einladungen. Ihr Konto muss von einem Administrator manuell genehmigt werden, bevor es verwendet werden kann. + Diese Instanz verwendet Einladungen. Dein Konto muss von einem Administrator manuell genehmigt werden, bevor es verwendet werden kann. Die Passwörter stimmen nicht überein! Ungültige E-Mail-Adresse! Du erhältst eine Bestätigungs-E-Mail @@ -454,7 +455,7 @@ \nDu kannst nun Dein Konto verbinden, indem Du %1$s in das erste Feld schreibst und auf die Schaltfläche Verbinden klickst. \n \nWichtig: Wenn Deine Instanz eine Bestätigung benötigt, erhältst Du eine E-Mail, sobald sie geprüft wurde! - Möchtest Du die Nachricht als Entwurf speichern\? + Möchtest Du den Beitrag als Entwurf speichern\? Verwaltung Berichte Ungelöst @@ -473,10 +474,10 @@ Unterbrechen widerrufen Die Anwendung benötigt Zugriff auf die Audioaufzeichnung Sprachnachricht - Innerhalb des Zeitfensters sendet die App Benachrichtigungen. Du kannst dieses Zeitfenster mit dem rechten Schieber zurücksetzen (d. h. leise). + Innerhalb des Zeitfensters sendet die App Benachrichtigungen. Du kannst dieses Zeitfenster mit dem Auswahlfeld rechts zurücksetzen (z. B. Still). Vorschauen in den Timelines werden nicht beschnitten Automatisches Einfügen eines Zeilenumbruchs nach einer Erwähnung, um den ersten Buchstaben groß zu schreiben - Ermöglicht es Inhaltserstellern, den Status ihrer RSS-Feeds zu teilen + Ermöglicht es Inhaltserstellern, ihre Beiträge als RSS-Feed zu teilen Verfassen Auswählen Instanz hinzufügen @@ -504,10 +505,10 @@ 3 Tage 7 Tage - Ihre Umfrage kann keine doppelten Optionen haben! - Cache beim Verlassen löschen - Der Cache (Medien, zwischengespeicherte Nachrichten, Daten aus dem eingebauten Browser) wird automatisch gelöscht, wenn die Anwendung verlassen wird. - Möchtest Du diesem Konto nicht mehr folgen\? + Deine Umfrage kann keine doppelten Optionen haben! + Zwischenspeicher beim Verlassen löschen + Der Zwischenspeicher (Medien, zwischengespeicherte Beiträge, Daten aus dem eingebauten Browser) wird automatisch gelöscht, wenn die Anwendung verlassen wird. + Möchtest Du diesem Konto entfolgen\? Bestätigungsdialog vor dem Entfolgen anzeigen Medium Nutze eine alternative Benutzeroberfläche für Medium @@ -519,10 +520,10 @@ Erlaube das Komprimieren von Videos während die Qualität erhalten bleibt. Sortieren nach Links - Ändert die Farbe der Links (URLs, Erwähnungen, Hashtags, etc.) in Nachrichten - Titelzeile des geteilten Beitrags - Ändern der Farbe des Anzeigenamens oben in den Nachrichten - Ändern der Farbe des Benutzernamens am Anfang von Nachrichten + Ändert die Farbe der Links (URLs, Erwähnungen, Hashtags, etc.) in Beiträgen + Kopfzeile des geteilten Beitrags + Ändert die Farbe des Anzeigenamens am Beginn eines Beitrags + Ändert die Farbe des Benutzernamens am Beginn eines Beitrags Ändert die Farbe der Kopfzeile von geteilten Beiträgen Beiträge Hintergrundfarbe der Beiträge in den Timelines @@ -536,7 +537,7 @@ Aktion ausführen Übersetzung Textfarbe - Ändere die Textfarbe in Nachrichten + Ändert die Textfarbe der Beiträge Verwende ein benutzerdefiniertes Design Farbschema Das Theme wurde exportiert @@ -567,11 +568,11 @@ Verifiziert von %1$s (%2$s) Aktion deaktiviert Entfolgen - Etwas ist schief gelaufen. Bitte überprüfen Sie Ihr Downloadverzeichnis in den Einstellungen. + Etwas ist schief gelaufen. Bitte überprüfe Dein Download-Verzeichnis in den Einstellungen. Ankündigungen Keine Ankündigungen! Eine Reaktion hinzufügen - Video-Cache in MB, Null bedeutet keinen Cache. + Video-Zwischenspeicher in MB, Null bedeutet keinen Zwischenspeicher. Wasserzeichen Automatisches Hinzufügen eines Wasserzeichens am unteren Rand von Bildern. Der Text kann für jedes Konto angepasst werden. Keine Dienste gefunden! @@ -584,7 +585,7 @@ Diese Instanz scheint nicht gültig zu sein! Geteilt von Favoritisiert von - Nur für Follower + Nur Follower Z. B.: Sensibler Inhalt Status hinzufügen Status entfernen @@ -593,8 +594,8 @@ Aufnahme anhalten Ich mag es nicht Es ist Spam - Die Nachricht wurde zu Deinen Lesezeichen hinzugefügt! - Die Nachricht wurde von Deinen Lesezeichen entfernt! + Der Beitrag wurde Deinen Lesezeichen hinzugefügt! + Der Beitrag wurde aus Deinen Lesezeichen entfernt! Anzahl der Konten pro Ladevorgang Musik Dieses Feld kann nicht leer sein! @@ -626,18 +627,18 @@ Weiterleiten an %1$s Komm ins Fediverse Erwähnungen - „Mastodon ist nicht wie Twitter oder Facebook, es besteht aus einem Netzwerk von tausenden, durch unterschiedliche Organisationen und Einzelpersonen betriebene, Gemeinschaften, die ein nahtloses Soziale-Medien-Erlebnis bieten.“ + „Mastodon ist keine einzelne Webseite wie Twitter oder Facebook, es besteht aus einem Netzwerk von tausenden, durch unterschiedliche Organisationen und Einzelpersonen betriebene Gemeinschaften, die ein nahtloses Soziale-Medien-Erlebnis bieten.“ Favoriten Änderungen speichern Gesperrt Entsperrt Feld hinzufügen Filter hinzufügen - Bist Du Dir sicher, dass Du alle Benachrichtigungen löschen willst\? Das kann nicht rückgängig gemacht werden. + Bist Du sicher, dass Du alle Benachrichtigungen löschen willst\? Das kann nicht rückgängig gemacht werden. Zeige alle Kategorien Ergebnisse der Umfrage Alle Benachrichtigungen als gelesen markieren - Alle Benachrichtigungen löschen + Alle Benachrichtigungen entfernen Geplant Profil wurde aktualisiert! Listenname ist nicht gültig! @@ -647,7 +648,7 @@ Art der Benachrichtigungen Benachrichtigungen deaktivieren Benachrichtigungstöne - Wähle die Art der Benachrichtigung + Wähle die Art der Benachrichtigungen Themen der Mitwirkenden Timelines anpassen Ein Thema wählen @@ -670,7 +671,7 @@ Bösartige Links, gefälschtes Engagement oder sich wiederholende Antworten Sage uns, was es mit diesem Beitrag auf sich hat Stummschalten %1$s - Blockieren %1$s + Blockiere %1$s Hallo! Wir laden Dich ein, dem Fediverse beizutreten. Bot-Konto Interaktionen @@ -678,7 +679,7 @@ Erlaubt die Erstellung des eigenen Themas Wähle, ob die Basis des Themas dunkel oder hell sein soll Arten der anzuzeigenden Benachrichtigungen - Standardmäßige Sichtbarkeit der Nachrichten: + Standardmäßige Sichtbarkeit der Beiträge: Anzahl an Benachrichtigungen pro Ladevorgang Nutze eine alternative Benutzeroberfläche für Instagram Instagram Frontend Domain @@ -687,15 +688,15 @@ Grundlage des Themas Während dieses Zeitfensters Schaltfläche \"Lesezeichen\" immer anzeigen - Das Konto stammt von einem anderen Server. Die anonymisierte Kopie des Berichts auch dorthin senden\? + Das Konto stammt von einem anderen Server. Eine anonymisierte Kopie des Berichts auch dorthin senden\? Wähle die beste Übereinstimmung Entfolge %1$s Du folgst diesem Konto. Um die Beiträge nicht mehr auf Deiner Startseite zu sehen, entfolge ihm. Du wirst ihre Beiträge nicht mehr sehen. Sie können Dir immer noch folgen und Deine Beiträge sehen und wissen nicht, dass sie stummgeschaltet sind. - Du wirst ihre Beiträge nicht mehr sehen. Sie werden Deine Beiträge nicht sehen und Dir nicht mehr folgen können. Sie werden erkennen können, dass sie blockiert sind. + Du wirst ihre Beiträge nicht mehr sehen. Sie werden Deine Beiträge nicht sehen und Dir nicht mehr folgen können. Sie können erkennen, dass sie geblockt sind. Geteilte Beiträge Aktualisierungen Anderer - Folgende + Folgt Auch geteilt von: Entfolgen bestätigen "Auch favorisiert von: " @@ -712,38 +713,38 @@ Hier tippen, um die Umfrage zu aktualisieren Linie Eckig - Datei-Cache Größe - Mehr Nachrichten laden… - Nachrichten in den Entwürfen gespeichert + Größe des Datei-Zwischenspeichers + Mehr Beiträge laden… + Beiträge als Entwürfe gespeichert Rund Radier-Modus Ankündigung · %1$s - %2$s - Cache leeren - Nachrichten im Cache für Startseite - Nachrichten im Cache für andere Timelines - Cache leeren - Bist Du Dir sicher den Cache zu leeren\? Angehängte Bilder/Videos werden in gespeicherten Entwürfen geschlöscht. + Zwischenspeicher löschen + Zwischenspeicher für Beiträge auf der Startseite + Zwischenspeicher für Beiträge in den anderen Timelines + Zwischenspeicher leeren + Bist Du Dir sicher, den Zwischenspeicher zu löschen\? Wenn Du gespeicherte Entwürfe mit angehängten Medien hast, gehen die Anhänge verloren. Verlassen, ohne das Bild zu speichern\? Form Domäne Personal - Nachrichtensprache + Sprache der Beiträge Meine Instanz Symbolgröße Einstellungen exportieren Vorschaubilder für Medien laden Timelines anzeigen - Die Anzahl neuer Nachrichten in den Timelines wird in der Registerkarte angezeigt + Die Anzahl neuer Beiträge wird in der Registerkarte der Timeline angezeigt Position in den Timelines merken Timelines werden zwischengespeichert, um die Anwendung zu beschleunigen. - Zwischengespeicherte Nachricht + Zwischengespeicherter Beitrag Antwort Anzeigeeinstellungen - Counter anzeigen + Anzahl anzeigen Meine App Mein Konto Versionshinweise - Medien in Benachrichtigung anzeigen + Medien in Benachrichtigungen anzeigen Logo auswählen Logo ändern Ändert das App-Logo auf dem Gerät @@ -754,20 +755,20 @@ Entwurf öffnen Einstellungen importieren Berechtigung nicht gestattet! - Nachricht anheften - Nachricht nicht mehr anheften + Beitrag anheften + Beitrag nicht mehr anheften Exportierte Einstellungen laden - Die Nachricht ist nicht mehr angeheftet! - Zeige Zähler für Nachrichten - Die Nachricht wurde angeheftet - Nachrichten übersetzen - Cache verwenden + Der Beitrag ist nicht mehr angeheftet! + Zeige Zähler für Beiträge + Der Beitrag wurde angeheftet + Beitrag übersetzen + Zwischenspeicher verwenden Medien anzeigen Timelines als Liste Wenn aktiv, werden alle angepinnten Timelines in einem Dropdown-Menü angezeigt Einfache Actionbar - Originalnachricht öffnen - Benachrichtigungsabrufzeit + Original-Beitrag öffnen + Abruf-Intervall Hole Benachrichtigungen Wenn aktiv, hat die App nur eine Anzeigeleiste für alle Timelines Datei konnte nicht hochgeladen werden! @@ -776,7 +777,7 @@ Verzögerung zwischen jedem Aktualisieren setzen Push-Dienst Die App konnte kein Token abrufen - Nachricht bearbeiten + Beitrag bearbeiten Angepinnte Timelines löschen\? Bericht eingereicht Datenschutz-Bestimmungen @@ -784,9 +785,9 @@ Bist Du sicher, dass diese Timeline nicht mehr angepinnt sein soll\? Geblockte Domänen %1$s bearbeitet %2$s - Domäne freigeben + Domäne entsperren Du hast keine Domänen geblockt - Sicher, dass Du %1$s wieder freigeben willst\? + Sicher, dass Du das Blockieren von %1$s aufheben möchtest\? Vorschläge Nicht interessiert Zuweisung aufheben @@ -798,9 +799,9 @@ Konto abgelehnt Konto genehmigt Meldung - Medien in Benachrichtigungen für geteilte Beiträge und Favoriten werden angezeigt + Medien werden in Benachrichtigungen für geteilte Beiträge und Favoriten angezeigt Übersetzung in eine bestimmte Sprache erzwingen. Wähle den ersten Wert, um auf Geräteeinstellungen zurückzusetzen - Nachrichten-Verlauf + Beitragsverlauf Bearbeitet am %1$s Erstellt am %1$s Nicht gelistete Antworten @@ -810,7 +811,7 @@ Aktuelle IP Erlauben Warnen - Benutzer per eMail benachrichtigen + Benutzer per E-Mail benachrichtigen Benutzerdefinierte Warnung Status von Meldungen Stummgeschaltet @@ -826,20 +827,20 @@ App neu starten\? Neustart Du musst die App neu starten um die Änderungen anzuwenden. - Du folgst bisher keinen Hashtags! - Hashtag nicht mehr folgen - Bist Du sicher dass Du diesem Hashtag nicht mehr folgen willst\? - Nicht mehr folgen + Du folgst keinen Hashtags! + Hashtag entfolgen + Bist Du sicher, dass Du diesem Hashtag entfolgen möchtest\? + Entfolgen Hashtag folgen Schreibe den Hashtag, dem Du folgen möchtest - Gefolgten Hashtags + Gefolgte Hashtags Hashtag folgen - Falls aktiv wird die App alle zusammenhängenden Benachrichtigungen einklappen + Wenn aktiviert, wird die App alle zusammengehörenden Benachrichtigungen einklappen Liste bearbeiten Profile Deine Instanz scheint diese Funktion nicht zu unterstützen! Erkunde Trends dieser Instanz - Nachricht bearbeiten + Beitrag wurde bearbeitet Aktualisierungen Mit Warnung verstecken Vollständig verstecken @@ -854,13 +855,13 @@ Timeline löschen Angemeldet Neue Registrierung - Eine Benutzer hat sich registriert + Ein Benutzer hat sich registriert Remote-Profil anzeigen Die App kann keine Remote-Daten finden! - Über Updates benachrichtigen + Benachrichtigung über Updates Domänen Neues Update - Eine Nachricht die Du geteilt hast wurde bearbeitet + Ein Beitrag, den Du geteilt hast, wurde bearbeitet Ein Benutzer hat eine Meldung gesendet Registrierungen Neue Meldung @@ -875,11 +876,11 @@ Betrifft nur \"öffentliche\" Antworten. Falls aktiv, werden Deine Antworten automatisch \"nicht gelistet\" statt \"öffentlich\" Anmeldestatus Sprachen in der Auswahl - Erlaube die Liste der Sprachen in der Auswahl beim Verfassen einer Nachricht zu reduzieren. + Reduziert die Liste der Sprachen-Auswahl beim Verfassen eines Beitrags. Bezeichnung des Hashtags ist nicht zulässig! Schweregrad Medien ablehnen - Mediendateien ablehnen + Medien-Dateien ablehnen Ignoriere alle Meldungen die von dieser Domäne kommen. Für Suspendierungen irrelevant Berichte ablehnen Domänenname verschleiern @@ -890,7 +891,7 @@ Domänen-Blockierung erstellen Mit einem anderen Konto öffnen Berichte ablehnen - Die Sperrung der Domäne verhindert nicht die Erstellung von Konto-Einträgen in der Datenbank, sondern wendet rückwirkend und automatisch bestimmte Moderations-Methoden auf diese Konten an. + Das Blockieren der Domäne verhindert nicht die Erstellung von Konto-Einträgen in der Datenbank, sondern wendet rückwirkend und automatisch bestimmte Moderations-Methoden auf diese Konten an. Ignoriere alle Meldungen die von dieser Domäne kommen. Für Suspendierungen irrelevant Stummschaltung macht die Beiträge des Kontos für alle unsichtbar, die ihm nicht folgen. Suspendierung entfernt alle Inhalte, Medien und Profildaten des Kontos. Verwende Keine, wenn Du nur die Mediendateien ablehnen möchtest. Verschleiere teilweise den Domänennamen in der Liste, wenn die Verteilung der Liste der Domänen-Beschränkunden aktiviert ist @@ -916,15 +917,15 @@ Eigene Farben auswählen Hell - Eigene Farben Dunkel - Eigene Farben - Entfernte Konversation anzeigen - Die Konversation begann auf Deiner Instanz! - Die Anwendung hat die entfernte Nachricht nicht gefunden. + Entfernte Unterhaltung (auf einer anderen Instanz) anzeigen + Die Unterhaltung begann auf Deiner Instanz! + Die Anwendung konnte den Beitrag (einer anderen Instanz) nicht finden. Hashtag stummschalten Anpinnen des Hashtags aufheben Stummschaltung des Hashtags aufheben Bitte später nochmal versuchen. Hashtag anpinnen - Alle Konten auf der Startseite stumm schalten. + Alle Konten auf der Startseite stummschalten. Alle Benutzer auf der Startseite stummschalten Daten importieren Gruppiere geteilte Beiträge auf der Startseite @@ -934,8 +935,8 @@ Hashtag entfolgen Auf der Startseite stummschalten Stummschaltung auf der Startseite aufheben - Entfernt den linken Rand in den Timelines, um Nachrichten kompakter darzustellen - Übersetzungs-Knopf immer anzeigen + Entfernt den linken Rand in den Timelines, um Beiträge kompakter darzustellen + Schaltfläche \"Übersetzen\" immer anzeigen Kartenansicht Entferne linken Rand Version @@ -943,4 +944,14 @@ Übersetzungsdienst Übersetzungsdienst-Version Übersetzungsdienst + Sichtbarkeit der Symbole + Du kannst die Symbole am unteren Rand bedenkenlos entfernen, um mehr Platz zu erhalten. Sie befinden sich auch im Untermenü. + Format des Beitrags + Format des Beitrags + Symbole für zusätzliche Funktionen + Zeige den Knopf zum \"Zitieren\" + Zeige Knöpfe für \"Reaktionen\" + Zusätzliche Funktionen + Wenn diese Option aktiviert ist, zeigt die App zusätzliche Funktionen an. Diese Funktion ist für soziale Plattformen wie Pleroma, Akkoma oder Glitch Social + Sofern Deine Instanz nicht alle zusätzlichen Funktionen unterstützt, kannst Du diese Symbole ausblenden \ No newline at end of file From e450589f76f23dedb12a86037717e4f3a67fc563 Mon Sep 17 00:00:00 2001 From: Oliebol Date: Sun, 1 Jan 2023 04:50:23 +0100 Subject: [PATCH 07/68] Translated using Weblate (Dutch) Currently translated at 99.8% (1019 of 1021 strings) Co-authored-by: Oliebol Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/ Translation: Fedilab/Strings --- app/src/main/res/values-nl/strings.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index f49402012..6874f8d7c 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -609,7 +609,7 @@ Profiel is bijgewerkt! Kies een thema Soorten meldingen tonen - Laad meer berichten… + Meer laden… Ovaal Rechthoek Wis modus @@ -935,4 +935,22 @@ Negeer tag Vertaalknop altijd tonen Maak tag los + Importeren gegevens + Beheer accounts + Verwijder linker kantlijn + Vertaler + Vertaler + Vertaler API key + Versie + Vertaler versie + Zet optie aan zodat de app meer mogelijkheden laat zien. Dit is voor social softwares zoals Pleroma, Akkoma or Glitch Social + Extra mogelijkheden + Zichtbaarheid iconen + Je kan deze iconen onderaan veilig verbergen voor meer ruimte. Ze staan ook in het submenu. + Iconen voor extra mogelijkheden + Als je instance niet alle mogelijkheden toestaat, kan je deze iconen verbergen + Toon de \"Quote\" knop + Toon \"Reacties\" knop + Groepeer reblogs in eigen tijdlijn + Verwijder linker kantlijn in tijdlijnen voor compactere berichten \ No newline at end of file From f4748cef954bdb27ab0eab3d2a4c53cd08cbb644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Sun, 1 Jan 2023 04:50:23 +0100 Subject: [PATCH 08/68] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (1021 of 1021 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/ Translation: Fedilab/Strings --- app/src/main/res/values-tr/strings.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 712ab75be..fef6b2ed1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -942,4 +942,14 @@ Çevirmen Çevirmen API anahtarı Sürüm + Ek özellikler + Bu seçeneği etkinleştirdiğinizde uygulama ek özellikler gösterecektir. Bu özellik Pleroma, Akkoma veya Glitch Social gibi sosyal yazılımlar için yapılır + Gönderi biçimi + Gönderi biçimi + Ek özellikler için simgeler + Sunucunuz bazı ek özellikleri kabul etmiyorsa, bu simgeleri gizleyebilirsiniz + \"Alıntı\" düğmesini göster + \"Tepkiler\" düğmelerini göster + Daha fazla alana sahip olmak için bu simgeleri alt kısımda güvenle gizleyebilirsiniz. Ayrıca alt menüde de bulunurlar. + Simge görünürlüğü \ No newline at end of file From a6f25737f7a93d7004bb12c38d06032b57523420 Mon Sep 17 00:00:00 2001 From: claleb Date: Sun, 1 Jan 2023 05:48:40 +0100 Subject: [PATCH 09/68] Translated using Weblate (German) Currently translated at 24.2% (16 of 66 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/ Translation: Fedilab/description --- .../fastlane/metadata/android/de/changelogs/455.txt | 9 +++++++++ .../fastlane/metadata/android/de/changelogs/456.txt | 10 ++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/455.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/456.txt diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/455.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/455.txt new file mode 100644 index 000000000..fa1fe51de --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/455.txt @@ -0,0 +1,9 @@ +Hinzugefügt: +- DeepL Übersetzung unterstützt Free/Pro-Tasten + +Geändert: +- Schaltflächen für Medien beim Bearbeiten ausblenden + +Behoben: +- GIFs werden als statische Bilder geladen +- Vorgeschlagene Konten können nicht verfolgt werden diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/456.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/456.txt new file mode 100644 index 000000000..411669664 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/456.txt @@ -0,0 +1,10 @@ +Geändert: +- Ausgeblendete Medien mit Vorschaubildern + +Behoben: +- Problem mit Medien für Android 11+ +- Absturz, wenn kein Übersetzungsschlüssel gesetzt wurde +- Behoben DeepL für API pro +- Absturz beim Besuch eines Profils mit vielen Medien +- Stummgeschaltete Konten funktionieren nicht ohne Filter +- Animierte benutzerdefinierte Emoji werden nicht angezeigt From 8fb7e4dc71c6377da5c9abc41df12cc39c0629c7 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Jan 2023 11:54:43 +0100 Subject: [PATCH 10/68] comment issue #702 - Add Bubble timeline --- .../app/fedilab/android/BaseMainActivity.java | 1 + .../client/entities/app/BubbleTimeline.java | 35 +++ .../client/entities/app/PinnedTimeline.java | 2 + .../app/fedilab/android/helper/Helper.java | 1 + .../android/helper/PinnedTimelineHelper.java | 245 ++++++++++++++++++ .../timeline/FragmentMastodonTimeline.java | 11 +- .../ui/pageadapter/FedilabPageAdapter.java | 2 + .../drawable/ic_baseline_bubble_chart_24.xml | 2 +- .../dialog_bubble_exclude_visibility.xml | 55 ++++ .../layout/dialog_bubble_reply_visibility.xml | 35 +++ .../main/res/menu/option_bubble_timeline.xml | 27 ++ app/src/main/res/values/strings.xml | 7 + 12 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/client/entities/app/BubbleTimeline.java create mode 100644 app/src/main/res/layout/dialog_bubble_exclude_visibility.xml create mode 100644 app/src/main/res/layout/dialog_bubble_reply_visibility.xml create mode 100644 app/src/main/res/menu/option_bubble_timeline.xml diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index a09a6ec54..ecfd4c635 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -683,6 +683,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt regex_local = sharedpreferences.getString(getString(R.string.SET_FILTER_REGEX_LOCAL) + currentUserID + currentInstance, null); regex_public = sharedpreferences.getString(getString(R.string.SET_FILTER_REGEX_PUBLIC) + currentUserID + currentInstance, null); show_art_nsfw = sharedpreferences.getBoolean(getString(R.string.SET_ART_WITH_NSFW) + currentUserID + currentInstance, false); + binding.profilePicture.setOnClickListener(v -> binding.drawerLayout.openDrawer(GravityCompat.START)); Helper.loadPP(BaseMainActivity.this, binding.profilePicture, currentAccount); headerMainBinding.accountAcc.setText(String.format("%s@%s", currentAccount.mastodon_account.username, currentAccount.instance)); diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/BubbleTimeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/BubbleTimeline.java new file mode 100644 index 000000000..b871af44c --- /dev/null +++ b/app/src/main/java/app/fedilab/android/client/entities/app/BubbleTimeline.java @@ -0,0 +1,35 @@ +package app.fedilab.android.client.entities.app; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * 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. + * + * Fedilab 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 Fedilab; if not, + * see . */ + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +public class BubbleTimeline implements Serializable { + @SerializedName("id") + public int id; + @SerializedName("only_media") + public boolean only_media = false; + @SerializedName("remote") + public boolean remote = false; + @SerializedName("with_muted") + public boolean with_muted; + @SerializedName("exclude_visibilities") + public List exclude_visibilities = null; + @SerializedName("reply_visibility") + public String reply_visibility = null; +} diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/PinnedTimeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/PinnedTimeline.java index 3bfa487b5..1158f816b 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/PinnedTimeline.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/PinnedTimeline.java @@ -38,6 +38,8 @@ public class PinnedTimeline implements Serializable { public RemoteInstance remoteInstance; @SerializedName("tagTimeline") public TagTimeline tagTimeline; + @SerializedName("bubbleTimeline") + public BubbleTimeline bubbleTimeline; @SerializedName("mastodonList") public MastodonList mastodonList; @SerializedName("currentFilter") diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index cb02fdb93..5af0b7272 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -257,6 +257,7 @@ public class Helper { public static final String ARG_SEARCH_KEYWORD_CACHE = "ARG_SEARCH_KEYWORD_CACHE"; public static final String ARG_VIEW_MODEL_KEY = "ARG_VIEW_MODEL_KEY"; public static final String ARG_TAG_TIMELINE = "ARG_TAG_TIMELINE"; + public static final String ARG_BUBBLE_TIMELINE = "ARG_BUBBLE_TIMELINE"; public static final String ARG_MEDIA_POSITION = "ARG_MEDIA_POSITION"; public static final String ARG_MEDIA_ATTACHMENT = "ARG_MEDIA_ATTACHMENT"; public static final String ARG_MEDIA_ATTACHMENTS = "ARG_MEDIA_ATTACHMENTS"; diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 2deefd41c..9457b9c5d 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -14,6 +14,7 @@ package app.fedilab.android.helper; * You should have received a copy of the GNU General Public License along with Fedilab; if not, * see . */ + import static app.fedilab.android.BaseMainActivity.currentAccount; import static app.fedilab.android.BaseMainActivity.currentInstance; import static app.fedilab.android.BaseMainActivity.currentUserID; @@ -59,6 +60,7 @@ import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.entities.api.MastodonList; import app.fedilab.android.client.entities.app.BottomMenu; +import app.fedilab.android.client.entities.app.BubbleTimeline; import app.fedilab.android.client.entities.app.Pinned; import app.fedilab.android.client.entities.app.PinnedTimeline; import app.fedilab.android.client.entities.app.RemoteInstance; @@ -66,6 +68,8 @@ import app.fedilab.android.client.entities.app.StatusCache; import app.fedilab.android.client.entities.app.TagTimeline; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.ActivityMainBinding; +import app.fedilab.android.databinding.DialogBubbleExcludeVisibilityBinding; +import app.fedilab.android.databinding.DialogBubbleReplyVisibilityBinding; import app.fedilab.android.databinding.TabCustomDefaultViewBinding; import app.fedilab.android.databinding.TabCustomViewBinding; import app.fedilab.android.exception.DBException; @@ -498,6 +502,9 @@ public class PinnedTimelineHelper { case TAG: tagClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); break; + case BUBBLE: + bubbleClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); + break; case REMOTE: if (pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER) { instanceClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); @@ -980,6 +987,244 @@ public class PinnedTimelineHelper { } + /** + * Manage long clicks on Bubble timelines + * + * @param activity - BaseMainActivity activity + * @param pinned - {@link Pinned} + * @param view - View + * @param position - int position of the tab + */ + public static void bubbleClick(BaseMainActivity activity, Pinned pinned, View view, ActivityMainBinding activityMainBinding, int position, String slug) { + int toRemove = itemToRemoveInBottomMenu(activity); + PopupMenu popup = new PopupMenu(activity, view); + int offSetPosition = position - (BOTTOM_TIMELINE_COUNT - toRemove); + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity); + boolean singleBar = sharedpreferences.getBoolean(activity.getString(R.string.SET_USE_SINGLE_TOPBAR), false); + if (singleBar) { + offSetPosition = position; + } + + if (pinned.pinnedTimelines.get(offSetPosition).bubbleTimeline == null) { + pinned.pinnedTimelines.get(offSetPosition).bubbleTimeline = new BubbleTimeline(); + } + BubbleTimeline bubbleTimeline = pinned.pinnedTimelines.get(offSetPosition).bubbleTimeline; + + popup.getMenuInflater() + .inflate(R.menu.option_bubble_timeline, popup.getMenu()); + Menu menu = popup.getMenu(); + + final MenuItem itemMediaOnly = menu.findItem(R.id.action_show_media_only); + final MenuItem itemRemote = menu.findItem(R.id.action_remote); + + + final boolean[] changes = {false}; + final boolean[] mediaOnly = {false}; + final boolean[] remote = {false}; + mediaOnly[0] = bubbleTimeline.only_media; + remote[0] = bubbleTimeline.remote; + itemMediaOnly.setChecked(mediaOnly[0]); + itemRemote.setChecked(remote[0]); + popup.setOnDismissListener(menu1 -> { + if (changes[0]) { + if (activityMainBinding.viewPager.getAdapter() != null) { + try { + new StatusCache(activity).deleteForSlug(slug); + } catch (DBException e) { + e.printStackTrace(); + } + + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(activity.getString(R.string.SET_INNER_MARKER) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance + slug, null); + editor.commit(); + Fragment fragmentMastodonTimeline = (Fragment) activityMainBinding.viewPager.getAdapter().instantiateItem(activityMainBinding.viewPager, activityMainBinding.tabLayout.getSelectedTabPosition()); + if (fragmentMastodonTimeline instanceof FragmentMastodonTimeline && fragmentMastodonTimeline.isVisible()) { + FragmentTransaction fragTransaction = activity.getSupportFragmentManager().beginTransaction(); + fragTransaction.detach(fragmentMastodonTimeline).commit(); + Bundle bundle = new Bundle(); + bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.BUBBLE); + bundle.putSerializable(Helper.ARG_BUBBLE_TIMELINE, bubbleTimeline); + bundle.putSerializable(Helper.ARG_INITIALIZE_VIEW, false); + fragmentMastodonTimeline.setArguments(bundle); + FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction(); + fragTransaction2.attach(fragmentMastodonTimeline); + fragTransaction2.commit(); + ((FragmentMastodonTimeline) fragmentMastodonTimeline).recreate(); + } + } + } + }); + + + int finalOffSetPosition = offSetPosition; + popup.setOnMenuItemClickListener(item -> { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); + item.setActionView(new View(activity)); + item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return false; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + return false; + } + }); + changes[0] = true; + int itemId = item.getItemId(); + if (itemId == R.id.action_show_media_only) { + mediaOnly[0] = !mediaOnly[0]; + bubbleTimeline.only_media = mediaOnly[0]; + pinned.pinnedTimelines.get(finalOffSetPosition).bubbleTimeline = bubbleTimeline; + itemMediaOnly.setChecked(mediaOnly[0]); + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } + } else if (itemId == R.id.action_remote) { + remote[0] = !remote[0]; + bubbleTimeline.remote = remote[0]; + pinned.pinnedTimelines.get(finalOffSetPosition).bubbleTimeline = bubbleTimeline; + itemRemote.setChecked(remote[0]); + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } + } else if (itemId == R.id.action_exclude_visibility) { + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle()); + DialogBubbleExcludeVisibilityBinding dialogBinding = DialogBubbleExcludeVisibilityBinding.inflate(activity.getLayoutInflater()); + dialogBuilder.setView(dialogBinding.getRoot()); + dialogBuilder.setTitle(R.string.exclude_visibility); + if (bubbleTimeline.exclude_visibilities == null) { + bubbleTimeline.exclude_visibilities = new ArrayList<>(); + } + for (String value : bubbleTimeline.exclude_visibilities) { + if (value.equalsIgnoreCase("public")) { + dialogBinding.valuePublic.setChecked(true); + } + if (value.equalsIgnoreCase("local")) { + dialogBinding.valueLocal.setChecked(true); + } + if (value.equalsIgnoreCase("direct")) { + dialogBinding.valueDirect.setChecked(true); + } + if (value.equalsIgnoreCase("list")) { + dialogBinding.valueList.setChecked(true); + } + if (value.equalsIgnoreCase("private")) { + dialogBinding.valuePrivate.setChecked(true); + } + if (value.equalsIgnoreCase("unlisted")) { + dialogBinding.valueUnlisted.setChecked(true); + } + } + dialogBinding.valuePrivate.setOnCheckedChangeListener((compoundButton, checked) -> { + if (checked) { + if (!bubbleTimeline.exclude_visibilities.contains("private")) { + bubbleTimeline.exclude_visibilities.add("private"); + } + } else { + bubbleTimeline.exclude_visibilities.remove("private"); + } + }); + dialogBinding.valueDirect.setOnCheckedChangeListener((compoundButton, checked) -> { + if (checked) { + if (!bubbleTimeline.exclude_visibilities.contains("direct")) { + bubbleTimeline.exclude_visibilities.add("direct"); + } + } else { + bubbleTimeline.exclude_visibilities.remove("direct"); + } + }); + dialogBinding.valueList.setOnCheckedChangeListener((compoundButton, checked) -> { + if (checked) { + if (!bubbleTimeline.exclude_visibilities.contains("list")) { + bubbleTimeline.exclude_visibilities.add("list"); + } + } else { + bubbleTimeline.exclude_visibilities.remove("list"); + } + }); + dialogBinding.valueLocal.setOnCheckedChangeListener((compoundButton, checked) -> { + if (checked) { + if (!bubbleTimeline.exclude_visibilities.contains("local")) { + bubbleTimeline.exclude_visibilities.add("local"); + } + } else { + bubbleTimeline.exclude_visibilities.remove("local"); + } + }); + dialogBinding.valuePublic.setOnCheckedChangeListener((compoundButton, checked) -> { + if (checked) { + if (!bubbleTimeline.exclude_visibilities.contains("public")) { + bubbleTimeline.exclude_visibilities.add("public"); + } + } else { + bubbleTimeline.exclude_visibilities.remove("public"); + } + }); + dialogBinding.valueUnlisted.setOnCheckedChangeListener((compoundButton, checked) -> { + if (checked) { + if (!bubbleTimeline.exclude_visibilities.contains("unlisted")) { + bubbleTimeline.exclude_visibilities.add("unlisted"); + } + } else { + bubbleTimeline.exclude_visibilities.remove("unlisted"); + } + }); + dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { + pinned.pinnedTimelines.get(finalOffSetPosition).bubbleTimeline = bubbleTimeline; + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } + }); + AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + } else if (itemId == R.id.action_reply_visibility) { + AlertDialog.Builder dialogBuilder; + AlertDialog alertDialog; + dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle()); + DialogBubbleReplyVisibilityBinding dialogBinding = DialogBubbleReplyVisibilityBinding.inflate(activity.getLayoutInflater()); + dialogBuilder.setView(dialogBinding.getRoot()); + dialogBuilder.setTitle(R.string.reply_visibility); + int checkedId = R.id.all; + if (bubbleTimeline.reply_visibility != null && bubbleTimeline.reply_visibility.equalsIgnoreCase("following")) { + checkedId = R.id.following; + } else if (bubbleTimeline.reply_visibility != null && bubbleTimeline.reply_visibility.equalsIgnoreCase("self")) { + checkedId = R.id.self; + } + dialogBinding.replyVisibility.check(checkedId); + dialogBinding.replyVisibility.setOnCheckedChangeListener((radioGroup, checkedElement) -> { + if (checkedElement == R.id.all) { + bubbleTimeline.reply_visibility = null; + } else if (checkedElement == R.id.following) { + bubbleTimeline.reply_visibility = "following"; + } else if (checkedElement == R.id.self) { + bubbleTimeline.reply_visibility = "self"; + } + }); + dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { + pinned.pinnedTimelines.get(finalOffSetPosition).bubbleTimeline = bubbleTimeline; + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } + }); + alertDialog = dialogBuilder.create(); + alertDialog.show(); + } + return false; + }); + popup.show(); + } + + /** * Manage long clicks on followed instances * diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 641a94ee3..cc7bdf6f5 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -51,6 +51,7 @@ import app.fedilab.android.client.entities.api.Attachment; import app.fedilab.android.client.entities.api.Pagination; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.api.Statuses; +import app.fedilab.android.client.entities.app.BubbleTimeline; import app.fedilab.android.client.entities.app.PinnedTimeline; import app.fedilab.android.client.entities.app.RemoteInstance; import app.fedilab.android.client.entities.app.StatusCache; @@ -165,6 +166,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private Statuses initialStatuses; private String list_id; private TagTimeline tagTimeline; + private BubbleTimeline bubbleTimeline; private LinearLayoutManager mLayoutManager; private Account accountTimeline; private boolean exclude_replies, exclude_reblogs, show_pinned, media_only, minified; @@ -331,6 +333,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. isViewInitialized = getArguments().getBoolean(Helper.ARG_INITIALIZE_VIEW, true); isNotPinnedTimeline = isViewInitialized; tagTimeline = (TagTimeline) getArguments().getSerializable(Helper.ARG_TAG_TIMELINE); + bubbleTimeline = (BubbleTimeline) getArguments().getSerializable(Helper.ARG_BUBBLE_TIMELINE); accountTimeline = (Account) getArguments().getSerializable(Helper.ARG_ACCOUNT); exclude_replies = !getArguments().getBoolean(Helper.ARG_SHOW_REPLIES, true); checkRemotely = getArguments().getBoolean(Helper.ARG_CHECK_REMOTELY, false); @@ -354,6 +357,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (tagTimeline.isART) { timelineType = Timeline.TimeLineEnum.ART; } + } else if (bubbleTimeline != null) { + ident = "@B@Bubble"; } else if (list_id != null) { ident = "@l@" + list_id; } else if (remoteInstance != null && !checkRemotely) { @@ -713,8 +718,10 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. timelineParams.remote = true; break; case BUBBLE: - timelineParams.onlyMedia = false; - timelineParams.remote = false; + timelineParams.onlyMedia = bubbleTimeline.only_media; + timelineParams.remote = bubbleTimeline.remote; + timelineParams.replyVisibility = bubbleTimeline.reply_visibility; + timelineParams.excludeVisibilities = bubbleTimeline.exclude_visibilities; break; case LIST: timelineParams.listId = list_id; diff --git a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java index aada3c696..326b3c654 100644 --- a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java @@ -137,6 +137,8 @@ public class FedilabPageAdapter extends FragmentStatePagerAdapter { bundle.putSerializable(Helper.ARG_TAG_TIMELINE, pinnedTimeline.tagTimeline); } else if (pinnedTimeline.type == Timeline.TimeLineEnum.REMOTE) { bundle.putSerializable(Helper.ARG_REMOTE_INSTANCE, pinnedTimeline); + } else if (pinnedTimeline.type == Timeline.TimeLineEnum.BUBBLE) { + bundle.putSerializable(Helper.ARG_BUBBLE_TIMELINE, pinnedTimeline.bubbleTimeline); } } diff --git a/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml b/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml index 86b72699d..8850e91f8 100644 --- a/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml +++ b/app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_bubble_reply_visibility.xml b/app/src/main/res/layout/dialog_bubble_reply_visibility.xml new file mode 100644 index 000000000..7739fb3d2 --- /dev/null +++ b/app/src/main/res/layout/dialog_bubble_reply_visibility.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/option_bubble_timeline.xml b/app/src/main/res/menu/option_bubble_timeline.xml new file mode 100644 index 000000000..e3b5c1eeb --- /dev/null +++ b/app/src/main/res/menu/option_bubble_timeline.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e3256ec44..dec946dd3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1365,6 +1365,8 @@ SET_LED_COLOUR_VAL_N SET_SHOW_BOOSTS SET_SHOW_REPLIES + + SET_DISABLE_ANIMATED_EMOJI SET_CAPITALIZE SET_THEME_BASE @@ -2175,4 +2177,9 @@ Display the \"Quote\" button Display \"Reactions\" buttons Bubble + Exclude visibility + Reply visibility + List + Following + Self \ No newline at end of file From c590ab48f5c2e7e63e7759c263475443dd6044be Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Jan 2023 11:55:32 +0100 Subject: [PATCH 11/68] Some cleaning --- .../app/fedilab/android/BaseMainActivity.java | 14 +- .../activities/AccountReportActivity.java | 1 + .../android/activities/ComposeActivity.java | 9 +- .../android/activities/ProfileActivity.java | 3 +- .../android/client/entities/api/Account.java | 60 +++---- .../android/client/entities/api/Status.java | 8 +- .../entities/api/admin/AdminAccount.java | 20 +-- .../client/entities/app/StatusCache.java | 2 +- .../app/fedilab/android/helper/Helper.java | 29 ++-- .../fedilab/android/helper/MediaHelper.java | 20 +-- .../android/helper/PinnedTimelineHelper.java | 1 - .../android/helper/SpannableHelper.java | 6 +- .../fedilab/android/helper/ThemeHelper.java | 2 - .../imageeditor/EditImageActivity.java | 4 +- .../android/ui/drawer/AccountAdapter.java | 2 +- .../android/ui/drawer/ComposeAdapter.java | 148 ++++++++-------- .../ui/drawer/ConversationAdapter.java | 32 ++-- .../android/ui/drawer/FieldAdapter.java | 2 +- .../android/ui/drawer/InstanceRegAdapter.java | 23 ++- .../ui/drawer/NotificationAdapter.java | 88 +++++----- .../android/ui/drawer/StatusAdapter.java | 163 +++++++++--------- .../fragment/admin/FragmentAdminReport.java | 1 - .../ui/fragment/login/FragmentLoginMain.java | 4 +- .../fragment/media/FragmentMediaProfile.java | 4 +- .../settings/FragmentThemingSettings.java | 1 - .../timeline/FragmentMastodonContext.java | 3 +- .../timeline/FragmentMastodonTimeline.java | 6 +- .../timeline/FragmentProfileTimeline.java | 1 + .../FedilabProfilePageAdapter.java | 2 +- .../FedilabProfileTLPageAdapter.java | 2 +- 30 files changed, 320 insertions(+), 341 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index ecfd4c635..dff1f87b1 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -165,6 +165,7 @@ import retrofit2.converter.gson.GsonConverterFactory; public abstract class BaseMainActivity extends BaseActivity implements NetworkStateReceiver.NetworkStateReceiverListener, FragmentMastodonTimeline.UpdateCounters, FragmentNotificationContainer.UpdateCounters, FragmentMastodonConversation.UpdateCounters { + private static final int REQUEST_CODE = 5415; public static String currentInstance, currentToken, currentUserID, client_id, client_secret, software; public static HashMap> emojis = new HashMap<>(); public static Account.API api; @@ -297,7 +298,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt }; private NetworkStateReceiver networkStateReceiver; private boolean headerMenuOpen; - private static final int REQUEST_CODE = 5415; @Override protected void onCreate(Bundle savedInstanceState) { @@ -786,7 +786,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt }); - binding.toolbarSearch.setOnSearchClickListener(v -> binding.tabLayout.setVisibility(View.VISIBLE)); //For receiving data from other activities LocalBroadcastManager.getInstance(BaseMainActivity.this).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA)); @@ -1042,7 +1041,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt String title = ""; String description = ""; - if(titleEl != null) { + if (titleEl != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { title = Html.fromHtml(titleEl.attr("content"), Html.FROM_HTML_MODE_LEGACY).toString(); } else { @@ -1050,7 +1049,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } } - if(descriptionEl != null) { + if (descriptionEl != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { description = Html.fromHtml(descriptionEl.attr("content"), Html.FROM_HTML_MODE_LEGACY).toString(); } else { @@ -1059,13 +1058,13 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } String imageUrl = ""; - if(imageUrlEl != null) { + if (imageUrlEl != null) { imageUrl = imageUrlEl.attr("content"); } StringBuilder titleBuilder = new StringBuilder(); - if(!originalUrl.trim().equalsIgnoreCase(sharedText.trim())) { + if (!originalUrl.trim().equalsIgnoreCase(sharedText.trim())) { // If the shared text is not just the URL, add it to the top String toAppend = sharedText.replaceAll("\\s*" + Pattern.quote(originalUrl) + "\\s*", ""); titleBuilder.append(toAppend); @@ -1073,7 +1072,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt if (title.length() > 0) { // OG title fetched from source - if(titleBuilder.length() > 0) titleBuilder.append("\n\n"); + if (titleBuilder.length() > 0) + titleBuilder.append("\n\n"); titleBuilder.append(title); } diff --git a/app/src/main/java/app/fedilab/android/activities/AccountReportActivity.java b/app/src/main/java/app/fedilab/android/activities/AccountReportActivity.java index 03fda1b7f..384a76980 100644 --- a/app/src/main/java/app/fedilab/android/activities/AccountReportActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/AccountReportActivity.java @@ -320,6 +320,7 @@ public class AccountReportActivity extends BaseBarActivity { } } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index 5ff370bac..622c3677a 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -107,11 +107,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana private Status statusReply, statusMention, statusQuoted; private StatusDraft statusDraft; private ComposeAdapter composeAdapter; - private boolean promptSaveDraft; - private boolean restoredDraft; - private List sharedAttachments; - - private final BroadcastReceiver imageReceiver = new BroadcastReceiver() { @Override public void onReceive(android.content.Context context, Intent intent) { @@ -138,7 +133,9 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana } } }; - + private boolean promptSaveDraft; + private boolean restoredDraft; + private List sharedAttachments; private ActivityPaginationBinding binding; private BaseAccount account; private String instance, token; diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index 97b13d769..1edb53858 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -117,8 +117,6 @@ public class ProfileActivity extends BaseActivity { private String mention_str; private WellKnownNodeinfo.NodeInfo nodeInfo; private boolean checkRemotely; - private boolean homeMuted; - private final BroadcastReceiver broadcast_data = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -133,6 +131,7 @@ public class ProfileActivity extends BaseActivity { } } }; + private boolean homeMuted; @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java index 6631be8fd..36667aa8c 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java @@ -87,28 +87,6 @@ public class Account implements Serializable { public Account moved; @SerializedName("role") public Role role; - - - public static class Role implements Serializable { - @SerializedName("id") - public String id; - @SerializedName("name") - public String name; - @SerializedName("color") - public String color; - @SerializedName("position") - public int position; - @SerializedName("permissions") - public int permissions; - @SerializedName("highlighted") - public boolean highlighted; - @SerializedName("created_at") - public Date created_at; - @SerializedName("updated_at") - public Date updated_at; - } - - public transient RelationShip relationShip; public synchronized Spannable getSpanDisplayName(Context context, WeakReference viewWeakReference) { @@ -133,6 +111,34 @@ public class Account implements Serializable { return SpannableHelper.convert(context, note, null, this, null, viewWeakReference); } + @Override + public boolean equals(@Nullable Object obj) { + boolean same = false; + if (obj instanceof Account) { + same = this.id.equals(((Account) obj).id); + } + return same; + } + + public static class Role implements Serializable { + @SerializedName("id") + public String id; + @SerializedName("name") + public String name; + @SerializedName("color") + public String color; + @SerializedName("position") + public int position; + @SerializedName("permissions") + public int permissions; + @SerializedName("highlighted") + public boolean highlighted; + @SerializedName("created_at") + public Date created_at; + @SerializedName("updated_at") + public Date updated_at; + } + public static class AccountParams implements Serializable { @SerializedName("discoverable") public boolean discoverable; @@ -150,14 +156,4 @@ public class Account implements Serializable { public LinkedHashMap fields; } - - - @Override - public boolean equals(@Nullable Object obj) { - boolean same = false; - if (obj instanceof Account) { - same = this.id.equals(((Account) obj).id); - } - return same; - } } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index ecc2a07ed..994a0d39b 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -153,10 +153,6 @@ public class Status implements Serializable, Cloneable { return contentTranslateSpan; } - public interface Callback { - void emojiFetched(); - } - @NonNull public Object clone() throws CloneNotSupportedException { return super.clone(); @@ -167,4 +163,8 @@ public class Status implements Serializable, Cloneable { BOTTOM } + public interface Callback { + void emojiFetched(); + } + } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/admin/AdminAccount.java b/app/src/main/java/app/fedilab/android/client/entities/api/admin/AdminAccount.java index 26eb86a75..070f91e3b 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/admin/AdminAccount.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/admin/AdminAccount.java @@ -25,16 +25,6 @@ import app.fedilab.android.client.entities.api.Account; public class AdminAccount implements Serializable { - @SerializedName("id") - public String id; - @SerializedName("username") - public String username; - @SerializedName("domain") - public String domain; - @SerializedName("created_at") - public Date created_at; - @SerializedName("email") - public String email; public static LinkedHashMap permissions; static { @@ -61,6 +51,16 @@ public class AdminAccount implements Serializable { permissions.put(80000, "Delete User Data"); } + @SerializedName("id") + public String id; + @SerializedName("username") + public String username; + @SerializedName("domain") + public String domain; + @SerializedName("created_at") + public Date created_at; + @SerializedName("email") + public String email; @SerializedName("ip") public String ip; @SerializedName("role") diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java b/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java index 626722580..d60a72ed1 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java @@ -509,7 +509,7 @@ public class StatusCache { try { db.delete(Sqlite.TABLE_STATUS_CACHE, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =? AND " + Sqlite.COL_STATUS + " LIKE ?", - new String[]{userid, instance, "%\"id\":\"" + targetedUser + "\"%" }); + new String[]{userid, instance, "%\"id\":\"" + targetedUser + "\"%"}); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index 5af0b7272..f8c588199 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -1965,6 +1965,20 @@ public class Helper { return R.style.AppTheme; } + public static void addMutedAccount(app.fedilab.android.client.entities.api.Account target) { + if (MainActivity.filteredAccounts == null) { + MainActivity.filteredAccounts = new ArrayList<>(); + } + if (!MainActivity.filteredAccounts.contains(target)) { + MainActivity.filteredAccounts.add(target); + } + } + + public static void removeMutedAccount(app.fedilab.android.client.entities.api.Account target) { + if (MainActivity.filteredAccounts != null) { + MainActivity.filteredAccounts.remove(target); + } + } //Enum that described actions to replace inside a toot content public enum PatternType { @@ -1996,19 +2010,4 @@ public class Helper { public interface OnFileCopied { void onFileCopied(File file); } - - public static void addMutedAccount(app.fedilab.android.client.entities.api.Account target) { - if (MainActivity.filteredAccounts == null) { - MainActivity.filteredAccounts = new ArrayList<>(); - } - if (!MainActivity.filteredAccounts.contains(target)) { - MainActivity.filteredAccounts.add(target); - } - } - - public static void removeMutedAccount(app.fedilab.android.client.entities.api.Account target) { - if (MainActivity.filteredAccounts != null) { - MainActivity.filteredAccounts.remove(target); - } - } } diff --git a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java index 352075b65..770436b5f 100644 --- a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java @@ -409,15 +409,6 @@ public class MediaHelper { return maxHeight; } - //Listener for recording media - public interface ActionRecord { - void onRecorded(String file); - } - - public interface OnSchedule { - void scheduledAt(String scheduledDate); - } - public static void ResizedImageRequestBody(Context context, Uri uri, File targetedFile) { InputStream decodeBitmapInputStream = null; try { @@ -529,7 +520,6 @@ public class MediaHelper { } } - private static long getMaxSize(long maxSize) { if (MainActivity.instanceInfo != null && MainActivity.instanceInfo.configuration != null && MainActivity.instanceInfo.configuration.media_attachments != null) { maxSize = MainActivity.instanceInfo.configuration.media_attachments.image_size_limit; @@ -584,4 +574,14 @@ public class MediaHelper { return null; } + + //Listener for recording media + public interface ActionRecord { + void onRecorded(String file); + } + + public interface OnSchedule { + void scheduledAt(String scheduledDate); + } + } diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 9457b9c5d..125212d38 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -98,7 +98,6 @@ public class PinnedTimelineHelper { } - public synchronized static void redrawTopBarPinned(BaseMainActivity activity, ActivityMainBinding activityMainBinding, Pinned pinned, BottomMenu bottomMenu, List mastodonLists) { //Values must be initialized if there is no records in db if (pinned == null) { diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 2e3ba27a1..f27a35939 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -88,16 +88,13 @@ import es.dmoral.toasty.Toasty; public class SpannableHelper { public static final String CLICKABLE_SPAN = "CLICKABLE_SPAN"; + private static int linkColor; public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, WeakReference viewWeakReference) { return convert(context, text, status, account, announcement, viewWeakReference, null); } - - private static int linkColor; - - public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, WeakReference viewWeakReference, Status.Callback callback) { @@ -613,7 +610,6 @@ public class SpannableHelper { } - /** * Remove extra carriage returns at the bottom due to

tags in toots * diff --git a/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java b/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java index 15fd4b083..46223b1a1 100644 --- a/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java @@ -70,7 +70,6 @@ public class ThemeHelper { } - /** * Animate two views, the current view will be hidden to left * @@ -230,7 +229,6 @@ public class ThemeHelper { } - /** * Allow to set colors for having description on media * diff --git a/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java b/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java index f0d5ea6ba..6433e0158 100644 --- a/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java +++ b/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java @@ -71,6 +71,8 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList private final ConstraintSet mConstraintSet = new ConstraintSet(); PhotoEditor mPhotoEditor; String path; + CropImageContractOptions cropImageContractOptions; + ActivityResultLauncher cropImageContractOptionsActivityResultLauncher; private PropertiesBSFragment mPropertiesBSFragment; private ShapeBSFragment mShapeBSFragment; private ShapeBuilder mShapeBuilder; @@ -79,8 +81,6 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList private Uri uri; private boolean exit; private ActivityEditImageBinding binding; - CropImageContractOptions cropImageContractOptions; - ActivityResultLauncher cropImageContractOptionsActivityResultLauncher; private static int exifToDegrees(int exifOrientation) { if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java index 3ccea89d7..9faa16bc1 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java @@ -56,8 +56,8 @@ import es.dmoral.toasty.Toasty; public class AccountAdapter extends RecyclerView.Adapter { private final List accountList; - private Context context; private final boolean home_mute; + private Context context; public AccountAdapter(List accountList, boolean home_mute) { this.accountList = accountList; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 0a6b23bac..dcfc31473 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -150,6 +150,30 @@ public class ComposeAdapter extends RecyclerView.Adapter statusList; + private final int TYPE_NORMAL = 0; + private final BaseAccount account; + private final String visibility; + private final app.fedilab.android.client.entities.api.Account mentionedAccount; + private final String editMessageId; + public ManageDrafts manageDrafts; + public promptDraftListener promptDraftListener; + private int statusCount; + private Context context; + private AlertDialog alertDialogEmoji; + private List emojisList = new ArrayList<>(); + private boolean unlisted_changed = false; + + public ComposeAdapter(List statusList, int statusCount, BaseAccount account, app.fedilab.android.client.entities.api.Account mentionedAccount, String visibility, String editMessageId) { + this.statusList = statusList; + this.statusCount = statusCount; + this.account = account; + this.mentionedAccount = mentionedAccount; + this.visibility = visibility; + this.editMessageId = editMessageId; + + } public static int countMorseChar(String content) { int count_char = 0; @@ -180,81 +204,6 @@ public class ComposeAdapter extends RecyclerView.Adapter statusList; - private final int TYPE_NORMAL = 0; - private final BaseAccount account; - private final String visibility; - private final app.fedilab.android.client.entities.api.Account mentionedAccount; - private final String editMessageId; - public ManageDrafts manageDrafts; - private int statusCount; - private Context context; - private AlertDialog alertDialogEmoji; - private List emojisList = new ArrayList<>(); - public promptDraftListener promptDraftListener; - private boolean unlisted_changed = false; - public static int currentCursorPosition; - - public ComposeAdapter(List statusList, int statusCount, BaseAccount account, app.fedilab.android.client.entities.api.Account mentionedAccount, String visibility, String editMessageId) { - this.statusList = statusList; - this.statusCount = statusCount; - this.account = account; - this.mentionedAccount = mentionedAccount; - this.visibility = visibility; - this.editMessageId = editMessageId; - - } - - /** - * Add an attachment from ComposeActivity - * - * @param position int - position of the drawer that added a media - * @param uris List - uris of the media - */ - public void addAttachment(int position, List uris) { - if (position == -1) { - position = statusList.size() - 1; - } - // position = statusCount-1+position; - if (statusList.get(position).media_attachments == null) { - statusList.get(position).media_attachments = new ArrayList<>(); - } - if (promptDraftListener != null) { - promptDraftListener.promptDraft(); - } - int finalPosition = position; - Helper.createAttachmentFromUri(context, uris, attachments -> { - for (Attachment attachment : attachments) { - statusList.get(finalPosition).media_attachments.add(attachment); - } - notifyItemChanged(finalPosition); - }); - } - - - /** - * Add an attachment from ComposeActivity - * - * @param position int - position of the drawer that added a media - * @param attachment Attachment - media attachment - */ - public void addAttachment(int position, Attachment attachment) { - if (position == -1) { - position = statusList.size() - 1; - } - // position = statusCount-1+position; - if (statusList.get(position).media_attachments == null) { - statusList.get(position).media_attachments = new ArrayList<>(); - } - if (promptDraftListener != null) { - promptDraftListener.promptDraft(); - } - int finalPosition = position; - statusList.get(finalPosition).media_attachments.add(attachment); - notifyItemChanged(finalPosition); - - } - private static void updateCharacterCount(ComposeViewHolder composeViewHolder) { int charCount = MastodonHelper.countLength(composeViewHolder); composeViewHolder.binding.characterCount.setText(String.valueOf(charCount)); @@ -285,6 +234,55 @@ public class ComposeAdapter extends RecyclerView.Adapter - uris of the media + */ + public void addAttachment(int position, List uris) { + if (position == -1) { + position = statusList.size() - 1; + } + // position = statusCount-1+position; + if (statusList.get(position).media_attachments == null) { + statusList.get(position).media_attachments = new ArrayList<>(); + } + if (promptDraftListener != null) { + promptDraftListener.promptDraft(); + } + int finalPosition = position; + Helper.createAttachmentFromUri(context, uris, attachments -> { + for (Attachment attachment : attachments) { + statusList.get(finalPosition).media_attachments.add(attachment); + } + notifyItemChanged(finalPosition); + }); + } + + /** + * Add an attachment from ComposeActivity + * + * @param position int - position of the drawer that added a media + * @param attachment Attachment - media attachment + */ + public void addAttachment(int position, Attachment attachment) { + if (position == -1) { + position = statusList.size() - 1; + } + // position = statusCount-1+position; + if (statusList.get(position).media_attachments == null) { + statusList.get(position).media_attachments = new ArrayList<>(); + } + if (promptDraftListener != null) { + promptDraftListener.promptDraft(); + } + int finalPosition = position; + statusList.get(finalPosition).media_attachments.add(attachment); + notifyItemChanged(finalPosition); + + } + //Create text when mentioning a toot public void loadMentions(Status status) { //Get the first draft diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java index 5651ca478..2defcdb7c 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java @@ -69,22 +69,6 @@ public class ConversationAdapter extends RecyclerView.Adapter { private final List fields; - private Context context; private final Account account; + private Context context; public FieldAdapter(List fields, Account account) { this.fields = fields; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java index 82a5703d8..f58954cbe 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java @@ -40,8 +40,12 @@ import app.fedilab.android.helper.Helper; public class InstanceRegAdapter extends RecyclerView.Adapter { private final List joinMastodonInstanceList; - private Context context; public ActionClick actionClick; + private Context context; + + public InstanceRegAdapter(List joinMastodonInstanceList) { + this.joinMastodonInstanceList = joinMastodonInstanceList; + } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { @@ -67,11 +71,6 @@ public class InstanceRegAdapter extends RecyclerView.Adapter actionClick.trends(position)); } - - public InstanceRegAdapter(List joinMastodonInstanceList) { - this.joinMastodonInstanceList = joinMastodonInstanceList; - } - public int getCount() { return joinMastodonInstanceList.size(); } @@ -88,12 +87,6 @@ public class InstanceRegAdapter extends RecyclerView.Adapter } - @Override - public void onAttachedToRecyclerView(RecyclerView recyclerView) { - super.onAttachedToRecyclerView(recyclerView); - - mRecyclerView = recyclerView; - } - - /* private static boolean mediaObfuscated(Status status) { - //Media is not sensitive and doesn't have a spoiler text - if (!status.isMediaObfuscated) { - return false; - } - if (!status.sensitive && (status.spoiler_text == null || status.spoiler_text.trim().isEmpty())) { - return false; - } - if (status.isMediaObfuscated && status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { - return true; - } else { - return status.sensitive; - } - }*/ - /** * Send a broadcast to other open fragments that content a timeline * @@ -2261,68 +2239,20 @@ public class StatusAdapter extends RecyclerView.Adapter LocalBroadcastManager.getInstance(context).sendBroadcast(intentBC); } - - @Override - public int getItemViewType(int position) { - if (timelineType == Timeline.TimeLineEnum.ART) { - return STATUS_ART; + /* private static boolean mediaObfuscated(Status status) { + //Media is not sensitive and doesn't have a spoiler text + if (!status.isMediaObfuscated) { + return false; + } + if (!status.sensitive && (status.spoiler_text == null || status.spoiler_text.trim().isEmpty())) { + return false; + } + if (status.isMediaObfuscated && status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { + return true; } else { - if (statusList.get(position).filteredByApp != null) { - if (statusList.get(position).filteredByApp.filter_action.equals("warn")) { - return STATUS_FILTERED; - } else { //These messages should not be displayed unless they contain a fetch more button - if (!statusList.get(position).isFetchMore) { - return STATUS_HIDDEN; - } else { - return STATUS_FILTERED_HIDE; - } - } - } else { - return isVisible(timelineType, statusList.get(position)) ? STATUS_VISIBLE : STATUS_HIDDEN; - } - + return status.sensitive; } - } - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - context = parent.getContext(); - if (viewType == STATUS_HIDDEN) { //Hidden statuses - ie: filtered - DrawerStatusHiddenBinding itemBinding = DrawerStatusHiddenBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); - return new StatusViewHolder(itemBinding); - } else if (viewType == STATUS_ART) { //Art statuses - DrawerStatusArtBinding itemBinding = DrawerStatusArtBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); - return new StatusViewHolder(itemBinding); - } else if (viewType == STATUS_FILTERED) { //Filtered warn - DrawerStatusFilteredBinding itemBinding = DrawerStatusFilteredBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); - return new StatusViewHolder(itemBinding); - } else if (viewType == STATUS_FILTERED_HIDE) { //Filtered hide - DrawerStatusFilteredHideBinding itemBinding = DrawerStatusFilteredHideBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); - return new StatusViewHolder(itemBinding); - } else { //Classic statuses - if (!minified) { - DrawerStatusBinding itemBinding = DrawerStatusBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); - return new StatusViewHolder(itemBinding); - } else { - DrawerStatusReportBinding itemBinding = DrawerStatusReportBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); - return new StatusViewHolder(itemBinding); - } - } - } - - public int getCount() { - return statusList.size(); - } - - public Status getItem(int position) { - return statusList.get(position); - } - - - public long getItemId(int position) { - return position; - } + }*/ public static void applyColor(Context context, StatusViewHolder holder) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); @@ -2410,6 +2340,74 @@ public class StatusAdapter extends RecyclerView.Adapter } } + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + + mRecyclerView = recyclerView; + } + + @Override + public int getItemViewType(int position) { + if (timelineType == Timeline.TimeLineEnum.ART) { + return STATUS_ART; + } else { + if (statusList.get(position).filteredByApp != null) { + if (statusList.get(position).filteredByApp.filter_action.equals("warn")) { + return STATUS_FILTERED; + } else { //These messages should not be displayed unless they contain a fetch more button + if (!statusList.get(position).isFetchMore) { + return STATUS_HIDDEN; + } else { + return STATUS_FILTERED_HIDE; + } + } + } else { + return isVisible(timelineType, statusList.get(position)) ? STATUS_VISIBLE : STATUS_HIDDEN; + } + + } + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + context = parent.getContext(); + if (viewType == STATUS_HIDDEN) { //Hidden statuses - ie: filtered + DrawerStatusHiddenBinding itemBinding = DrawerStatusHiddenBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); + } else if (viewType == STATUS_ART) { //Art statuses + DrawerStatusArtBinding itemBinding = DrawerStatusArtBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); + } else if (viewType == STATUS_FILTERED) { //Filtered warn + DrawerStatusFilteredBinding itemBinding = DrawerStatusFilteredBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); + } else if (viewType == STATUS_FILTERED_HIDE) { //Filtered hide + DrawerStatusFilteredHideBinding itemBinding = DrawerStatusFilteredHideBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); + } else { //Classic statuses + if (!minified) { + DrawerStatusBinding itemBinding = DrawerStatusBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); + } else { + DrawerStatusReportBinding itemBinding = DrawerStatusReportBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); + } + } + } + + public int getCount() { + return statusList.size(); + } + + public Status getItem(int position) { + return statusList.get(position); + } + + public long getItemId(int position) { + return position; + } + @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { //Nothing to do with hidden statuses @@ -2604,6 +2602,7 @@ public class StatusAdapter extends RecyclerView.Adapter DrawerStatusArtBinding bindingArt; DrawerStatusFilteredBinding bindingFiltered; DrawerStatusFilteredHideBinding bindingFilteredHide; + StatusViewHolder(DrawerStatusBinding itemView) { super(itemView.getRoot()); binding = itemView; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/admin/FragmentAdminReport.java b/app/src/main/java/app/fedilab/android/ui/fragment/admin/FragmentAdminReport.java index 2aad4a379..8f8cc33ba 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/admin/FragmentAdminReport.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/admin/FragmentAdminReport.java @@ -200,5 +200,4 @@ public class FragmentAdminReport extends Fragment { } - } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java b/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java index 8b4be76dd..6840be3a6 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginMain.java @@ -68,11 +68,11 @@ import es.dmoral.toasty.Toasty; public class FragmentLoginMain extends Fragment { + private static final int REQUEST_CODE = 5412; + private final int PICK_IMPORT = 5557; private FragmentLoginMainBinding binding; private boolean searchInstanceRunning = false; private String oldSearch; - private static final int REQUEST_CODE = 5412; - private final int PICK_IMPORT = 5557; private ActivityResultLauncher permissionLauncher; public View onCreateView(@NonNull LayoutInflater inflater, diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/media/FragmentMediaProfile.java b/app/src/main/java/app/fedilab/android/ui/fragment/media/FragmentMediaProfile.java index 2bfc17215..86670549e 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/media/FragmentMediaProfile.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/media/FragmentMediaProfile.java @@ -46,6 +46,8 @@ import es.dmoral.toasty.Toasty; public class FragmentMediaProfile extends Fragment { + String tempToken; + String tempInstance; private FragmentPaginationBinding binding; private AccountsVM accountsVM; private Account accountTimeline; @@ -53,8 +55,6 @@ public class FragmentMediaProfile extends Fragment { private List mediaStatuses; private String max_id; private ImageAdapter imageAdapter; - String tempToken; - String tempInstance; private boolean checkRemotely; private String accountId; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java index b6b407e5d..62ca1258c 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java @@ -32,7 +32,6 @@ import es.dmoral.toasty.Toasty; public class FragmentThemingSettings extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { - @Override public void onCreatePreferences(Bundle bundle, String s) { createPref(); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java index ffa1d1299..0e3352de5 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonContext.java @@ -50,12 +50,11 @@ import app.fedilab.android.viewmodel.mastodon.StatusesVM; public class FragmentMastodonContext extends Fragment { + public FirstMessage firstMessage; private FragmentPaginationBinding binding; private StatusesVM statusesVM; private List statuses; private StatusAdapter statusAdapter; - public FirstMessage firstMessage; - //Handle actions that can be done in other fragments private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index cc7bdf6f5..fd4543cb2 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -84,9 +84,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private StatusAdapter statusAdapter; private Timeline.TimeLineEnum timelineType; private List timelineStatuses; - private boolean checkRemotely; - private String accountIDInRemoteInstance; - //Handle actions that can be done in other fragments private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override @@ -162,6 +159,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } }; + private boolean checkRemotely; + private String accountIDInRemoteInstance; private boolean isViewInitialized; private Statuses initialStatuses; private String list_id; @@ -180,6 +179,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private int lockForResumeCall; private boolean isNotPinnedTimeline; private int extraCalls; + //Allow to recreate data when detaching/attaching fragment public void recreate() { initialStatuses = null; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentProfileTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentProfileTimeline.java index 76bec3fb4..a7a27092c 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentProfileTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentProfileTimeline.java @@ -36,6 +36,7 @@ public class FragmentProfileTimeline extends Fragment { private Account account; private FragmentProfileTimelinesBinding binding; private boolean checkRemotely; + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfilePageAdapter.java b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfilePageAdapter.java index 372f7659c..6d7a10e37 100644 --- a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfilePageAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfilePageAdapter.java @@ -30,8 +30,8 @@ import app.fedilab.android.ui.fragment.timeline.FragmentMastodonTimeline; public class FedilabProfilePageAdapter extends FragmentStatePagerAdapter { private final Account account; - private Fragment mCurrentFragment; private final boolean checkRemotely; + private Fragment mCurrentFragment; public FedilabProfilePageAdapter(FragmentManager fm, Account account, boolean remotely) { super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); diff --git a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfileTLPageAdapter.java b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfileTLPageAdapter.java index ca2ebb26a..582aa9d44 100644 --- a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfileTLPageAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabProfileTLPageAdapter.java @@ -30,8 +30,8 @@ import app.fedilab.android.ui.fragment.timeline.FragmentProfileTimeline; public class FedilabProfileTLPageAdapter extends FragmentStatePagerAdapter { private final Account account; - private Fragment mCurrentFragment; private final boolean checkRemotely; + private Fragment mCurrentFragment; public FedilabProfileTLPageAdapter(FragmentManager fm, Account account, boolean remotely) { super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); From 7303e7faa8258ae49f3ce1e384b5817537ef16ed Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Jan 2023 16:46:59 +0100 Subject: [PATCH 12/68] Spoiler text when editing --- .../app/fedilab/android/ui/drawer/ComposeAdapter.java | 7 ++++--- .../fastlane/metadata/android/en/changelogs/458.txt | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/458.txt diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index dcfc31473..6e8f290d2 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -1023,13 +1023,13 @@ public class ComposeAdapter extends RecyclerView.Adapter 0) { holder.binding.contentSpoiler.setVisibility(View.VISIBLE); } else { holder.binding.contentSpoiler.setVisibility(View.GONE); diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/458.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/458.txt new file mode 100644 index 000000000..e00871da3 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/458.txt @@ -0,0 +1,8 @@ +Added: +- Add Bubble timeline support in extra-features + +Changed: + + +Fixed: +- Spoiler text when editing \ No newline at end of file From 61798a7ce13d46e9346c545799a27c4a9ff6214b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Jan 2023 18:20:18 +0100 Subject: [PATCH 13/68] Release 3.13.4 --- app/src/main/assets/release_notes/notes.json | 5 +++++ .../fedilab/android/activities/ProfileActivity.java | 6 +++++- .../main/java/app/fedilab/android/helper/Helper.java | 12 +++++------- app/src/main/res/values/strings.xml | 4 ++++ app/src/main/res/xml/pref_interface.xml | 8 ++++++++ .../fastlane/metadata/android/en/changelogs/458.txt | 8 +++++--- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index 24c9070a8..6d5afedbc 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,9 @@ [ + { + "version": "3.13.4", + "code": "458", + "note": "Added:\n- Add Bubble timeline support in extra-features with filters\n- Allow to display public profiles by default to get all messages (Settings > Interface)\n\nChanged:\n- Full rework on links in messages (also mentions and tags)\n\nFixed:\n- Spoiler text when editing\n- Fix watermarks" + }, { "version": "3.13.3", "code": "457", diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index 1edb53858..1ab57d6d8 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -144,6 +144,7 @@ public class ProfileActivity extends BaseActivity { Bundle b = getIntent().getExtras(); binding.accountFollow.setEnabled(false); checkRemotely = false; + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this); homeMuted = false; if (b != null) { account = (Account) b.getSerializable(Helper.ARG_ACCOUNT); @@ -151,6 +152,9 @@ public class ProfileActivity extends BaseActivity { mention_str = b.getString(Helper.ARG_MENTION, null); checkRemotely = b.getBoolean(Helper.ARG_CHECK_REMOTELY, false); } + if (!checkRemotely) { + checkRemotely = sharedpreferences.getBoolean(getString(R.string.SET_PROFILE_REMOTELY), false); + } ActivityCompat.postponeEnterTransition(ProfileActivity.this); //Remove title if (actionBar != null) { @@ -161,7 +165,7 @@ public class ProfileActivity extends BaseActivity { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true); } - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this); + float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f); binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale); accountsVM = new ViewModelProvider(ProfileActivity.this).get(AccountsVM.class); diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index f8c588199..310edb0d4 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -1173,19 +1173,17 @@ public class Helper { File files = new File(attachment.local_path); float textSize = 15; Paint paint = new Paint(); - float textWidht = paint.measureText(waterMark); - float width = Helper.convertDpToPixel(textWidht, context); + float width = paint.measureText(waterMark, 0, waterMark.length()); try { BitmapFactory.Options options = new BitmapFactory.Options(); Bitmap backgroundBitmap = BitmapFactory.decodeFile(files.getAbsolutePath(), options); - - int w = options.outWidth; - int h = options.outHeight; - float valx = (float) 1.0 - width / (float) w; + int w = backgroundBitmap.getWidth(); + int h = backgroundBitmap.getHeight(); + float valx = (float) 1.0 - ((Helper.convertDpToPixel(width, context) + 10)) / (float) w; if (valx < 0) valx = 0; - float valy = (h - Helper.convertDpToPixel(textSize, context) - 10) / (float) h; + float valy = (h - Helper.convertDpToPixel(textSize, context) - 0) / (float) h; WatermarkText watermarkText = new WatermarkText(waterMark) .setPositionX(valx) .setPositionY(valy) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dec946dd3..8f1e603a3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1445,6 +1445,8 @@ SET_NOTIF_VALIDATION_FAV SET_DISPLAY_COUNTER_FAV_BOOST SET_REMOVE_LEFT_MARGIN + + SET_PROFILE_REMOTELY SET_EXTAND_EXTRA_FEATURES SET_INNER_MARKER @@ -2182,4 +2184,6 @@ List Following Self + Remote profiles + The app will display publicly profiles to get all messages. Interactions will need an extra step to federate messages. \ No newline at end of file diff --git a/app/src/main/res/xml/pref_interface.xml b/app/src/main/res/xml/pref_interface.xml index 55b5f58ec..ef3387c38 100644 --- a/app/src/main/res/xml/pref_interface.xml +++ b/app/src/main/res/xml/pref_interface.xml @@ -28,6 +28,14 @@ app:summary="@string/set_remove_left_margin" app:title="@string/set_remove_left_margin_title" /> + + Interface) Changed: - +- Full rework on links in messages (also mentions and tags) Fixed: -- Spoiler text when editing \ No newline at end of file +- Spoiler text when editing +- Fix watermarks \ No newline at end of file From cbc5eddc9c3b62604f845599f6f154295e5d894b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 1 Jan 2023 18:23:00 +0100 Subject: [PATCH 14/68] Release 3.13.4 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8aace30fe..464da616d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 33 - versionCode 457 - versionName "3.13.3" + versionCode 458 + versionName "3.13.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" From 0d1107ec15244f66002070aaef57dc150b931920 Mon Sep 17 00:00:00 2001 From: claleb Date: Sun, 1 Jan 2023 18:21:06 +0100 Subject: [PATCH 15/68] Translated using Weblate (German) Currently translated at 100.0% (1027 of 1027 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/ Translation: Fedilab/Strings --- app/src/main/res/values-de/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f9615f7aa..945744eb7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -954,4 +954,10 @@ Zusätzliche Funktionen Wenn diese Option aktiviert ist, zeigt die App zusätzliche Funktionen an. Diese Funktion ist für soziale Plattformen wie Pleroma, Akkoma oder Glitch Social Sofern Deine Instanz nicht alle zusätzlichen Funktionen unterstützt, kannst Du diese Symbole ausblenden + Liste + Eigene + Gefolgte + Sichtbarkeit von Antworten + Sichtbarkeit ausschließen + Blase \ No newline at end of file From 0ec4e0c51bbb7efa957a08a738ae9a3866cddce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Sun, 1 Jan 2023 18:21:06 +0100 Subject: [PATCH 16/68] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (1027 of 1027 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/ Translation: Fedilab/Strings --- app/src/main/res/values-tr/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index fef6b2ed1..dab0ab049 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -952,4 +952,10 @@ \"Tepkiler\" düğmelerini göster Daha fazla alana sahip olmak için bu simgeleri alt kısımda güvenle gizleyebilirsiniz. Ayrıca alt menüde de bulunurlar. Simge görünürlüğü + Hariç tutma görünürlüğü + Listele + Takip edilenler + Baloncuk + Yanıt görünürlüğü + Kendi \ No newline at end of file From 6a98b4db48a87278ad76de0235f905fb59738d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Mon, 2 Jan 2023 07:51:07 +0100 Subject: [PATCH 17/68] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 99.2% (1022 of 1030 strings) Co-authored-by: Lukáš Jelínek Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/ Translation: Fedilab/Strings --- app/src/main/res/values-cs/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 53b785850..5bce7b73a 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -961,4 +961,8 @@ Povolením této volby se zobrazí extra funkce. Jsou určeny pro softwary sociálních sítí jako Pleroma, Akkoma nebo Glitch Social Extra funkce Formát příspěvků + Bublina + K získání všech zpráv bude aplikace veřejně zobrazovat profily. Interakce budou k federaci zpráv potřebovat dodatečný krok. + Seznam + Vzdálené profily \ No newline at end of file From ccdbc2f45a6f89285e7e6abd175c917c56c73447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Mon, 2 Jan 2023 07:51:07 +0100 Subject: [PATCH 18/68] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (1030 of 1030 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/ Translation: Fedilab/Strings --- app/src/main/res/values-tr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dab0ab049..e01bdd5da 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -958,4 +958,6 @@ Baloncuk Yanıt görünürlüğü Kendi + Uzak profiller + Uygulama, tüm mesajları almak için herkese açık profilleri görüntüleyecektir. Etkileşimlerin mesajları birleştirmek için ek bir adıma ihtiyacı olacaktır. \ No newline at end of file From 64e50bd8b50520ca2891babadf8cfc50dad7029d Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 2 Jan 2023 15:06:31 +0100 Subject: [PATCH 19/68] Fix crashes --- .../fedilab/android/helper/PinnedTimelineHelper.java | 6 ++++++ .../app/fedilab/android/helper/SpannableHelper.java | 3 +++ .../ui/fragment/timeline/FragmentMastodonTimeline.java | 10 ++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 125212d38..f95e42c38 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -183,6 +183,12 @@ public class PinnedTimelineHelper { if (extraFeatures) { try { Pinned pinnedAll = new Pinned(activity).getAllPinned(currentAccount); + if (pinnedAll == null) { + pinnedAll = new Pinned(); + pinnedAll.user_id = currentUserID; + pinnedAll.instance = currentInstance; + pinnedAll.pinnedTimelines = new ArrayList<>(); + } boolean createDefaultBubbleAtTop = true; for (PinnedTimeline pinnedTimeline : pinnedAll.pinnedTimelines) { if (pinnedTimeline.type == Timeline.TimeLineEnum.BUBBLE) { diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index f27a35939..2ddf9a6fa 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -299,6 +299,9 @@ public class SpannableHelper { } int matchEnd = start + newUrl.length(); String finalUrl = url; + if (content.length() < matchEnd) { + matchEnd = content.length(); + } content.setSpan(new LongClickableSpan() { @Override public void onLongClick(View view) { diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index fd4543cb2..318de33de 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -718,10 +718,12 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. timelineParams.remote = true; break; case BUBBLE: - timelineParams.onlyMedia = bubbleTimeline.only_media; - timelineParams.remote = bubbleTimeline.remote; - timelineParams.replyVisibility = bubbleTimeline.reply_visibility; - timelineParams.excludeVisibilities = bubbleTimeline.exclude_visibilities; + if (bubbleTimeline != null) { + timelineParams.onlyMedia = bubbleTimeline.only_media; + timelineParams.remote = bubbleTimeline.remote; + timelineParams.replyVisibility = bubbleTimeline.reply_visibility; + timelineParams.excludeVisibilities = bubbleTimeline.exclude_visibilities; + } break; case LIST: timelineParams.listId = list_id; From 508f3c62536300ad825122577253436fee5351d1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 2 Jan 2023 16:20:58 +0100 Subject: [PATCH 20/68] comment #702 - Add post local only (Glitch) --- .../android/client/entities/api/Status.java | 2 ++ .../fedilab/android/jobs/ComposeWorker.java | 3 +++ .../android/ui/drawer/ComposeAdapter.java | 23 +++++++++++++++++++ .../android/ui/drawer/StatusAdapter.java | 7 ++++++ .../drawable/ic_baseline_local_only_24.xml | 10 ++++++++ app/src/main/res/layout/drawer_status.xml | 8 +++++++ .../main/res/layout/drawer_status_compose.xml | 13 ++++++++++- app/src/main/res/values/strings.xml | 8 +++++++ 8 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_baseline_local_only_24.xml diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index 994a0d39b..98ad50cda 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -102,6 +102,8 @@ public class Status implements Serializable, Cloneable { public List filtered; @SerializedName("pleroma") public Pleroma pleroma; + @SerializedName("local_only") + public boolean local_only = false; @SerializedName("cached") public boolean cached = false; public Attachment art_attachment; diff --git a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java index 05ed092b9..6637c03cc 100644 --- a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java +++ b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java @@ -218,6 +218,9 @@ public class ComposeWorker extends Worker { return; } String language = sharedPreferences.getString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + dataPost.userId + dataPost.instance, null); + if (statuses.get(i).local_only) { + statuses.get(i).text += " \uD83D\uDC41"; + } if (dataPost.scheduledDate == null) { if (dataPost.statusEditId == null) { statusCall = mastodonStatusesService.createStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 6e8f290d2..054e6e4de 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -1279,6 +1279,7 @@ public class ComposeAdapter extends RecyclerView.Adapter { AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle()); builder.setTitle(context.getString(R.string.post_format)); @@ -1304,6 +1305,28 @@ public class ComposeAdapter extends RecyclerView.Adapter dialog.dismiss()); builder.create().show(); }); + holder.binding.buttonLocalOnly.setOnClickListener(v -> { + AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle()); + builder.setTitle(context.getString(R.string.local_only)); + Resources res = context.getResources(); + boolean[] valArr = new boolean[]{false, true}; + String[] labelArr = res.getStringArray(R.array.set_local_only); + + int selection = 0; + boolean localOnly = sharedpreferences.getBoolean(context.getString(R.string.SET_LOCAL_ONLY) + account.user_id + account.instance, false); + if (statusDraft.local_only || localOnly) { + selection = 1; + } + builder.setSingleChoiceItems(labelArr, selection, null); + builder.setPositiveButton(R.string.validate, (dialog, which) -> { + int selectedPosition = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); + statusDraft.local_only = valArr[selectedPosition]; + notifyItemChanged(holder.getLayoutPosition()); + dialog.dismiss(); + }); + builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + builder.create().show(); + }); } else { holder.binding.buttonTextFormat.setVisibility(View.GONE); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index eaa6a1de7..6a7c78753 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -1053,6 +1053,13 @@ public class StatusAdapter extends RecyclerView.Adapter ressource = R.drawable.ic_baseline_mail_24; break; } + + if (statusToDeal.local_only) { + holder.binding.localOnly.setVisibility(View.VISIBLE); + } else { + holder.binding.localOnly.setVisibility(View.GONE); + } + if (status.isFocused) { holder.binding.statusInfo.setVisibility(View.VISIBLE); holder.binding.reblogsCount.setText(String.valueOf(status.reblogs_count)); diff --git a/app/src/main/res/drawable/ic_baseline_local_only_24.xml b/app/src/main/res/drawable/ic_baseline_local_only_24.xml new file mode 100644 index 000000000..ba4d830ec --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_local_only_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index 7dcc0a61d..d28cfe2bb 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -159,6 +159,14 @@ android:singleLine="true" tools:text="@tools:sample/full_names" /> + + @@ -103,6 +103,17 @@ app:layout_constraintTop_toBottomOf="@id/button_emoji_one" tools:visibility="visible" /> + + text/x.misskeymarkdown + + + No + Yes + + Always Wifi only @@ -1435,6 +1441,7 @@ SET_DISPLAY_TRANSLATE SET_POST_FORMAT + SET_LOCAL_ONLY SET_TRANSLATOR SET_TRANSLATOR_VERSION @@ -2186,4 +2193,5 @@ Self Remote profiles The app will display publicly profiles to get all messages. Interactions will need an extra step to federate messages. + Local only \ No newline at end of file From 537bb3f6220dce331cf164622c3ae578c82eb043 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 2 Jan 2023 17:28:09 +0100 Subject: [PATCH 21/68] Release 3.13.5 --- app/build.gradle | 4 ++-- app/src/main/assets/release_notes/notes.json | 5 +++++ .../android/ui/drawer/ComposeAdapter.java | 9 ++++++--- .../settings/FragmentExtraFeaturesSettings.java | 13 +++++++++++++ app/src/main/res/values/strings.xml | 9 +++++++-- app/src/main/res/xml/pref_extra_features.xml | 17 +++++++++++++++++ .../metadata/android/en/changelogs/459.txt | 5 +++++ 7 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/459.txt diff --git a/app/build.gradle b/app/build.gradle index 464da616d..47616d831 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 33 - versionCode 458 - versionName "3.13.4" + versionCode 459 + versionName "3.13.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index 6d5afedbc..f0b81c4b6 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,9 @@ [ + { + "version": "3.13.5", + "code": "459", + "note": "Added:\n- Glitch: Allow to post messages locally (Can be turned off in Settings)\n\nFixed:\n- Crashes" + }, { "version": "3.13.4", "code": "458", diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 054e6e4de..2d02e143e 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -1278,8 +1278,11 @@ public class ComposeAdapter extends RecyclerView.Adapter { AlertDialog.Builder builder = new AlertDialog.Builder(context, Helper.dialogStyle()); builder.setTitle(context.getString(R.string.post_format)); @@ -1313,8 +1316,8 @@ public class ComposeAdapter extends RecyclerView.Adaptertext/x.misskeymarkdown + + 0 + 1 + No @@ -1441,7 +1445,7 @@ SET_DISPLAY_TRANSLATE SET_POST_FORMAT - SET_LOCAL_ONLY + SET_COMPOSE_LOCAL_ONLY SET_TRANSLATOR SET_TRANSLATOR_VERSION @@ -1455,7 +1459,7 @@ SET_PROFILE_REMOTELY SET_EXTAND_EXTRA_FEATURES - + SET_DISPLAY_LOCAL_ONLY SET_INNER_MARKER SET_NOTIF_SILENT SET_REMEMBER_POSITION @@ -2194,4 +2198,5 @@ Remote profiles The app will display publicly profiles to get all messages. Interactions will need an extra step to federate messages. Local only + Display \"Local only\" button \ No newline at end of file diff --git a/app/src/main/res/xml/pref_extra_features.xml b/app/src/main/res/xml/pref_extra_features.xml index 91d0a2637..26af2edf3 100644 --- a/app/src/main/res/xml/pref_extra_features.xml +++ b/app/src/main/res/xml/pref_extra_features.xml @@ -47,6 +47,12 @@ app:key="@string/SET_DISPLAY_REACTIONS" app:singleLineTitle="false" app:title="@string/set_display_reaction_indication" /> + + + \ No newline at end of file diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/459.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/459.txt new file mode 100644 index 000000000..e5cf9e108 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/459.txt @@ -0,0 +1,5 @@ +Added: +- Glitch: Allow to post messages locally (Can be turned off in Settings) + +Fixed: +- Crashes \ No newline at end of file From 66acb1b8d875dd980100d133584920942a510ba8 Mon Sep 17 00:00:00 2001 From: claleb Date: Mon, 2 Jan 2023 16:21:59 +0100 Subject: [PATCH 22/68] Translated using Weblate (German) Currently translated at 100.0% (1030 of 1030 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/ Translation: Fedilab/Strings --- app/src/main/res/values-de/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 945744eb7..221603ae3 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -960,4 +960,6 @@ Sichtbarkeit von Antworten Sichtbarkeit ausschließen Blase + Die Anwendung ruft öffentlich verfügbare Profile ab, um deren Beiträge darzustellen. Interaktionen mit föderierten Beiträgen benötigen einen zusätzlichen Arbeitsschritt. + Profile auf anderen Instanzen \ No newline at end of file From df5354ec1e6a0d18328d5d329d6b1a091eb33f0b Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 3 Jan 2023 09:07:41 +0100 Subject: [PATCH 23/68] Fix issue #719 - Wrong instance emojis with cross compose --- .../app/fedilab/android/activities/ComposeActivity.java | 4 ++-- .../app/fedilab/android/ui/drawer/ComposeAdapter.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index 622c3677a..e7596ed0d 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -534,10 +534,10 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana if (token == null) { token = account.token; } - if (emojis == null || !emojis.containsKey(currentInstance)) { + if (emojis == null || !emojis.containsKey(instance)) { new Thread(() -> { try { - emojis.put(currentInstance, new EmojiInstance(ComposeActivity.this).getEmojiList(currentInstance)); + emojis.put(instance, new EmojiInstance(ComposeActivity.this).getEmojiList(instance)); } catch (DBException e) { e.printStackTrace(); } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 2d02e143e..fbd59767d 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -1488,7 +1488,7 @@ public class ComposeAdapter extends RecyclerView.Adapter { try { - displayEmojiPicker(holder); + displayEmojiPicker(holder, account.instance); } catch (DBException e) { e.printStackTrace(); } @@ -1875,7 +1875,7 @@ public class ComposeAdapter extends RecyclerView.Adapter 0) { GridView gridView = new GridView(context); - gridView.setAdapter(new EmojiAdapter(emojis.get(BaseMainActivity.currentInstance))); + gridView.setAdapter(new EmojiAdapter(emojis.get(instance))); gridView.setNumColumns(5); gridView.setOnItemClickListener((parent, view, position, id) -> { - holder.binding.content.getText().insert(holder.binding.content.getSelectionStart(), " :" + emojis.get(BaseMainActivity.currentInstance).get(position).shortcode + ": "); + holder.binding.content.getText().insert(holder.binding.content.getSelectionStart(), " :" + emojis.get(instance).get(position).shortcode + ": "); alertDialogEmoji.dismiss(); }); gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp); From d9f477a57f9d0281bbd3ae2980b01746da0b9007 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 3 Jan 2023 10:59:25 +0100 Subject: [PATCH 24/68] Fix issue #715 - Custom emoji not displayed in notifications --- .../java/app/fedilab/android/ui/drawer/NotificationAdapter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java index e91b862b4..4ae229416 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java @@ -437,7 +437,6 @@ public class NotificationAdapter extends RecyclerView.Adapter(holderStatus.bindingNotification.status.displayName), title), TextView.BufferType.SPANNABLE); - holderStatus.bindingNotification.status.displayName.setText(title, TextView.BufferType.SPANNABLE); holderStatus.bindingNotification.status.username.setText(String.format("@%s", notification.account.acct)); holderStatus.bindingNotification.status.actionButtons.setVisibility(View.GONE); } From 580024e1b99026791459c7fe976033f2bf91715a Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 3 Jan 2023 11:31:12 +0100 Subject: [PATCH 25/68] Fix issue #710 - Fav/Boost markers with shared message from conversations are not applied in timeline --- .../timeline/FragmentMastodonTimeline.java | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 318de33de..72c08c85e 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -100,12 +100,24 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (receivedStatus != null && statusAdapter != null) { int position = getPosition(receivedStatus); if (position >= 0) { - timelineStatuses.get(position).reblog = receivedStatus.reblog; - timelineStatuses.get(position).reblogged = receivedStatus.reblogged; - timelineStatuses.get(position).favourited = receivedStatus.favourited; - timelineStatuses.get(position).bookmarked = receivedStatus.bookmarked; - timelineStatuses.get(position).reblogs_count = receivedStatus.reblogs_count; - timelineStatuses.get(position).favourites_count = receivedStatus.favourites_count; + if (receivedStatus.reblog != null) { + timelineStatuses.get(position).reblog = receivedStatus.reblog; + } + if (timelineStatuses.get(position).reblog != null) { + timelineStatuses.get(position).reblog.reblogged = receivedStatus.reblogged; + timelineStatuses.get(position).reblog.favourited = receivedStatus.favourited; + timelineStatuses.get(position).reblog.bookmarked = receivedStatus.bookmarked; + timelineStatuses.get(position).reblog.reblogs_count = receivedStatus.reblogs_count; + timelineStatuses.get(position).reblog.favourites_count = receivedStatus.favourites_count; + } else { + timelineStatuses.get(position).reblogged = receivedStatus.reblogged; + timelineStatuses.get(position).favourited = receivedStatus.favourited; + timelineStatuses.get(position).bookmarked = receivedStatus.bookmarked; + timelineStatuses.get(position).reblogs_count = receivedStatus.reblogs_count; + timelineStatuses.get(position).favourites_count = receivedStatus.favourites_count; + } + + statusAdapter.notifyItemChanged(position); } } else if (delete_statuses_for_user != null && statusAdapter != null) { @@ -242,7 +254,10 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. return -1; } for (Status _status : timelineStatuses) { - if (_status.id != null && _status.id.compareTo(status.id) == 0) { + if (_status.reblog == null && _status.id != null && _status.id.compareTo(status.id) == 0) { + found = true; + break; + } else if (_status.reblog != null && _status.reblog.id != null && _status.reblog.id.compareTo(status.id) == 0) { found = true; break; } From 1edd554fdea4e4a7b5b1d0667c0b9cf34baf6447 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 3 Jan 2023 13:42:46 +0100 Subject: [PATCH 26/68] Fix issue #712 - Empty notifications --- .../ui/drawer/NotificationAdapter.java | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java index 4ae229416..441537763 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java @@ -47,6 +47,7 @@ import app.fedilab.android.client.entities.api.Notification; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.DrawerFollowBinding; import app.fedilab.android.databinding.DrawerStatusFilteredBinding; +import app.fedilab.android.databinding.DrawerStatusFilteredHideBinding; import app.fedilab.android.databinding.DrawerStatusNotificationBinding; import app.fedilab.android.databinding.NotificationsRelatedAccountsBinding; import app.fedilab.android.helper.Helper; @@ -70,6 +71,7 @@ public class NotificationAdapter extends RecyclerView.Adapter Date: Tue, 3 Jan 2023 14:10:42 +0100 Subject: [PATCH 27/68] Fix some issues --- .../java/app/fedilab/android/activities/ComposeActivity.java | 1 + .../java/app/fedilab/android/ui/drawer/NotificationAdapter.java | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index e7596ed0d..a97cd6da7 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -634,6 +634,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana } if (statusReply.spoiler_text != null) { statusDraftList.get(0).spoiler_text = statusReply.spoiler_text; + statusDraftList.get(0).spoilerChecked = true; } if (statusReply.language != null && !statusReply.language.isEmpty()) { statusDraftList.get(0).language = statusReply.language; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java index 441537763..932d6e089 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java @@ -313,8 +313,6 @@ public class NotificationAdapter extends RecyclerView.Adapter Date: Tue, 3 Jan 2023 14:22:28 +0100 Subject: [PATCH 28/68] Fix expand media with fit preview images when sensitive --- .../app/fedilab/android/ui/drawer/StatusAdapter.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 6a7c78753..5f2b90257 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -392,6 +392,7 @@ public class StatusAdapter extends RecyclerView.Adapter boolean confirmFav = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION_FAV), false); boolean confirmBoost = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION), true); boolean fullAttachement = sharedpreferences.getBoolean(context.getString(R.string.SET_FULL_PREVIEW), false); + boolean expand_media = sharedpreferences.getBoolean(context.getString(R.string.SET_EXPAND_MEDIA), false); boolean displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK) + MainActivity.currentUserID + MainActivity.currentInstance, true); boolean displayTranslate = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_TRANSLATE) + MainActivity.currentUserID + MainActivity.currentInstance, false); boolean displayCounters = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COUNTER_FAV_BOOST), false); @@ -1278,7 +1279,7 @@ public class StatusAdapter extends RecyclerView.Adapter boolean singleMedia = statusToDeal.media_attachments.size() == 1; for (Attachment attachment : statusToDeal.media_attachments) { LayoutMediaBinding layoutMediaBinding = LayoutMediaBinding.inflate(LayoutInflater.from(context)); - if (fullAttachement && !statusToDeal.sensitive) { + if (fullAttachement && (!statusToDeal.sensitive || expand_media)) { float ratio = 1.0f; float mediaH = -1.0f; @@ -1317,7 +1318,7 @@ public class StatusAdapter extends RecyclerView.Adapter loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, -1.f, -1.f, -1.f, statusToDeal, attachment, singleMedia); } mediaPosition++; - if ((fullAttachement && !statusToDeal.sensitive) || singleMedia) { + if ((fullAttachement && (!statusToDeal.sensitive || expand_media)) || singleMedia) { holder.binding.mediaContainer.addView(layoutMediaBinding.getRoot()); } else { holder.binding.attachmentsList.addView(layoutMediaBinding.getRoot()); @@ -2100,7 +2101,7 @@ public class StatusAdapter extends RecyclerView.Adapter boolean expand_media = sharedpreferences.getBoolean(context.getString(R.string.SET_EXPAND_MEDIA), false); LinearLayout.LayoutParams lp; - if (fullAttachement && mediaH > 0 && !statusToDeal.sensitive) { + if (fullAttachement && mediaH > 0 && (!statusToDeal.sensitive || expand_media)) { lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) (mediaH * ratio)); layoutMediaBinding.media.setScaleType(ImageView.ScaleType.FIT_CENTER); } else { @@ -2214,7 +2215,7 @@ public class StatusAdapter extends RecyclerView.Adapter adapter.notifyItemChanged(holder.getBindingAdapterPosition()); }); - if (!statusToDeal.sensitive && (fullAttachement || singleImage)) { + if ((!statusToDeal.sensitive || expand_media) && (fullAttachement || singleImage)) { layoutMediaBinding.getRoot().setPadding(0, 0, 0, 10); } else { layoutMediaBinding.getRoot().setPadding(0, 0, 10, 0); From 807530f8d6aac7e10b0aac50fc0b85e463352f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Tue, 3 Jan 2023 14:51:01 +0100 Subject: [PATCH 29/68] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 99.2% (1026 of 1034 strings) Co-authored-by: Lukáš Jelínek Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/ Translation: Fedilab/Strings --- app/src/main/res/values-cs/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 5bce7b73a..824cc58af 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -965,4 +965,6 @@ K získání všech zpráv bude aplikace veřejně zobrazovat profily. Interakce budou k federaci zpráv potřebovat dodatečný krok. Seznam Vzdálené profily + Zobrazit tlačítko „Jen místní“ + Jen místní \ No newline at end of file From 32105309756921e4a01bfc0084fda0aca45f2f12 Mon Sep 17 00:00:00 2001 From: claleb Date: Tue, 3 Jan 2023 14:51:02 +0100 Subject: [PATCH 30/68] Translated using Weblate (German) Currently translated at 100.0% (1034 of 1034 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/ Translation: Fedilab/Strings --- app/src/main/res/values-de/strings.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 221603ae3..a489bd956 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -482,7 +482,7 @@ Auswählen Instanz hinzufügen Absturzberichte aktivieren - Wenn aktiviert, wird ein Absturzbericht erstellt. Anschließend kannst Du diesen teilen. + Wenn aktiviert, wird ein Absturzbericht auf Deinem Mobiltelefon erstellt. Anschließend kannst Du diesen teilen. Fedilab ist abgestürzt :( Du kannst mir den Fehlerreport per E-Mail senden. Dies hilft mir bei der Fehlerbehebung:)\n\nDu kannst weitere Inhalte hinzufügen. Danke! Sichtbarkeit @@ -950,7 +950,7 @@ Format des Beitrags Symbole für zusätzliche Funktionen Zeige den Knopf zum \"Zitieren\" - Zeige Knöpfe für \"Reaktionen\" + Zeige die Knöpfe für \"Reaktionen\" Zusätzliche Funktionen Wenn diese Option aktiviert ist, zeigt die App zusätzliche Funktionen an. Diese Funktion ist für soziale Plattformen wie Pleroma, Akkoma oder Glitch Social Sofern Deine Instanz nicht alle zusätzlichen Funktionen unterstützt, kannst Du diese Symbole ausblenden @@ -962,4 +962,6 @@ Blase Die Anwendung ruft öffentlich verfügbare Profile ab, um deren Beiträge darzustellen. Interaktionen mit föderierten Beiträgen benötigen einen zusätzlichen Arbeitsschritt. Profile auf anderen Instanzen + Nur Lokal + Zeige den Knopf \"Nur Lokal\" \ No newline at end of file From 5480ff91d23403749990e0d48659d76113e1b01e Mon Sep 17 00:00:00 2001 From: RintanBroadleaf Date: Tue, 3 Jan 2023 14:51:02 +0100 Subject: [PATCH 31/68] Translated using Weblate (Japanese) Currently translated at 100.0% (1034 of 1034 strings) Co-authored-by: RintanBroadleaf Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/ Translation: Fedilab/Strings --- app/src/main/res/values-ja/strings.xml | 47 ++++++++++++++++++++------ 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index c67ed5d53..676ecadd9 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -185,7 +185,7 @@ 何もすることはできません 翻訳中にエラーが発生しました! - 一回あたりに読み込む投稿数 + 1回あたりに読み込む投稿の数 GIFアバターを無効にする フォローされたときに通知する 投稿がブーストされたときに通知する @@ -501,7 +501,7 @@ このアカウントのフォローを解除しますか? フォローを解除する前に確認を表示する Medium - Mediumの代替フロントエンドを使用する + Mediumの代替フロントエンドを使用します Mediumフロントエンドのドメイン プッシュ通知システムを使用してリアルタイムに通知を取得します。 メモを追加 @@ -613,11 +613,11 @@ 1回あたりに読み込む通知の数 音楽 Twitter - Twitterの代替フロントエンドを使用する + Twitterの代替フロントエンドを使用します Twitterフロントエンドのドメイン Instagramフロントエンドのドメイン Reddit - Redditの代替フロントエンドを使用する + Redditの代替フロントエンドを使用します 続行 カスタム 次のユーザーにブーストされました @@ -660,11 +660,11 @@ 1回あたりに読み込むアカウントの数 この項目は空欄にできません! YouTube - YouTubeの代替フロントエンドを使用する + YouTubeの代替フロントエンドを使用します YouTubeフロントエンドのドメイン Redditフロントエンドのドメイン Instagram - Instagramの代替フロントエンドを使用する + Instagramの代替フロントエンドを使用します フォロワーのみ ステータスを追加 このサーバーは無効なようです! @@ -861,7 +861,7 @@ 登録しました データをインポート 通報を却下 - 新着情報の通知 + 新着情報を通知する 新しい通報(モデレーター) 新着情報 新規登録 @@ -890,7 +890,7 @@ 通知を消去しない ダイナミックカラー 個人設定の壁紙の配色に合わせます。 - 翻訳ボタンを常に表示します + 翻訳ボタンを常に表示する 通報を却下 ドメイン名の難読化 公開コメント @@ -904,7 +904,7 @@ カスタムカラーの設定 時間をおいて再試行してください。 ホームでのミュート - タイムライン上の左のマージンを削除し、投稿をよりコンパクトにします + タイムライン上の左の余白をなくし、投稿をよりコンパクトにします 通報しました ドメイン 新規登録(モデレーター) @@ -921,12 +921,37 @@ 全てのアカウントがホームタイムライン上でミュートされます。 全てのユーザーをホームでのミュート対象として追加 選択をミュート - ホームタイムラインでブーストをグループ化 + ホームタイムラインでブーストをグループ化する アカウントの管理 - 左のマージンを削除 + 左の余白を詰める このドメインからの通報を全て無視します。サスペンドとは無関係です ドメイン制限リストの公開が有効なとき、リスト内のドメイン名を一部難読化します 内部コメント このドメイン制限に関するコメントで、モデレーターによって内部で使用されます。 このドメイン制限に関するコメントで、ドメイン制限リストの公開が有効な場合に一般外部向けに使用されます。 + 翻訳ツールのバージョン + 「引用」ボタンを表示 + バブル + 表示設定を除外する + フォロー中 + 自分 + リモートプロフィール + 翻訳 + 翻訳ツールのAPIキー + バージョン + 投稿形式 + スペースを増やすために下部にあるこれらのアイコンを安全に非表示にできます。サブメニューからも利用可能です。 + 追加機能 + このオプションを有効にするとアプリは追加の機能を表示します。これはPleromaやAkkoma、Glitch Socialなどのソフトウェア向きの機能です + アイコンの表示設定 + 投稿形式 + 追加機能のアイコン + サーバーが一部の追加機能を無効にしている場合、それらのアイコンを非表示にできます + アプリは全ての投稿を表示するために公開プロフィールにアクセスします。交流する場合は投稿を連合させるために追加の操作を必要とします。 + 「リアクション」ボタンを表示 + 返信の公開範囲 + ローカルのみ + リスト + 「ローカルのみ」ボタンを表示 + 翻訳 \ No newline at end of file From f140b2883a94895c40e7d13d677eee9ff9d21561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Tue, 3 Jan 2023 14:51:02 +0100 Subject: [PATCH 32/68] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (1034 of 1034 strings) Co-authored-by: Oğuz Ersen Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/ Translation: Fedilab/Strings --- app/src/main/res/values-tr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index e01bdd5da..784df89b2 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -960,4 +960,6 @@ Kendi Uzak profiller Uygulama, tüm mesajları almak için herkese açık profilleri görüntüleyecektir. Etkileşimlerin mesajları birleştirmek için ek bir adıma ihtiyacı olacaktır. + \"Yalnızca yerel\" düğmesini göster + Yalnızca yerel \ No newline at end of file From 886f0660712373563f6c51d92a83c41d2d32f954 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 3 Jan 2023 17:29:53 +0100 Subject: [PATCH 33/68] Fix issue #607 - Issue with fetchmore --- .../app/fedilab/android/activities/ComposeActivity.java | 4 +++- .../app/fedilab/android/client/entities/api/Status.java | 4 ++-- .../java/app/fedilab/android/ui/drawer/StatusAdapter.java | 1 - .../ui/fragment/timeline/FragmentMastodonTimeline.java | 7 +++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index a97cd6da7..849b28a94 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -634,7 +634,9 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana } if (statusReply.spoiler_text != null) { statusDraftList.get(0).spoiler_text = statusReply.spoiler_text; - statusDraftList.get(0).spoilerChecked = true; + if (statusReply.spoiler_text.trim().length() > 0) { + statusDraftList.get(0).spoilerChecked = true; + } } if (statusReply.language != null && !statusReply.language.isEmpty()) { statusDraftList.get(0).language = statusReply.language; diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index 98ad50cda..fb3919a5e 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -109,8 +109,8 @@ public class Status implements Serializable, Cloneable { public Attachment art_attachment; public boolean isExpended = false; public boolean isTruncated = true; - public boolean isFetchMore = false; - public PositionFetchMore positionFetchMore = PositionFetchMore.BOTTOM; + public transient boolean isFetchMore = false; + public transient PositionFetchMore positionFetchMore = PositionFetchMore.BOTTOM; public boolean isChecked = false; public String translationContent; public boolean translationShown; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 5f2b90257..a7fc576c1 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -2031,7 +2031,6 @@ public class StatusAdapter extends RecyclerView.Adapter drawerFetchMoreBinding.fetchMoreMin.setOnClickListener(v -> { status.isFetchMore = false; int position = holder.getBindingAdapterPosition(); - int position2 = getStatusPosition(statusList, status); adapter.notifyItemChanged(position); if (position < statusList.size() - 1) { String fromId; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 72c08c85e..560809216 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -407,7 +407,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. binding.swipeContainer.setRefreshing(false); binding.loadingNextElements.setVisibility(View.GONE); flagLoading = false; - + int currentPosition = mLayoutManager.findFirstVisibleItemPosition(); if (timelineStatuses != null && fetched_statuses != null && fetched_statuses.statuses != null && fetched_statuses.statuses.size() > 0) { try { if (statusToUpdate != null) { @@ -470,7 +470,10 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. update.onUpdate(0, timelineType, slug); } if (direction == DIRECTION.TOP && fetchingMissing) { - binding.recyclerView.scrollToPosition(getPosition(fetched_statuses.statuses.get(fetched_statuses.statuses.size() - 1)) + 1); + int newPosition = currentPosition + fetched_statuses.statuses.size() + 1; + if (newPosition < timelineStatuses.size()) { + binding.recyclerView.scrollToPosition(newPosition); + } } if (!fetchingMissing) { if (fetched_statuses.pagination.max_id == null) { From 299df2cd597c88b2f97c8b33d098612794e7a042 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 3 Jan 2023 18:12:15 +0100 Subject: [PATCH 34/68] 3.13.6 --- app/build.gradle | 4 ++-- app/src/main/assets/release_notes/notes.json | 5 +++++ .../app/fedilab/android/ui/drawer/ComposeAdapter.java | 10 ++++------ .../fastlane/metadata/android/en/changelogs/460.txt | 8 ++++++++ 4 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/460.txt diff --git a/app/build.gradle b/app/build.gradle index 47616d831..1ad481d40 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 33 - versionCode 459 - versionName "3.13.5" + versionCode 460 + versionName "3.13.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index f0b81c4b6..e8fc65450 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,9 @@ [ + { + "version": "3.13.6", + "code": "460", + "note": "Fixed:\n- Cross-compose: Wrong instance emojis\n- Custom emojis not displayed in notifications\n- Fav/Boost markers with shared messages\n- Empty notifications\n- Fix cw removed when replying\n- Fix expand media with fit preview images when sensitive\n- Fix an issue with fetch more displayed too often (cache clear will help or wait new messages)" + }, { "version": "3.13.5", "code": "459", diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index fbd59767d..b09f4b08c 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -68,7 +68,6 @@ import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; @@ -1023,19 +1022,18 @@ public class ComposeAdapter extends RecyclerView.Adapter Date: Tue, 3 Jan 2023 20:43:45 +0100 Subject: [PATCH 35/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 65.3% (676 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e9e0e54a4..cf2f2b773 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -581,4 +581,63 @@ Вам нужен дистрибьютор для получения push-уведомлений.\nВы найдете более подробную информацию по адресу %1$s.\n\nВы также можете отключить push-уведомления в настройках для игнорирования этого сообщения. Выберите дистрибьютора Размер значков + YouTube + Домен интерфейса YouTube + Использовать альтернативный интерфейс для YouTube + Twitter + Добавить фильтр + Сохранить изменения + Бот-аккаунт + Запланировано + Выберите тему + Упоминания + Обновления у людей + Вы уверены, что хотите удалить это поле\? + Также продвинуто: + Я модератор + Овал + Прямоугольник + Линия + Форма, фигура + Выйти без сохранения изображения\? + Нажмите здесь, чтобы обновить опрос + Получать уведомления каждые: + Экспорт настроек + Репосты + Взаимодействия + Удалить поле + Тип уведомлений + Импорт настроек + Выберите, должна ли основа темы быть темной или светлой + Избранные + Результаты опросов + Подписки + Отображать все категории + Профиль обновлён! + Недопустимое имя списка! + Для этого списка не найдено ни одного аккаунта! + Список изменений + Использовать системный язык по умолчанию + Мое приложение + Сообщение отправлено! + Добавить поле + Удалить все уведомления + Пометить все уведомления как прочитанные + Режим ластика + Настроить ленты + Всегда отображать кнопку закладки + Выберите тип уведомлений + Звук уведомлений + Отключить уведомления + В это время + "Также в избранном у: " + Мой аккаунт + Медиафайлы не могут быть загружены! + Подтвердить отписку + Тип опроса: + Длительность опроса: + Всегда отображать кнопку перевода + Удалить кеш + Вы уверены, что хотите удалить все уведомления\? Это не может быть отменено. + Загрузить экспортированные настройки \ No newline at end of file From 9dbf8ccdc06bb2e08203bcdf62bd3502d1ed55f3 Mon Sep 17 00:00:00 2001 From: Cilian Date: Tue, 3 Jan 2023 20:43:46 +0100 Subject: [PATCH 36/68] Translated using Weblate (Russian) Currently translated at 65.3% (676 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index cf2f2b773..71a02caec 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -640,4 +640,5 @@ Удалить кеш Вы уверены, что хотите удалить все уведомления\? Это не может быть отменено. Загрузить экспортированные настройки + Использовать альтернативный фронтенд для Twitter \ No newline at end of file From 10ce384282998f075b3a4f625e5f627c071c0d23 Mon Sep 17 00:00:00 2001 From: Cilian Date: Tue, 3 Jan 2023 20:44:30 +0100 Subject: [PATCH 37/68] Translated using Weblate (Russian) Currently translated at 65.4% (677 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 71a02caec..e66524da0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -641,4 +641,5 @@ Вы уверены, что хотите удалить все уведомления\? Это не может быть отменено. Загрузить экспортированные настройки Использовать альтернативный фронтенд для Twitter + Домен фронтенда Twitter \ No newline at end of file From 090fbce96ac4902eb18f6057c206450ba177ef17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= Date: Tue, 3 Jan 2023 20:44:30 +0100 Subject: [PATCH 38/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 65.4% (677 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e66524da0..b602e1bf7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -640,6 +640,6 @@ Удалить кеш Вы уверены, что хотите удалить все уведомления\? Это не может быть отменено. Загрузить экспортированные настройки - Использовать альтернативный фронтенд для Twitter + Использовать альтернативный интерфейс для Twitter Домен фронтенда Twitter \ No newline at end of file From f7205fbbbba4ffad9a8a032b940a38a4381a21f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= Date: Tue, 3 Jan 2023 20:45:03 +0100 Subject: [PATCH 39/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 65.6% (679 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b602e1bf7..f26708a09 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -641,5 +641,6 @@ Вы уверены, что хотите удалить все уведомления\? Это не может быть отменено. Загрузить экспортированные настройки Использовать альтернативный интерфейс для Twitter - Домен фронтенда Twitter + Домен интерфейса Twitter + Instagram \ No newline at end of file From d6a5d2a1c7c2acfa62b59626a54c80787e19513d Mon Sep 17 00:00:00 2001 From: Cilian Date: Tue, 3 Jan 2023 20:45:04 +0100 Subject: [PATCH 40/68] Translated using Weblate (Russian) Currently translated at 65.6% (679 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index f26708a09..c8ea867a9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -643,4 +643,5 @@ Использовать альтернативный интерфейс для Twitter Домен интерфейса Twitter Instagram + Использовать альтернативный фронтенд для Instagram \ No newline at end of file From f3391b1ac609a7170f8a6cbc9505411d5bd4e7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= Date: Tue, 3 Jan 2023 20:45:25 +0100 Subject: [PATCH 41/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 65.7% (680 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c8ea867a9..53bdbe30f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -643,5 +643,5 @@ Использовать альтернативный интерфейс для Twitter Домен интерфейса Twitter Instagram - Использовать альтернативный фронтенд для Instagram + Использовать альтернативный интерфейс для Instagram \ No newline at end of file From db8d57b18d3d879c1b3823d8e4443633651a77f6 Mon Sep 17 00:00:00 2001 From: Cilian Date: Tue, 3 Jan 2023 20:45:25 +0100 Subject: [PATCH 42/68] Translated using Weblate (Russian) Currently translated at 65.7% (680 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 53bdbe30f..b3f210127 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -644,4 +644,5 @@ Домен интерфейса Twitter Instagram Использовать альтернативный интерфейс для Instagram + Домен фронтеда Instagram \ No newline at end of file From f6eedc3eb58f98635dc2314b46172f255f5d59db Mon Sep 17 00:00:00 2001 From: Cilian Date: Tue, 3 Jan 2023 20:45:55 +0100 Subject: [PATCH 43/68] Translated using Weblate (Russian) Currently translated at 65.9% (682 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b3f210127..d8a17113f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -645,4 +645,5 @@ Instagram Использовать альтернативный интерфейс для Instagram Домен фронтеда Instagram + Использовать альтернативный фронтенд для Reddit \ No newline at end of file From e726b6a540f18913dce571ec23d54f86ce335baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= Date: Tue, 3 Jan 2023 20:45:55 +0100 Subject: [PATCH 44/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 65.9% (682 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d8a17113f..4fdd75000 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -644,6 +644,7 @@ Домен интерфейса Twitter Instagram Использовать альтернативный интерфейс для Instagram - Домен фронтеда Instagram + Домен интерфейса Instagram Использовать альтернативный фронтенд для Reddit + Reddit \ No newline at end of file From b45a007797a7fbc043c8f73fd0553eece05be9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= Date: Tue, 3 Jan 2023 20:46:20 +0100 Subject: [PATCH 45/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 66.0% (683 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 4fdd75000..aa713f2e0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -645,6 +645,6 @@ Instagram Использовать альтернативный интерфейс для Instagram Домен интерфейса Instagram - Использовать альтернативный фронтенд для Reddit + Использовать альтернативный интерфейс для Reddit Reddit \ No newline at end of file From 4e9af2abb27712475221fc9d4e27e838875b30e1 Mon Sep 17 00:00:00 2001 From: Cilian Date: Tue, 3 Jan 2023 20:46:20 +0100 Subject: [PATCH 46/68] Translated using Weblate (Russian) Currently translated at 66.0% (683 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index aa713f2e0..a4109762c 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -647,4 +647,5 @@ Домен интерфейса Instagram Использовать альтернативный интерфейс для Reddit Reddit + Домен фронтенда Reddit \ No newline at end of file From 785257cc6cbc5b0ed10d505efb09f852fb2da3dd Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 4 Jan 2023 11:12:17 +0100 Subject: [PATCH 47/68] Fix potential crashes --- .../main/java/app/fedilab/android/helper/SpannableHelper.java | 3 +++ .../app/fedilab/android/ui/drawer/NotificationAdapter.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 2ddf9a6fa..b75b5d3ce 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -143,6 +143,9 @@ public class SpannableHelper { int start = content.getSpanStart(span); int end = content.getSpanEnd(span); + if (start < 0 || end > content.length()) { + continue; + } content.removeSpan(span); //Get the matching word associated to the URL String word = content.subSequence(start, end).toString(); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java index 932d6e089..3ecbc6517 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java @@ -313,7 +313,7 @@ public class NotificationAdapter extends RecyclerView.Adapter Date: Wed, 4 Jan 2023 11:53:51 +0100 Subject: [PATCH 48/68] Add tags in any when pinned / Fix quotes with tags breaking lines --- .../java/app/fedilab/android/activities/HashTagActivity.java | 2 ++ .../main/java/app/fedilab/android/helper/SpannableHelper.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java index 7bf49af50..af6b0c533 100644 --- a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java @@ -221,6 +221,8 @@ public class HashTagActivity extends BaseActivity { tagTimeline.name = stripTag.trim(); tagTimeline.isNSFW = false; tagTimeline.isART = false; + tagTimeline.any = new ArrayList<>(); + tagTimeline.any.add(stripTag.trim()); pinnedTimeline.tagTimeline = tagTimeline; pinned.pinnedTimelines.add(pinnedTimeline); if (update) { diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index b75b5d3ce..dad5c73bf 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -124,7 +124,7 @@ public class SpannableHelper { if (status != null && status.mentions != null) { mentions.addAll(status.mentions); } - text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)>(((?!([<])).)*))", "$2

$3
"); + text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)>(((?!(<\\s?br\\s?/?>|<\\s?/s?p\\s?>)).)*))", "$2
$3
"); text = text.trim().replaceAll("\\s{3}", "   "); text = text.trim().replaceAll("\\s{2}", "  "); SpannableString initialContent; From 229262d478502574a6900884bfcd434ffc86af27 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 4 Jan 2023 14:34:22 +0100 Subject: [PATCH 49/68] clean --- .../main/java/app/fedilab/android/helper/SpannableHelper.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index dad5c73bf..6ac84cac9 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -139,8 +139,6 @@ public class SpannableHelper { //Loop through links for (URLSpan span : urls) { String url = span.getURL(); - - int start = content.getSpanStart(span); int end = content.getSpanEnd(span); if (start < 0 || end > content.length()) { From ca85e500a5ed22126b5022b56009536e23c5956e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Wed, 4 Jan 2023 22:51:05 +0100 Subject: [PATCH 50/68] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 99.6% (1030 of 1034 strings) Co-authored-by: Lukáš Jelínek Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/ Translation: Fedilab/Strings --- app/src/main/res/values-cs/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 824cc58af..54e26a9c2 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -967,4 +967,8 @@ Vzdálené profily Zobrazit tlačítko „Jen místní“ Jen místní + Stav e-mailu + Stav přihlášení + Připojil(a) se + Ztišen(a) \ No newline at end of file From 31bdafe5fd1c41f65522de0ef2c5cea50ad05658 Mon Sep 17 00:00:00 2001 From: claleb Date: Wed, 4 Jan 2023 22:51:05 +0100 Subject: [PATCH 51/68] Translated using Weblate (German) Currently translated at 100.0% (1034 of 1034 strings) Co-authored-by: claleb Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/ Translation: Fedilab/Strings --- app/src/main/res/values-de/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a489bd956..bf2c0d0f7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -358,12 +358,12 @@ Bot Pixelfed-Instanz Mastodon-Instanz - Irgendwelche davon + Eines davon Alle davon Keine davon - Eines dieser Wörter (durch Leerzeichen getrennt) - Alle diese Wörter (durch Leerzeichen getrennt) - Wörter zum Filter hinzufügen (durch Leerzeichen getrennt) + Einer dieser Hashtags (durch Leerzeichen getrennt) + Alle dieser Hashtags (durch Leerzeichen getrennt) + Hashtags zum Filter hinzufügen (durch Leerzeichen getrennt) Spaltenname ändern Misskey Instanz Angesagt From 1c650b56f1323030acc03a4cc95513e1321017d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= Date: Wed, 4 Jan 2023 22:51:05 +0100 Subject: [PATCH 52/68] Translated using Weblate (Russian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 72.8% (753 of 1034 strings) Co-authored-by: Виталий Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 63 ++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a4109762c..5210c68d2 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -513,7 +513,7 @@ Вы хотите отписаться от этого аккаунта? Предупреждать перед отменой подписки Replace Medium links - Replace medium.com links with an open source alternative front-end focused on privacy. + Использовать альтернативный интерфейс для Medium Default: scribe.rip Использовать систему push-уведомлений для получения уведомлений в режиме реального времени. Добавить примечания @@ -598,7 +598,7 @@ Овал Прямоугольник Линия - Форма, фигура + Фигура Выйти без сохранения изображения\? Нажмите здесь, чтобы обновить опрос Получать уведомления каждые: @@ -647,5 +647,62 @@ Домен интерфейса Instagram Использовать альтернативный интерфейс для Reddit Reddit - Домен фронтенда Reddit + Домен интерфейса Reddit + Перезапустить + Это нарушает правила сервера + Вы знаете, что это нарушает определенные правила + Изменить логотип + Пользователь + Модератор + Мне это не нравится + Количество аккаунтов на загрузку + Загружать предпросмотр + Подтверждено + Не подтверждено + Недопустимое имя тега! + Переводчик + Версия переводчика + Администратор + Содержимое лент будет временно сохраняться у вас, чтобы ускорить работу приложения. + Отображать медиа + Видимость иконок + Переводчик + API-ключ переводчика + Количество уведомлений на загрузку + Скажите нам, что не так с этим постом\? + Выберите наиболее подходящее + Отписаться от тега + Вы уверены, что хотите отписаться от этого тега\? + Подписаться на тег + Вы не подписаны ни на один тег! + Отписаться + Отслеживаемые теги + Подписаться на тег + Другое + Показать содержимое > + Присоединяйтесь к fediverse + Привет! Приглашаем Вас присоединиться к Fediverse. + Проблема не подпадает под другие категории + У вас нет аккаунта\? + Мой инстанс + Профили + Отображать медиа в уведомлениях + Запоминать позицию на ленте + Будут отображаться медиа в уведомлениях для репостов и избранного + Версия + Скрыть содержимое < + Пожаловаться на %1$s + Это НЕ то что вы бы хотели видеть + Использовать кэш + Это спам + Вредоносные ссылки, повторяющиеся ответы + «Mastodon — это не один веб-сайт, такой как Twitter или Facebook, это сеть из тысяч сообществ, управляемых различными организациями и частными лицами, которые обеспечивают бесперебойную работу в социальных сетях». + Измените логотип приложения на вашем устройстве + Перезапустить приложение\? + Вы должны перезапустить приложение, чтобы применить изменения. + Напишите тег для подписки + Похоже, ваш инстанс не поддерживает эту функцию! + Дополнительные функции + Включив эту опцию, приложение будет отображать дополнительные функции. Это предназначается для социальных платформ, таких как Pleroma, Akkoma или Glitch Social + Вы можете смело спрятать эти значки внизу, чтобы было больше места. Они также находятся в подменю. \ No newline at end of file From 97e3d7ed19c95d4731d85958274c3dfbee4803de Mon Sep 17 00:00:00 2001 From: Cilian Date: Wed, 4 Jan 2023 22:51:06 +0100 Subject: [PATCH 53/68] Translated using Weblate (Russian) Currently translated at 72.8% (753 of 1034 strings) Co-authored-by: Cilian Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translation: Fedilab/Strings --- app/src/main/res/values-ru/strings.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5210c68d2..b6debd1a0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -705,4 +705,15 @@ Дополнительные функции Включив эту опцию, приложение будет отображать дополнительные функции. Это предназначается для социальных платформ, таких как Pleroma, Akkoma или Glitch Social Вы можете смело спрятать эти значки внизу, чтобы было больше места. Они также находятся в подменю. + Это поле не может быть пустым! + Добавлен в избранное + Только для подписчиков + Музыка + Продолжить + Пользовательский + Другое + Настройки успешно экспортированы + Настройки успешно импортированы + Настройки экспортированы + Продвинут \ No newline at end of file From 9e701f82ba54c7e59618dd5a4ad915c3970095b1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Jan 2023 15:15:39 +0100 Subject: [PATCH 54/68] release notes --- src/fdroid/fastlane/metadata/android/en/changelogs/461.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/461.txt diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt new file mode 100644 index 000000000..58453dff2 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt @@ -0,0 +1,7 @@ + +Changed: +- Add pinned tag in "any" to avoid to lose it when renaming timeline + +Fixed: +- Fix quotes with tags/mentions +- Some crashes \ No newline at end of file From 8fe26abec7f098f1ebff10ecf4f2480637090400 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Jan 2023 18:53:49 +0100 Subject: [PATCH 55/68] release notes --- .../fedilab/android/helper/ECDHFedilab.java | 251 ++++++++++++++++++ .../android/helper/PushNotifications.java | 35 ++- .../android/services/CustomReceiver.java | 14 +- 3 files changed, 276 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java diff --git a/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java b/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java new file mode 100644 index 000000000..0dbe27fde --- /dev/null +++ b/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java @@ -0,0 +1,251 @@ +package app.fedilab.android.helper; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * 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. + * + * Fedilab 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 Fedilab; if not, + * see . */ + +import static app.fedilab.android.client.entities.app.StatusCache.restoreNotificationFromString; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Base64; +import android.util.Log; + +import androidx.preference.PreferenceManager; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyAgreement; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import app.fedilab.android.client.entities.api.Notification; + + +public class ECDHFedilab { + + + public static final String kp_public = "kp_public"; + public static final String peer_public = "peer_public"; + + public static final String name = "prime256v1"; + private static final byte[] P256_HEAD = new byte[]{(byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00}; + + static { + Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider()); + } + + private final KeyPairGenerator kpg; + private final PublicKey publicKey; + private final String encodedPublicKey; + private final byte[] authKey; + private final String slug; + private final String pushPublicKey; + private final String encodedAuthKey; + private final String pushAccountID; + private final String pushPrivateKey; + PrivateKey privateKey; + private String pushPrivateKe; + + public ECDHFedilab(Context context, String slug) throws Exception { + if (slug == null) { + throw new Exception("slug cannot be null"); + } + try { + kpg = KeyPairGenerator.getInstance("EC"); + ECGenParameterSpec spec = new ECGenParameterSpec("prime256v1"); + kpg.initialize(spec); + KeyPair keyPair = kpg.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + encodedPublicKey = Base64.encodeToString(serializeRawPublicKey(publicKey), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + authKey = new byte[16]; + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(authKey); + byte[] randomAccountID = new byte[16]; + secureRandom.nextBytes(randomAccountID); + pushPrivateKey = Base64.encodeToString(privateKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + pushPublicKey = Base64.encodeToString(publicKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + encodedAuthKey = Base64.encodeToString(authKey, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + pushAccountID = Base64.encodeToString(randomAccountID, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + SharedPreferences.Editor prefsEditor = PreferenceManager + .getDefaultSharedPreferences(context).edit(); + prefsEditor.putString("pushPrivateKey" + slug, pushPrivateKey); + prefsEditor.putString("pushPublicKey" + slug, pushPublicKey); + prefsEditor.putString("encodedAuthKey" + slug, encodedAuthKey); + prefsEditor.putString("pushAccountID" + slug, pushAccountID); + prefsEditor.apply(); + this.slug = slug; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static String getServerKey(Context context, String slug) { + SharedPreferences sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(context); + return sharedPreferences.getString("server_key" + slug, null); + } + + private static byte[] serializeRawPublicKey(PublicKey key) { + ECPoint point = ((ECPublicKey) key).getW(); + byte[] x = point.getAffineX().toByteArray(); + byte[] y = point.getAffineY().toByteArray(); + if (x.length > 32) + x = Arrays.copyOfRange(x, x.length - 32, x.length); + if (y.length > 32) + y = Arrays.copyOfRange(y, y.length - 32, y.length); + byte[] result = new byte[65]; + result[0] = 4; + System.arraycopy(x, 0, result, 1 + (32 - x.length), x.length); + System.arraycopy(y, 0, result, result.length - y.length, y.length); + return result; + } + + public static Notification decryptNotification(Context context, String slug, byte[] messageEncrypted) { + + + SharedPreferences sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(context); + Log.v(Helper.TAG, ">>slug: " + slug); + String pushPrivateKey = sharedPreferences.getString("pushPrivateKey" + slug, null); + String pushPublicKey = sharedPreferences.getString("pushPublicKey" + slug, null); + String encodedAuthKey = sharedPreferences.getString("encodedAuthKey" + slug, null); + sharedPreferences.getString("pushAccountID" + slug, null); + + + Log.v(Helper.TAG, "getServerKey(context, slug): " + getServerKey(context, slug)); + + + Log.v(Helper.TAG, "pushPrivateKey: " + pushPrivateKey); + Log.v(Helper.TAG, "pushPublicKey: " + pushPublicKey); + Log.v(Helper.TAG, "encodedAuthKey: " + encodedAuthKey); + + PublicKey serverKey = null; + serverKey = deserializeRawPublicKey(Base64.decode(getServerKey(context, slug), Base64.URL_SAFE)); + Log.v(Helper.TAG, "serverKey: " + serverKey); + PrivateKey privateKey; + PublicKey publicKey; + byte[] authKey; + try { + KeyFactory kf = KeyFactory.getInstance("EC"); + privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decode(pushPrivateKey, Base64.URL_SAFE))); + publicKey = kf.generatePublic(new X509EncodedKeySpec(Base64.decode(pushPublicKey, Base64.URL_SAFE))); + authKey = Base64.decode(encodedAuthKey, Base64.URL_SAFE); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + e.printStackTrace(); + Log.v(Helper.TAG, "err1: " + e.getMessage()); + return null; + } + byte[] sharedSecret; + try { + KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH"); + keyAgreement.init(privateKey); + keyAgreement.doPhase(serverKey, true); + sharedSecret = keyAgreement.generateSecret(); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + e.printStackTrace(); + Log.v(Helper.TAG, "err2: " + e.getMessage()); + return null; + } + byte[] secondSaltInfo = "Content-Encoding: auth\0".getBytes(StandardCharsets.UTF_8); + byte[] deriveKey; + try { + deriveKey = deriveKey(authKey, sharedSecret, secondSaltInfo, 32); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + e.printStackTrace(); + Log.v(Helper.TAG, "err3: " + e.getMessage()); + return null; + } + String decryptedStr; + try { + + SecretKeySpec aesKey = new SecretKeySpec(deriveKey, "AES"); + byte[] iv = Arrays.copyOfRange(messageEncrypted, 0, 12); + byte[] ciphertext = Arrays.copyOfRange(messageEncrypted, 12, messageEncrypted.length); // Separate ciphertext (the MAC is implicitly separated from the ciphertext) + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec gCMParameterSpec = new GCMParameterSpec(128, iv); + cipher.init(Cipher.DECRYPT_MODE, aesKey, gCMParameterSpec); + byte[] decrypted = cipher.doFinal(ciphertext); + decryptedStr = new String(decrypted, 2, decrypted.length - 2, StandardCharsets.UTF_8); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + Log.v(Helper.TAG, "err4: " + e.getMessage()); + return null; + } + return restoreNotificationFromString(decryptedStr); + } + + protected static PublicKey deserializeRawPublicKey(byte[] rawBytes) { + if (rawBytes.length != 65 && rawBytes.length != 64) + return null; + try { + KeyFactory kf = KeyFactory.getInstance("EC"); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + os.write(P256_HEAD); + if (rawBytes.length == 64) + os.write(4); + os.write(rawBytes); + return kf.generatePublic(new X509EncodedKeySpec(os.toByteArray())); + } catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) { + e.printStackTrace(); + } + return null; + } + + private static byte[] deriveKey(byte[] firstSalt, byte[] secondSalt, byte[] info, int length) throws NoSuchAlgorithmException, InvalidKeyException { + Mac hmacContext = Mac.getInstance("HmacSHA256"); + hmacContext.init(new SecretKeySpec(firstSalt, "HmacSHA256")); + byte[] hmac = hmacContext.doFinal(secondSalt); + hmacContext.init(new SecretKeySpec(hmac, "HmacSHA256")); + hmacContext.update(info); + byte[] result = hmacContext.doFinal(new byte[]{1}); + return result.length <= length ? result : Arrays.copyOfRange(result, 0, length); + } + + public String getPublicKey() { + return this.encodedPublicKey; + } + + public String getAuthKey() { + return this.encodedAuthKey; + } + +} diff --git a/app/src/main/java/app/fedilab/android/helper/PushNotifications.java b/app/src/main/java/app/fedilab/android/helper/PushNotifications.java index 0b1d561c4..670909de9 100644 --- a/app/src/main/java/app/fedilab/android/helper/PushNotifications.java +++ b/app/src/main/java/app/fedilab/android/helper/PushNotifications.java @@ -15,21 +15,17 @@ package app.fedilab.android.helper; * see . */ -import static app.fedilab.android.helper.ECDH.kp_private; -import static app.fedilab.android.helper.ECDH.kp_public; - import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; +import android.util.Log; import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; -import java.util.Random; import java.util.concurrent.TimeUnit; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.client.endpoints.MastodonNotificationsService; import app.fedilab.android.client.entities.api.PushSubscription; @@ -50,24 +46,18 @@ public class PushNotifications { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context); - String strPub = prefs.getString(kp_public + slug, ""); - String strPriv = prefs.getString(kp_private + slug, ""); - ECDH ecdh = null; + ECDHFedilab ecdh = null; try { - ecdh = ECDH.getInstance(slug); + ecdh = new ECDHFedilab(context, slug); } catch (Exception e) { e.printStackTrace(); } if (ecdh == null) { return; } - if (strPub.trim().isEmpty() || strPriv.trim().isEmpty()) { - ecdh.newPair(context); - } - String pubKey = ecdh.getPublicKey(context); - byte[] randBytes = new byte[16]; - new Random().nextBytes(randBytes); - String auth = ECDH.base64Encode(randBytes); + + String pubKey = ecdh.getPublicKey(); + String auth = ecdh.getAuthKey(); boolean notif_follow = prefs.getBoolean(context.getString(R.string.SET_NOTIF_FOLLOW), true); @@ -75,8 +65,6 @@ public class PushNotifications { boolean notif_share = prefs.getBoolean(context.getString(R.string.SET_NOTIF_SHARE), true); boolean notif_poll = prefs.getBoolean(context.getString(R.string.SET_NOTIF_POLL), true); boolean notif_fav = prefs.getBoolean(context.getString(R.string.SET_NOTIF_FAVOURITE), true); - MastodonNotificationsService mastodonNotificationsService = init(context, BaseMainActivity.currentInstance); - ECDH finalEcdh = ecdh; new Thread(() -> { String[] slugArray = slug.split("@"); BaseAccount accountDb = null; @@ -85,9 +73,11 @@ public class PushNotifications { } catch (DBException e) { e.printStackTrace(); } + if (accountDb == null) { return; } + MastodonNotificationsService mastodonNotificationsService = init(context, accountDb.instance); PushSubscription pushSubscription; Call pushSubscriptionCall = mastodonNotificationsService.pushSubscription( accountDb.token, @@ -105,10 +95,16 @@ public class PushNotifications { if (pushSubscriptionResponse.isSuccessful()) { pushSubscription = pushSubscriptionResponse.body(); if (pushSubscription != null) { - finalEcdh.saveServerKey(context, pushSubscription.server_key); + pushSubscription.server_key = pushSubscription.server_key.replace('/', '_'); + pushSubscription.server_key = pushSubscription.server_key.replace('+', '-'); + SharedPreferences.Editor prefsEditor = PreferenceManager + .getDefaultSharedPreferences(context).edit(); + prefsEditor.putString("server_key" + slug, pushSubscription.server_key); + prefsEditor.apply(); } } } catch (Exception e) { + Log.v(Helper.TAG, slug + " -> " + e.getMessage()); e.printStackTrace(); } } @@ -122,6 +118,7 @@ public class PushNotifications { } + public static String getToken(Context context, String slug) { return context.getSharedPreferences("unifiedpush.connector", Context.MODE_PRIVATE).getString( slug + "/unifiedpush.connector", null); diff --git a/app/src/main/java/app/fedilab/android/services/CustomReceiver.java b/app/src/main/java/app/fedilab/android/services/CustomReceiver.java index f87ded11c..3e13ff73a 100644 --- a/app/src/main/java/app/fedilab/android/services/CustomReceiver.java +++ b/app/src/main/java/app/fedilab/android/services/CustomReceiver.java @@ -16,6 +16,7 @@ package app.fedilab.android.services; import android.content.Context; import android.content.Intent; +import android.util.Log; import androidx.annotation.NonNull; @@ -23,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.unifiedpush.android.connector.MessagingReceiver; +import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.NotificationsHelper; import app.fedilab.android.helper.PushNotifications; @@ -38,13 +40,15 @@ public class CustomReceiver extends MessagingReceiver { @Override public void onMessage(@NotNull Context context, @NotNull byte[] message, @NotNull String slug) { // Called when a new message is received. The message contains the full POST body of the push message + Log.v(Helper.TAG, "onMessage: " + slug); new Thread(() -> { try { - /* ECDH ecdh = ECDH.getInstance(slug); - if (ecdh == null) { - return; - }*/ - //String decrypted = ecdh.uncryptMessage(context, String.valueOf(message)); + /*Notification notification = ECDHFedilab.decryptNotification(context, slug, message); + Log.v(Helper.TAG,"notification: " + notification); + if(notification != null) { + Log.v(Helper.TAG,"id: " + notification.id); + } + */ NotificationsHelper.task(context, slug); } catch (Exception e) { e.printStackTrace(); From 1e807725e1d4277530ae5bbd3d56748cac987cbf Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Jan 2023 19:01:27 +0100 Subject: [PATCH 56/68] release notes --- src/fdroid/fastlane/metadata/android/en/changelogs/461.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt index 58453dff2..572d0c776 100644 --- a/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt @@ -4,4 +4,5 @@ Changed: Fixed: - Fix quotes with tags/mentions +- Fix notifications - Some crashes \ No newline at end of file From 56b82461b5ef07bf159a3f29d649ad01c3f141be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?jos=C3=A9=20m?= Date: Fri, 6 Jan 2023 06:51:02 +0100 Subject: [PATCH 57/68] Translated using Weblate (Galician) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (1034 of 1034 strings) Co-authored-by: josé m Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/ Translation: Fedilab/Strings --- app/src/main/res/values-gl/strings.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 1cc6350d9..f472dd914 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -933,4 +933,29 @@ Xestionar contas Eliminar marxe esquerda Eliminar a marxe esquerda nas cronoloxías para compactar máis as mensaxes + Tradutor + Mostrar botón \"Só local\" + Chave da API do tradutor + Versión + Ao activar esta opción a app mostrará características extra. Temos esta función para software social tipo Pleroma, Akkoma ou Glitch Social + Formato da publicación + Iconas para Extras + Se a túa instancia non acepta características extra, podes agochar estas iconas + Mostrar botón \"Cita\" + Mostrar botóns de \"Reaccións\" + Propio + Seguindo + Perfís remotos + Só local + Burbulla + Lista + Visibilidade da resposta + Visibilidade da exclusión + Tradutor + Características extra + Visibilidade das iconas + Formato da publicación + Versión do tradutor + Podes agochar tranquilamente estas iconas ao pé para ter máis espazo. Están tamén no submenú. + A app mostrará públicamente os perfís para obter tódalas mensaxes. As interaccións precisarán un paso extra para federar as mensaxes. \ No newline at end of file From caa14ecaa913f294532cfe1dfe23f1f1951ee1a4 Mon Sep 17 00:00:00 2001 From: Ajeje Brazorf Date: Fri, 6 Jan 2023 06:51:02 +0100 Subject: [PATCH 58/68] Translated using Weblate (Sardinian) Currently translated at 98.5% (1019 of 1034 strings) Co-authored-by: Ajeje Brazorf Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/ Translation: Fedilab/Strings --- app/src/main/res/values-sc/strings.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 3a4733e8e..dc9289c41 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -929,4 +929,25 @@ Importa datos Agrupa is cumpartziduras in sa lìnia de tempus printzipale Amministra is contos + Funtzionalidades extra + Formadu de publicatzione + Iconas pro funtzionalidades extra + Visibilidade de is iconas + Formadu de publicatzione + Ammustra su butone \"Tzita\" + Ammustra su butone \"Reatziones\" + Profilos remotos + Bullunca + Lista + Sighende + Boga su màrgine a manca + Boga su màrgine a manca de is lìnias de tempus pro chi is messàgios siant prus cumpatos + Tradutore + Tradutore + Crae API de su tradutore + Versione + Versione de su tradutore + Ativende cussa optzione s\'aplicatzione at a ammustrare funtzionalidades extra. Custa funtzionalidade b\'est pro programmas sotziales che a Pleroma, Akkoma o Glitch Social + Podes cuare custas iconas in manera segura in fundu pro tènnere prus logu. Sunt fintzas in su suta-menù. + Si s\'istàntzia tua no atzetat unas cantas funtzionalidades extra podes cuare custas iconas \ No newline at end of file From 17d6152af31d3603def7bcf076cee0ecddb742a4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 6 Jan 2023 09:52:46 +0100 Subject: [PATCH 59/68] Some fixes --- app/src/main/java/app/fedilab/android/BaseMainActivity.java | 1 - src/fdroid/fastlane/metadata/android/en/changelogs/461.txt | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index dff1f87b1..43b4ddb3b 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -1139,7 +1139,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt b.putSerializable(Helper.ARG_MEDIA_ATTACHMENTS, new ArrayList<>(attachments)); CrossActionHelper.doCrossShare(BaseMainActivity.this, b); }); - CrossActionHelper.doCrossShare(BaseMainActivity.this, b); } else { Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); } diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt index 572d0c776..fc06af601 100644 --- a/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/461.txt @@ -3,6 +3,8 @@ Changed: - Add pinned tag in "any" to avoid to lose it when renaming timeline Fixed: +- Fix push notifications with several accounts - Fix quotes with tags/mentions - Fix notifications +- Fix sending multiple media - Some crashes \ No newline at end of file From 7e1d9b8910a0023dea2d28f7c1340da3167b409b Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 6 Jan 2023 15:57:05 +0100 Subject: [PATCH 60/68] Fix issue #730 --- .../main/java/app/fedilab/android/jobs/ComposeWorker.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java index 6637c03cc..f66b8ca3b 100644 --- a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java +++ b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java @@ -270,7 +270,11 @@ public class ComposeWorker extends Worker { b.putBoolean(Helper.RECEIVE_COMPOSE_ERROR_MESSAGE, true); Intent intentBD = new Intent(Helper.INTENT_COMPOSE_ERROR_MESSAGE); b.putSerializable(Helper.ARG_STATUS_DRAFT, dataPost.statusDraft); - b.putSerializable(Helper.RECEIVE_ERROR_MESSAGE, statusResponse.errorBody().string()); + String err = statusResponse.errorBody().string(); + if (err.contains("{\"error\":\"")) { + err = err.replaceAll("\\{\"error\":\"(.*)\"}", "$1"); + } + b.putSerializable(Helper.RECEIVE_ERROR_MESSAGE, err); intentBD.putExtras(b); LocalBroadcastManager.getInstance(context).sendBroadcast(intentBD); return; From c052e376e22088f02a28b725c6f18bbf3bf40652 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 6 Jan 2023 16:27:26 +0100 Subject: [PATCH 61/68] Fix reactions displayed in all notif tabs --- .../app/fedilab/android/helper/ECDHFedilab.java | 14 -------------- .../fedilab/android/helper/PushNotifications.java | 2 -- .../fedilab/android/services/CustomReceiver.java | 3 --- .../android/ui/drawer/NotificationAdapter.java | 6 +++++- .../timeline/FragmentMastodonNotification.java | 1 + 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java b/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java index 0dbe27fde..de56a1921 100644 --- a/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java +++ b/app/src/main/java/app/fedilab/android/helper/ECDHFedilab.java @@ -19,7 +19,6 @@ import static app.fedilab.android.client.entities.app.StatusCache.restoreNotific import android.content.Context; import android.content.SharedPreferences; import android.util.Base64; -import android.util.Log; import androidx.preference.PreferenceManager; @@ -144,23 +143,14 @@ public class ECDHFedilab { SharedPreferences sharedPreferences = PreferenceManager .getDefaultSharedPreferences(context); - Log.v(Helper.TAG, ">>slug: " + slug); String pushPrivateKey = sharedPreferences.getString("pushPrivateKey" + slug, null); String pushPublicKey = sharedPreferences.getString("pushPublicKey" + slug, null); String encodedAuthKey = sharedPreferences.getString("encodedAuthKey" + slug, null); sharedPreferences.getString("pushAccountID" + slug, null); - Log.v(Helper.TAG, "getServerKey(context, slug): " + getServerKey(context, slug)); - - - Log.v(Helper.TAG, "pushPrivateKey: " + pushPrivateKey); - Log.v(Helper.TAG, "pushPublicKey: " + pushPublicKey); - Log.v(Helper.TAG, "encodedAuthKey: " + encodedAuthKey); - PublicKey serverKey = null; serverKey = deserializeRawPublicKey(Base64.decode(getServerKey(context, slug), Base64.URL_SAFE)); - Log.v(Helper.TAG, "serverKey: " + serverKey); PrivateKey privateKey; PublicKey publicKey; byte[] authKey; @@ -171,7 +161,6 @@ public class ECDHFedilab { authKey = Base64.decode(encodedAuthKey, Base64.URL_SAFE); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { e.printStackTrace(); - Log.v(Helper.TAG, "err1: " + e.getMessage()); return null; } byte[] sharedSecret; @@ -182,7 +171,6 @@ public class ECDHFedilab { sharedSecret = keyAgreement.generateSecret(); } catch (NoSuchAlgorithmException | InvalidKeyException e) { e.printStackTrace(); - Log.v(Helper.TAG, "err2: " + e.getMessage()); return null; } byte[] secondSaltInfo = "Content-Encoding: auth\0".getBytes(StandardCharsets.UTF_8); @@ -191,7 +179,6 @@ public class ECDHFedilab { deriveKey = deriveKey(authKey, sharedSecret, secondSaltInfo, 32); } catch (NoSuchAlgorithmException | InvalidKeyException e) { e.printStackTrace(); - Log.v(Helper.TAG, "err3: " + e.getMessage()); return null; } String decryptedStr; @@ -207,7 +194,6 @@ public class ECDHFedilab { decryptedStr = new String(decrypted, 2, decrypted.length - 2, StandardCharsets.UTF_8); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { e.printStackTrace(); - Log.v(Helper.TAG, "err4: " + e.getMessage()); return null; } return restoreNotificationFromString(decryptedStr); diff --git a/app/src/main/java/app/fedilab/android/helper/PushNotifications.java b/app/src/main/java/app/fedilab/android/helper/PushNotifications.java index 670909de9..a2be75ea9 100644 --- a/app/src/main/java/app/fedilab/android/helper/PushNotifications.java +++ b/app/src/main/java/app/fedilab/android/helper/PushNotifications.java @@ -19,7 +19,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; -import android.util.Log; import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; @@ -104,7 +103,6 @@ public class PushNotifications { } } } catch (Exception e) { - Log.v(Helper.TAG, slug + " -> " + e.getMessage()); e.printStackTrace(); } } diff --git a/app/src/main/java/app/fedilab/android/services/CustomReceiver.java b/app/src/main/java/app/fedilab/android/services/CustomReceiver.java index 3e13ff73a..a6eb6f77a 100644 --- a/app/src/main/java/app/fedilab/android/services/CustomReceiver.java +++ b/app/src/main/java/app/fedilab/android/services/CustomReceiver.java @@ -16,7 +16,6 @@ package app.fedilab.android.services; import android.content.Context; import android.content.Intent; -import android.util.Log; import androidx.annotation.NonNull; @@ -24,7 +23,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.unifiedpush.android.connector.MessagingReceiver; -import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.NotificationsHelper; import app.fedilab.android.helper.PushNotifications; @@ -40,7 +38,6 @@ public class CustomReceiver extends MessagingReceiver { @Override public void onMessage(@NotNull Context context, @NotNull byte[] message, @NotNull String slug) { // Called when a new message is received. The message contains the full POST body of the push message - Log.v(Helper.TAG, "onMessage: " + slug); new Thread(() -> { try { /*Notification notification = ECDHFedilab.decryptNotification(context, slug, message); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java index 3ecbc6517..f3b2af690 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/NotificationAdapter.java @@ -186,7 +186,11 @@ public class NotificationAdapter extends RecyclerView.Adapter Date: Fri, 6 Jan 2023 18:21:41 +0100 Subject: [PATCH 62/68] Pixelfed view --- .../android/ui/drawer/SliderAdapter.java | 97 +++++++++++++++++++ .../android/ui/drawer/StatusAdapter.java | 60 +++++++++++- .../settings/FragmentTimelinesSettings.java | 12 +++ app/src/main/res/layout/drawer_slider.xml | 8 ++ .../res/layout/drawer_status_pixelfed.xml | 97 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/pref_timelines.xml | 7 +- autoimageslider/build.gradle | 10 +- 8 files changed, 286 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/ui/drawer/SliderAdapter.java create mode 100644 app/src/main/res/layout/drawer_slider.xml create mode 100644 app/src/main/res/layout/drawer_status_pixelfed.xml diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/SliderAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/SliderAdapter.java new file mode 100644 index 000000000..de0975c47 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/ui/drawer/SliderAdapter.java @@ -0,0 +1,97 @@ +package app.fedilab.android.ui.drawer; +/* Copyright 2023 Thomas Schneider + * + * This file is a part of Fedilab + * + * 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. + * + * Fedilab 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 Fedilab; if not, + * see . */ + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.core.app.ActivityOptionsCompat; + +import com.bumptech.glide.Glide; +import com.smarteist.autoimageslider.SliderViewAdapter; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.android.activities.MediaActivity; +import app.fedilab.android.client.entities.api.Attachment; +import app.fedilab.android.client.entities.api.Status; +import app.fedilab.android.databinding.DrawerSliderBinding; +import app.fedilab.android.helper.Helper; + +public class SliderAdapter extends SliderViewAdapter { + + private final Status status; + private final List mSliderItems; + private Context context; + + public SliderAdapter(Status status) { + this.status = status; + this.mSliderItems = status.media_attachments; + } + + + public void addItem(Attachment sliderItem) { + this.mSliderItems.add(sliderItem); + notifyDataSetChanged(); + } + + @Override + public SliderAdapterVH onCreateViewHolder(ViewGroup parent) { + context = parent.getContext(); + DrawerSliderBinding itemBinding = DrawerSliderBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new SliderAdapterVH(itemBinding); + } + + @Override + public void onBindViewHolder(SliderAdapterVH viewHolder, final int position) { + + Attachment sliderItem = mSliderItems.get(position); + + Glide.with(viewHolder.itemView) + .load(sliderItem.preview_url) + .centerCrop() + .into(viewHolder.binding.ivAutoImageSlider); + viewHolder.itemView.setOnClickListener(v -> { + Intent mediaIntent = new Intent(context, MediaActivity.class); + Bundle b = new Bundle(); + b.putInt(Helper.ARG_MEDIA_POSITION, position + 1); + b.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(status.media_attachments)); + mediaIntent.putExtras(b); + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation((Activity) context, viewHolder.binding.ivAutoImageSlider, status.media_attachments.get(0).url); + // start the new activity + context.startActivity(mediaIntent, options.toBundle()); + }); + } + + @Override + public int getCount() { + return mSliderItems.size(); + } + + static class SliderAdapterVH extends ViewHolder { + DrawerSliderBinding binding; + + SliderAdapterVH(DrawerSliderBinding itemView) { + super(itemView.getRoot()); + binding = itemView; + } + } +} diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index a7fc576c1..376951461 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -87,6 +87,8 @@ import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.request.RequestOptions; import com.github.stom79.mytransl.MyTransL; +import com.smarteist.autoimageslider.SliderAnimations; +import com.smarteist.autoimageslider.SliderView; import com.vanniktech.emoji.EmojiManager; import com.vanniktech.emoji.EmojiPopup; import com.vanniktech.emoji.one.EmojiOneProvider; @@ -128,6 +130,7 @@ import app.fedilab.android.databinding.DrawerStatusFilteredBinding; import app.fedilab.android.databinding.DrawerStatusFilteredHideBinding; import app.fedilab.android.databinding.DrawerStatusHiddenBinding; import app.fedilab.android.databinding.DrawerStatusNotificationBinding; +import app.fedilab.android.databinding.DrawerStatusPixelfedBinding; import app.fedilab.android.databinding.DrawerStatusReportBinding; import app.fedilab.android.databinding.LayoutMediaBinding; import app.fedilab.android.databinding.LayoutPollItemBinding; @@ -157,6 +160,7 @@ public class StatusAdapter extends RecyclerView.Adapter public static final int STATUS_ART = 2; public static final int STATUS_FILTERED = 3; public static final int STATUS_FILTERED_HIDE = 4; + public static final int STATUS_PIXELFED = 5; private final List statusList; private final boolean minified; private final Timeline.TimeLineEnum timelineType; @@ -164,6 +168,7 @@ public class StatusAdapter extends RecyclerView.Adapter private final boolean checkRemotely; public FetchMoreCallBack fetchMoreCallBack; private Context context; + private boolean visiblePixelfed; private RecyclerView mRecyclerView; @@ -188,6 +193,11 @@ public class StatusAdapter extends RecyclerView.Adapter return -1; } + + private static boolean isVisiblePixelfed(Status status) { + return status.media_attachments != null && status.media_attachments.size() > 0; + } + private static boolean isVisible(Timeline.TimeLineEnum timelineType, Status status) { if (timelineType == Timeline.TimeLineEnum.HOME && !show_boosts && status.reblog != null) { return false; @@ -2370,7 +2380,15 @@ public class StatusAdapter extends RecyclerView.Adapter } } } else { - return isVisible(timelineType, statusList.get(position)) ? STATUS_VISIBLE : STATUS_HIDDEN; + if (isVisible(timelineType, statusList.get(position))) { + if (visiblePixelfed && isVisiblePixelfed(statusList.get(position)) && timelineType != Timeline.TimeLineEnum.UNKNOWN) { + return STATUS_PIXELFED; + } else { + return STATUS_VISIBLE; + } + } else { + return STATUS_HIDDEN; + } } } @@ -2380,12 +2398,17 @@ public class StatusAdapter extends RecyclerView.Adapter @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { context = parent.getContext(); + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + visiblePixelfed = sharedpreferences.getBoolean(context.getString(R.string.SET_PIXELFED_PRESENTATION) + MainActivity.currentUserID + MainActivity.currentInstance, false); if (viewType == STATUS_HIDDEN) { //Hidden statuses - ie: filtered DrawerStatusHiddenBinding itemBinding = DrawerStatusHiddenBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusViewHolder(itemBinding); } else if (viewType == STATUS_ART) { //Art statuses DrawerStatusArtBinding itemBinding = DrawerStatusArtBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusViewHolder(itemBinding); + } else if (viewType == STATUS_PIXELFED) { //Art statuses + DrawerStatusPixelfedBinding itemBinding = DrawerStatusPixelfedBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new StatusViewHolder(itemBinding); } else if (viewType == STATUS_FILTERED) { //Filtered warn DrawerStatusFilteredBinding itemBinding = DrawerStatusFilteredBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new StatusViewHolder(itemBinding); @@ -2582,6 +2605,35 @@ public class StatusAdapter extends RecyclerView.Adapter intent.putExtra(Helper.ARG_STATUS, status); context.startActivity(intent); }); + } else if (viewHolder.getItemViewType() == STATUS_PIXELFED) { + StatusViewHolder holder = (StatusViewHolder) viewHolder; + MastodonHelper.loadPPMastodon(holder.bindingPixelfed.artPp, status.account); + SliderAdapter adapter = new SliderAdapter(status); + holder.bindingPixelfed.artMedia.setSliderAdapter(adapter); + holder.bindingPixelfed.artMedia.setSliderTransformAnimation(SliderAnimations.SIMPLETRANSFORMATION); + holder.bindingPixelfed.artMedia.setAutoCycleDirection(SliderView.AUTO_CYCLE_DIRECTION_BACK_AND_FORTH); + holder.bindingPixelfed.artMedia.setScrollTimeInSec(4); + holder.bindingPixelfed.artMedia.startAutoCycle(); + holder.bindingPixelfed.commentNumber.setText(String.valueOf(status.replies_count)); + holder.bindingPixelfed.artUsername.setText( + status.account.getSpanDisplayName(context, + new WeakReference<>(holder.bindingPixelfed.artUsername)), + TextView.BufferType.SPANNABLE); + holder.bindingPixelfed.artAcct.setText(String.format(Locale.getDefault(), "@%s", status.account.acct)); + holder.bindingPixelfed.artPp.setOnClickListener(v -> { + Intent intent = new Intent(context, ProfileActivity.class); + Bundle b = new Bundle(); + b.putSerializable(Helper.ARG_ACCOUNT, status.account); + intent.putExtras(b); + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation((Activity) context, holder.bindingPixelfed.artPp, context.getString(R.string.activity_porfile_pp)); + context.startActivity(intent, options.toBundle()); + }); + holder.bindingPixelfed.bottomBanner.setOnClickListener(v -> { + Intent intent = new Intent(context, ContextActivity.class); + intent.putExtra(Helper.ARG_STATUS, status); + context.startActivity(intent); + }); } } @@ -2607,6 +2659,7 @@ public class StatusAdapter extends RecyclerView.Adapter DrawerStatusReportBinding bindingReport; DrawerStatusNotificationBinding bindingNotification; DrawerStatusArtBinding bindingArt; + DrawerStatusPixelfedBinding bindingPixelfed; DrawerStatusFilteredBinding bindingFiltered; DrawerStatusFilteredHideBinding bindingFilteredHide; @@ -2638,6 +2691,11 @@ public class StatusAdapter extends RecyclerView.Adapter bindingArt = itemView; } + StatusViewHolder(DrawerStatusPixelfedBinding itemView) { + super(itemView.getRoot()); + bindingPixelfed = itemView; + } + StatusViewHolder(DrawerStatusFilteredBinding itemView) { super(itemView.getRoot()); bindingFiltered = itemView; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentTimelinesSettings.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentTimelinesSettings.java index 49867c7f4..05606bc6c 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentTimelinesSettings.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentTimelinesSettings.java @@ -73,6 +73,12 @@ public class FragmentTimelinesSettings extends PreferenceFragmentCompat implemen boolean checked = sharedpreferences.getBoolean(getString(R.string.SET_DISPLAY_TRANSLATE) + MainActivity.currentUserID + MainActivity.currentInstance, false); SET_DISPLAY_TRANSLATE.setChecked(checked); } + + SwitchPreferenceCompat SET_PIXELFED_PRESENTATION = findPreference(getString(R.string.SET_PIXELFED_PRESENTATION)); + if (SET_PIXELFED_PRESENTATION != null) { + boolean checked = sharedpreferences.getBoolean(getString(R.string.SET_PIXELFED_PRESENTATION) + MainActivity.currentUserID + MainActivity.currentInstance, false); + SET_PIXELFED_PRESENTATION.setChecked(checked); + } } @Override @@ -95,6 +101,12 @@ public class FragmentTimelinesSettings extends PreferenceFragmentCompat implemen editor.putBoolean(getString(R.string.SET_DISPLAY_TRANSLATE) + MainActivity.currentUserID + MainActivity.currentInstance, SET_DISPLAY_TRANSLATE.isChecked()); } } + if (key.compareToIgnoreCase(getString(R.string.SET_PIXELFED_PRESENTATION)) == 0) { + SwitchPreferenceCompat SET_PIXELFED_PRESENTATION = findPreference(getString(R.string.SET_PIXELFED_PRESENTATION)); + if (SET_PIXELFED_PRESENTATION != null) { + editor.putBoolean(getString(R.string.SET_PIXELFED_PRESENTATION) + MainActivity.currentUserID + MainActivity.currentInstance, SET_PIXELFED_PRESENTATION.isChecked()); + } + } editor.apply(); } } diff --git a/app/src/main/res/layout/drawer_slider.xml b/app/src/main/res/layout/drawer_slider.xml new file mode 100644 index 000000000..33f3f3302 --- /dev/null +++ b/app/src/main/res/layout/drawer_slider.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_status_pixelfed.xml b/app/src/main/res/layout/drawer_status_pixelfed.xml new file mode 100644 index 000000000..317c14b3f --- /dev/null +++ b/app/src/main/res/layout/drawer_status_pixelfed.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 84aaab18f..9068bf22c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1440,6 +1440,7 @@ SET_FILTER_REGEX_PUBLIC SET_NOTIF_VALIDATION SET_DISPLAY_BOOKMARK + SET_PIXELFED_PRESENTATION SET_DISPLAY_QUOTES SET_DISPLAY_REACTIONS @@ -2199,4 +2200,5 @@ The app will display publicly profiles to get all messages. Interactions will need an extra step to federate messages. Local only Display \"Local only\" button + Pixelfed presentation for media \ No newline at end of file diff --git a/app/src/main/res/xml/pref_timelines.xml b/app/src/main/res/xml/pref_timelines.xml index 34ea407f9..f78ff5adf 100644 --- a/app/src/main/res/xml/pref_timelines.xml +++ b/app/src/main/res/xml/pref_timelines.xml @@ -46,7 +46,12 @@ app:key="@string/SET_DISPLAY_BOOKMARK" app:singleLineTitle="false" app:title="@string/set_display_bookmark_indication" /> - + Date: Fri, 6 Jan 2023 18:37:26 +0100 Subject: [PATCH 63/68] Release 3.13.7 --- app/build.gradle | 4 +-- app/src/main/assets/release_notes/notes.json | 5 ++++ .../android/ui/drawer/StatusAdapter.java | 26 ++++++++++++++----- .../res/layout/drawer_status_pixelfed.xml | 24 +++++++++++++---- .../metadata/android/en/changelogs/461.txt | 3 +++ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1ad481d40..5efca00f0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 33 - versionCode 460 - versionName "3.13.6" + versionCode 461 + versionName "3.13.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index e8fc65450..35d084d40 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,9 @@ [ + { + "version": "3.13.7", + "code": "461", + "note": "Added:\n- Pixelfed: Custom layout to display Media fully \n*(Settings > Timelines > Pixelfed Presentation) - Also works for other softwares when there are media\n\nChanged:\n- Add pinned tag in \"any\" to avoid to lose it when renaming timeline\n\nFixed:\n- Fix push notifications with several accounts\n- Fix quotes with tags/mentions\n- Fix notifications\n- Fix sending multiple media\n- Some crashes" + }, { "version": "3.13.6", "code": "460", diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 376951461..45bf4949b 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -195,6 +195,9 @@ public class StatusAdapter extends RecyclerView.Adapter private static boolean isVisiblePixelfed(Status status) { + if (status.reblog != null) { + status = status.reblog; + } return status.media_attachments != null && status.media_attachments.size() > 0; } @@ -2606,24 +2609,33 @@ public class StatusAdapter extends RecyclerView.Adapter context.startActivity(intent); }); } else if (viewHolder.getItemViewType() == STATUS_PIXELFED) { + Status statusToDeal = status.reblog != null ? status.reblog : status; StatusViewHolder holder = (StatusViewHolder) viewHolder; - MastodonHelper.loadPPMastodon(holder.bindingPixelfed.artPp, status.account); - SliderAdapter adapter = new SliderAdapter(status); + + if (status.reblog != null) { + MastodonHelper.loadPPMastodon(holder.bindingPixelfed.artReblogPp, status.account); + holder.bindingPixelfed.artReblogPp.setVisibility(View.VISIBLE); + } else { + holder.bindingPixelfed.artReblogPp.setVisibility(View.GONE); + } + + MastodonHelper.loadPPMastodon(holder.bindingPixelfed.artPp, statusToDeal.account); + SliderAdapter adapter = new SliderAdapter(statusToDeal); holder.bindingPixelfed.artMedia.setSliderAdapter(adapter); holder.bindingPixelfed.artMedia.setSliderTransformAnimation(SliderAnimations.SIMPLETRANSFORMATION); holder.bindingPixelfed.artMedia.setAutoCycleDirection(SliderView.AUTO_CYCLE_DIRECTION_BACK_AND_FORTH); holder.bindingPixelfed.artMedia.setScrollTimeInSec(4); holder.bindingPixelfed.artMedia.startAutoCycle(); - holder.bindingPixelfed.commentNumber.setText(String.valueOf(status.replies_count)); + holder.bindingPixelfed.commentNumber.setText(String.valueOf(statusToDeal.replies_count)); holder.bindingPixelfed.artUsername.setText( - status.account.getSpanDisplayName(context, + statusToDeal.account.getSpanDisplayName(context, new WeakReference<>(holder.bindingPixelfed.artUsername)), TextView.BufferType.SPANNABLE); - holder.bindingPixelfed.artAcct.setText(String.format(Locale.getDefault(), "@%s", status.account.acct)); + holder.bindingPixelfed.artAcct.setText(String.format(Locale.getDefault(), "@%s", statusToDeal.account.acct)); holder.bindingPixelfed.artPp.setOnClickListener(v -> { Intent intent = new Intent(context, ProfileActivity.class); Bundle b = new Bundle(); - b.putSerializable(Helper.ARG_ACCOUNT, status.account); + b.putSerializable(Helper.ARG_ACCOUNT, statusToDeal.account); intent.putExtras(b); ActivityOptionsCompat options = ActivityOptionsCompat .makeSceneTransitionAnimation((Activity) context, holder.bindingPixelfed.artPp, context.getString(R.string.activity_porfile_pp)); @@ -2631,7 +2643,7 @@ public class StatusAdapter extends RecyclerView.Adapter }); holder.bindingPixelfed.bottomBanner.setOnClickListener(v -> { Intent intent = new Intent(context, ContextActivity.class); - intent.putExtra(Helper.ARG_STATUS, status); + intent.putExtra(Helper.ARG_STATUS, statusToDeal); context.startActivity(intent); }); } diff --git a/app/src/main/res/layout/drawer_status_pixelfed.xml b/app/src/main/res/layout/drawer_status_pixelfed.xml index 317c14b3f..c410908d1 100644 --- a/app/src/main/res/layout/drawer_status_pixelfed.xml +++ b/app/src/main/res/layout/drawer_status_pixelfed.xml @@ -18,6 +18,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/art_container" + android:layout_marginHorizontal="@dimen/card_margin" + android:layout_marginTop="@dimen/card_margin" android:layout_width="match_parent" android:layout_height="wrap_content"> @@ -54,12 +56,24 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"> - - + android:layout_height="50dp"> + + + + + + Timelines > Pixelfed Presentation) - Also works for other softwares when there are media Changed: - Add pinned tag in "any" to avoid to lose it when renaming timeline From cd4df2d29a2288e658875d96fa929f504c96f519 Mon Sep 17 00:00:00 2001 From: Jean-Luc Tibaux Date: Sat, 7 Jan 2023 08:51:16 +0100 Subject: [PATCH 64/68] Translated using Weblate (German) Currently translated at 38.5% (27 of 70 strings) Co-authored-by: Jean-Luc Tibaux Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/ Translation: Fedilab/description --- .../metadata/android/de/changelogs/395.txt | 2 ++ .../metadata/android/de/changelogs/398.txt | 6 ++++++ .../metadata/android/de/changelogs/409.txt | 5 +++++ .../metadata/android/de/changelogs/410.txt | 4 ++++ .../metadata/android/de/changelogs/411.txt | 3 +++ .../metadata/android/de/changelogs/412.txt | 5 +++++ .../metadata/android/de/changelogs/413.txt | 10 ++++++++++ .../metadata/android/de/changelogs/414.txt | 7 +++++++ .../metadata/android/de/changelogs/415.txt | 2 ++ .../metadata/android/de/changelogs/416.txt | 12 ++++++++++++ .../metadata/android/de/changelogs/417.txt | 15 +++++++++++++++ 11 files changed, 71 insertions(+) create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/395.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/398.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/409.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/410.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/411.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/412.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/413.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/414.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/415.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/416.txt create mode 100644 src/fdroid/fastlane/metadata/android/de/changelogs/417.txt diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/395.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/395.txt new file mode 100644 index 000000000..bcbbc5a5a --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/395.txt @@ -0,0 +1,2 @@ +- Fehlerbehebungen +- Ermöglicht das Teilen aus der App diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/398.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/398.txt new file mode 100644 index 000000000..f52770330 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/398.txt @@ -0,0 +1,6 @@ +- Weiteres Verbessern des Scrollverhaltens +- Scrollen nach oben (erneute Auswahl des Tabs) holt neue Nachrichten und scrollt dann nach oben +- Fokuspunkt für die Medienvorschau entfernen +- Behebung des Problems, dass Nachrichten nicht mit einem Konto geteilt werden können +- Behebung des schwarzen Themas +- Behebung einiger Schaltflächenfarben diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/409.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/409.txt new file mode 100644 index 000000000..6bd771e1a --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/409.txt @@ -0,0 +1,5 @@ +- Behebung eines Problems mit dem Cache und der Home-Timeline +- Nitter-Zeitleisten verwenden die benutzerdefinierte Instanz aus den Einstellungen +- Behebung von Nitter-Problemen (nur RT) +- Ungültiges Zertifikat für Onion-URLs (Google) wird nicht mehr akzeptiert +- Behebung einiger Abstürze diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/410.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/410.txt new file mode 100644 index 000000000..f5a7a924b --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/410.txt @@ -0,0 +1,4 @@ +- Neuer Cache-Mechanismus +- Cache kann in den Einstellungen deaktiviert werden +- Hinzufügen von Zählern für neue Nachrichten +- Einige Korrekturen. diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/411.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/411.txt new file mode 100644 index 000000000..2737568c2 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/411.txt @@ -0,0 +1,3 @@ +- Fehlerkorrektur für Beiträge die Medien enthalten +- Ladeverhalten der Thumbnails einstellen: Immer/Nur WLAN/Fragen +- Einige andere kleine Korrekturen diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/412.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/412.txt new file mode 100644 index 000000000..a21f318d8 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/412.txt @@ -0,0 +1,5 @@ +- Korrektur der Beitragsnachricht mit Medien +- Kodierungsproblem bei Medienbeschreibungen behoben +- Behebung der Friendica-Tag-Suche +- Korrekturen beim Verfassen +- Einige andere kleine Korrekturen diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/413.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/413.txt new file mode 100644 index 000000000..b354236db --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/413.txt @@ -0,0 +1,10 @@ +Neu hinzugefügt: +- Zwischenspeicher-Mechanismus (kann in den Einstellungen deaktiviert werden) +- Ladeverhalten für Vorschau einstellbar (Immer/Nur mit WLan/Fragen) +- Zähler für neue Nachrichten in Zeitleisten verfügbar +Behoben: +- Kontextmenü funktioniert nicht in Threads +- Problem bei Tag-Suche mit Friendica +- Klick auf Benachrichtigung öffnet den falschen Tab +- Kodierungsproblem bei der Beschreibung von Medien +- Einige andere Korrekturen diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/414.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/414.txt new file mode 100644 index 000000000..4958da74a --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/414.txt @@ -0,0 +1,7 @@ +Hinzugefügt: +- Zähler in den Einstellungen deaktivieren +Behoben: +- Doppelte Nachrichten aus dem Cache +- Benachrichtigungen im Doppel +- Entwürfe werden nicht automatisch entfernt +- Nachrichten werden nach Löschung nicht aus dem Cache entfernt diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/415.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/415.txt new file mode 100644 index 000000000..6aee60738 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/415.txt @@ -0,0 +1,2 @@ +Behoben: +- Fehler beim Anhängen von Medien an eine Antwort diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/416.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/416.txt new file mode 100644 index 000000000..03f03369d --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/416.txt @@ -0,0 +1,12 @@ +Geändert: +- Swipe zwischen Zeitleisten +- Cache verbessern +- Schaltflächengrößen in Nachrichten folgen definierter Skala + +Behoben: +- Pleroma: Emoji-Reaktionen +- Teilen (mehrere Korrekturen) +- Theme-Probleme +- Rendering-Problem für Links +- Benachrichtigungen werden nicht aus dem Cache entfernt +- Einige Abstürze diff --git a/src/fdroid/fastlane/metadata/android/de/changelogs/417.txt b/src/fdroid/fastlane/metadata/android/de/changelogs/417.txt new file mode 100644 index 000000000..148727244 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/de/changelogs/417.txt @@ -0,0 +1,15 @@ +Geändert: +- Swipe zwischen Zeitleisten +- Cache verbessern +- Die Größe der Schaltflächen kann in den Einstellungen geändert werden +- Französische Übersetzung + +Behoben: +- Pleroma: Emoji-Reaktionen +- Teilen (mehrere Korrekturen) +- Theme-Probleme +- Rendering-Problem für Links +- Benachrichtigungen werden nicht aus dem Cache entfernt +- Problem mit Wasserzeichen +- Paginierung mit Lesezeichen/Favoriten +- Einige Abstürze From 3ea4559f697f6d9cc7f9d288438334da53527a97 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 7 Jan 2023 15:27:33 +0100 Subject: [PATCH 65/68] Option to align left message bottom buttons --- .../app/fedilab/android/ui/drawer/StatusAdapter.java | 9 +++++++++ app/src/main/res/values-w1240dp/dimens.xml | 2 +- app/src/main/res/values-w600dp/dimens.xml | 2 +- app/src/main/res/values/strings.xml | 4 ++++ app/src/main/res/xml/pref_interface.xml | 8 ++++++++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 45bf4949b..25e1059ac 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -71,6 +71,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.LinearLayoutCompat; import androidx.appcompat.widget.PopupMenu; import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.constraintlayout.widget.ConstraintSet; import androidx.core.app.ActivityOptionsCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; @@ -413,6 +414,14 @@ public class StatusAdapter extends RecyclerView.Adapter boolean extraFeatures = sharedpreferences.getBoolean(context.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false); boolean displayQuote = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_QUOTES) + MainActivity.currentUserID + MainActivity.currentInstance, true); boolean displayReactions = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_REACTIONS) + MainActivity.currentUserID + MainActivity.currentInstance, true); + boolean compactButtons = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COMPACT_ACTION_BUTTON), false); + + if (compactButtons) { + ConstraintSet set = new ConstraintSet(); + set.clone(holder.binding.actionButtons); + set.clear(R.id.status_emoji, ConstraintSet.END); + set.applyTo(holder.binding.actionButtons); + } if (removeLeftMargin) { LinearLayoutCompat.MarginLayoutParams p = (LinearLayoutCompat.MarginLayoutParams) holder.binding.spoiler.getLayoutParams(); diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml index d73f4a359..22d7f0043 100644 --- a/app/src/main/res/values-w1240dp/dimens.xml +++ b/app/src/main/res/values-w1240dp/dimens.xml @@ -1,3 +1,3 @@ - 200dp + 48dp \ No newline at end of file diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml index 22d7f0043..2a235a023 100644 --- a/app/src/main/res/values-w600dp/dimens.xml +++ b/app/src/main/res/values-w600dp/dimens.xml @@ -1,3 +1,3 @@ - 48dp + 32dp \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9068bf22c..e83cc5cc7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1371,6 +1371,8 @@ SET_UNFOLLOW_VALIDATION SET_USE_SINGLE_TOPBAR SET_DISPLAY_COUNTERS + SET_DISPLAY_COMPACT_ACTION_BUTTON + SET_TIMELINES_IN_A_LIST SET_LED_COLOUR_VAL_N SET_SHOW_BOOSTS @@ -2201,4 +2203,6 @@ Local only Display \"Local only\" button Pixelfed presentation for media + Compact action buttons + Buttons at the bottom of messages will not take the whole width \ No newline at end of file diff --git a/app/src/main/res/xml/pref_interface.xml b/app/src/main/res/xml/pref_interface.xml index ef3387c38..da7f64c32 100644 --- a/app/src/main/res/xml/pref_interface.xml +++ b/app/src/main/res/xml/pref_interface.xml @@ -53,6 +53,14 @@ app:summary="@string/set_display_counters_description" app:title="@string/set_display_counters" /> + + Date: Sat, 7 Jan 2023 15:36:57 +0100 Subject: [PATCH 66/68] Fix a crash for long messages --- app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java index f66b8ca3b..3e9f97be6 100644 --- a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java +++ b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java @@ -272,7 +272,7 @@ public class ComposeWorker extends Worker { b.putSerializable(Helper.ARG_STATUS_DRAFT, dataPost.statusDraft); String err = statusResponse.errorBody().string(); if (err.contains("{\"error\":\"")) { - err = err.replaceAll("\\{\"error\":\"(.*)\"}", "$1"); + err = err.replaceAll("\\{\"error\":\"(.*)\"\\}", "$1"); } b.putSerializable(Helper.RECEIVE_ERROR_MESSAGE, err); intentBD.putExtras(b); From 6df271c3194ef9488ae7e3eb3d80852fb795193a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 7 Jan 2023 17:03:50 +0100 Subject: [PATCH 67/68] Fix urls --- .../android/helper/SpannableHelper.java | 57 ++++++++++++++++--- .../android/ui/drawer/StatusAdapter.java | 3 + .../timeline/FragmentMastodonTimeline.java | 5 ++ .../metadata/android/en/changelogs/462.txt | 20 +++++++ 4 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/462.txt diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 6ac84cac9..f53c1172a 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -41,6 +41,7 @@ import android.text.style.URLSpan; import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; +import android.webkit.URLUtil; import android.widget.Toast; import androidx.annotation.NonNull; @@ -286,19 +287,25 @@ public class SpannableHelper { private static void makeLinks(Context context, SpannableStringBuilder content, String url, int start, int end) { String newUrl = url; - String newURL = Helper.transformURL(context, url); - //If URL has been transformed - if (newURL.compareTo(url) != 0) { - content.replace(start, end, newURL); - end = start + newURL.length(); - url = newURL; + boolean validUrl = URLUtil.isValidUrl(url) && url.length() == (end - start); + if (validUrl) { + newUrl = Helper.transformURL(context, url); } - if (url.length() > 30 && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("gimini://"))) { + + + //If URL has been transformed + if (validUrl && newUrl.compareTo(url) != 0) { + content.replace(start, end, newUrl); + end = start + newUrl.length(); + url = newUrl; + } + if (url.length() > 30 && (validUrl || url.startsWith("gimini://"))) { newUrl = url.substring(0, 30); newUrl += "…"; content.replace(start, end, newUrl); } - int matchEnd = start + newUrl.length(); + int matchEnd = validUrl ? start + newUrl.length() : end; + String finalUrl = url; if (content.length() < matchEnd) { matchEnd = content.length(); @@ -439,6 +446,8 @@ public class SpannableHelper { textView.setTag(CLICKABLE_SPAN); Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); Matcher matcherLink = link.matcher(finalUrl); + Pattern linkLong = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)(/[0-9]+)?$"); + Matcher matcherLinkLong = linkLong.matcher(finalUrl); if (matcherLink.find() && !finalUrl.contains("medium.com")) { if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() { @@ -460,6 +469,38 @@ public class SpannableHelper { public void federatedStatus(Status status) { } + @Override + public void federatedAccount(Account account) { + Intent intent = new Intent(context, ProfileActivity.class); + Bundle b = new Bundle(); + b.putSerializable(Helper.ARG_ACCOUNT, account); + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + }); + } + } else if (matcherLinkLong.find() && !finalUrl.contains("medium.com")) { + if (matcherLinkLong.group(3) != null && Objects.requireNonNull(matcherLinkLong.group(3)).length() > 0) { //It's a toot + CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { + Intent intent = new Intent(context, ContextActivity.class); + intent.putExtra(Helper.ARG_STATUS, status); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + @Override + public void federatedAccount(Account account) { + } + }); + } else if (matcherLinkLong.group(2) != null) {//It's an account + CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLinkLong.group(2), new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { + } + @Override public void federatedAccount(Account account) { Intent intent = new Intent(context, ProfileActivity.class); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 25e1059ac..a3bda4bb7 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -1743,6 +1743,9 @@ public class StatusAdapter extends RecyclerView.Adapter statusDraft.statusReplyList = new ArrayList<>(); statusToDeal.text = statusSource.text; statusToDeal.spoiler_text = statusSource.spoiler_text; + if (statusToDeal.spoiler_text != null && statusToDeal.spoiler_text.length() > 0) { + statusToDeal.spoilerChecked = true; + } statusDraft.statusDraftList.add(statusToDeal); intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); intent.putExtra(Helper.ARG_EDIT_STATUS_ID, statusToDeal.id); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 560809216..b3e2e6b42 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -366,6 +366,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (acctArray.length > 1) { remoteInstance = acctArray[1]; } + if (remoteInstance != null && remoteInstance.equalsIgnoreCase(currentInstance)) { + checkRemotely = false; + } else if (remoteInstance == null) { + checkRemotely = false; + } } if (tagTimeline != null) { ident = "@T@" + tagTimeline.name; diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt new file mode 100644 index 000000000..ed7710059 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt @@ -0,0 +1,20 @@ +Added: + +- Add Bubble timeline support in extra-features with filters +- Allow to display public profiles by default to get all messages (Settings > Interface) +- Glitch: Allow to post messages locally (Can be turned off in Settings) +- Pixelfed: Custom layout to display Media fully (Also works for other software when there are media) +- Allow to align left action buttons in messages + +Changed: +- Full rework on links in messages (also mentions and tags) +- Add pinned tag in "any" to avoid to lose it when renaming timeline + +Fixed: +- Links to messages not handled by the app +- CW when editing a message +- Fix push notifications with several accounts +- Fix quotes with tags/mentions +- Fix notifications +- Fix sending multiple media +- Fix crashes \ No newline at end of file From 47e43193b834feabfb02c030960e88aca3b02458 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 7 Jan 2023 17:47:57 +0100 Subject: [PATCH 68/68] Release 3.14.0 --- app/build.gradle | 4 ++-- app/src/main/assets/release_notes/notes.json | 5 +++++ .../client/endpoints/MastodonNotificationsService.java | 7 ++++++- .../fedilab/android/helper/NotificationsHelper.java | 7 ++++++- .../app/fedilab/android/helper/PushNotifications.java | 10 +++++++++- .../android/viewmodel/mastodon/NotificationsVM.java | 9 +++++++-- .../fastlane/metadata/android/en/changelogs/462.txt | 1 + 7 files changed, 36 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5efca00f0..2046c73dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 33 - versionCode 461 - versionName "3.13.7" + versionCode 462 + versionName "3.14.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index 35d084d40..c55a9703b 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,9 @@ [ + { + "version": "3.14.0", + "code": "462", + "note": "Added:\n\n- Add Bubble timeline support in extra-features with filters\n- Allow to display public profiles by default to get all messages (Settings > Interface)\n- Glitch: Allow to post messages locally (Can be turned off in Settings)\n- Pixelfed: Custom layout to display Media fully (Also works for other software when there are media)\n- Allow to align left action buttons in messages\n\nChanged:\n- Full rework on links in messages (also mentions and tags)\n- Add pinned tag in \"any\" to avoid to lose it when renaming timeline\n\nFixed:\n- Links to messages not handled by the app\n- CW when editing a message\n- Fix push notifications with several accounts\n- New messages or edition notifications not pushed\n- Fix quotes with tags/mentions\n- Fix notifications\n- Fix sending multiple media\n- Fix crashes" + }, { "version": "3.13.7", "code": "461", diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonNotificationsService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonNotificationsService.java index d6f2f15a1..898359fb9 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonNotificationsService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonNotificationsService.java @@ -71,7 +71,12 @@ public interface MastodonNotificationsService { @Field("data[alerts][favourite]") boolean favourite, @Field("data[alerts][reblog]") boolean reblog, @Field("data[alerts][mention]") boolean mention, - @Field("data[alerts][poll]") boolean poll + @Field("data[alerts][poll]") boolean poll, + @Field("data[alerts][status]") boolean status, + @Field("data[alerts][update]") boolean update, + @Field("data[alerts][admin.sign_up]") boolean admin_sign_up, + @Field("data[alerts][admin.report]") boolean admin_report + ); @GET("push/subscription") diff --git a/app/src/main/java/app/fedilab/android/helper/NotificationsHelper.java b/app/src/main/java/app/fedilab/android/helper/NotificationsHelper.java index 18a81cfbd..4473d48f8 100644 --- a/app/src/main/java/app/fedilab/android/helper/NotificationsHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/NotificationsHelper.java @@ -90,8 +90,13 @@ public class NotificationsHelper { boolean notif_share = prefs.getBoolean(context.getString(R.string.SET_NOTIF_SHARE), true); boolean notif_poll = prefs.getBoolean(context.getString(R.string.SET_NOTIF_POLL), true); boolean notif_fav = prefs.getBoolean(context.getString(R.string.SET_NOTIF_FAVOURITE), true); + boolean notif_status = prefs.getBoolean(context.getString(R.string.SET_NOTIF_STATUS), true); + boolean notif_updates = prefs.getBoolean(context.getString(R.string.SET_NOTIF_UPDATE), true); + boolean notif_signup = prefs.getBoolean(context.getString(R.string.SET_NOTIF_ADMIN_SIGNUP), true); + boolean notif_report = prefs.getBoolean(context.getString(R.string.SET_NOTIF_ADMIN_REPORT), true); + //User disagree with all notifications - if (!notif_follow && !notif_fav && !notif_mention && !notif_share && !notif_poll) + if (!notif_follow && !notif_fav && !notif_mention && !notif_share && !notif_poll && !notif_status && !notif_updates && !notif_signup && !notif_report) return; //Nothing is done MastodonNotificationsService mastodonNotificationsService = init(context, slugArray[1]); diff --git a/app/src/main/java/app/fedilab/android/helper/PushNotifications.java b/app/src/main/java/app/fedilab/android/helper/PushNotifications.java index a2be75ea9..eda242596 100644 --- a/app/src/main/java/app/fedilab/android/helper/PushNotifications.java +++ b/app/src/main/java/app/fedilab/android/helper/PushNotifications.java @@ -64,6 +64,10 @@ public class PushNotifications { boolean notif_share = prefs.getBoolean(context.getString(R.string.SET_NOTIF_SHARE), true); boolean notif_poll = prefs.getBoolean(context.getString(R.string.SET_NOTIF_POLL), true); boolean notif_fav = prefs.getBoolean(context.getString(R.string.SET_NOTIF_FAVOURITE), true); + boolean notif_status = prefs.getBoolean(context.getString(R.string.SET_NOTIF_STATUS), true); + boolean notif_updates = prefs.getBoolean(context.getString(R.string.SET_NOTIF_UPDATE), true); + boolean notif_signup = prefs.getBoolean(context.getString(R.string.SET_NOTIF_ADMIN_SIGNUP), true); + boolean notif_report = prefs.getBoolean(context.getString(R.string.SET_NOTIF_ADMIN_REPORT), true); new Thread(() -> { String[] slugArray = slug.split("@"); BaseAccount accountDb = null; @@ -87,7 +91,11 @@ public class PushNotifications { notif_fav, notif_share, notif_mention, - notif_poll); + notif_poll, + notif_status, + notif_updates, + notif_signup, + notif_report); if (pushSubscriptionCall != null) { try { Response pushSubscriptionResponse = pushSubscriptionCall.execute(); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java index d7ee2dd4b..02e63b43c 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java @@ -304,12 +304,17 @@ public class NotificationsVM extends AndroidViewModel { boolean favourite, boolean reblog, boolean mention, - boolean poll) { + boolean poll, + boolean status, + boolean updates, + boolean signup, + boolean report + ) { pushSubscriptionMutableLiveData = new MutableLiveData<>(); MastodonNotificationsService mastodonNotificationsService = init(instance); new Thread(() -> { PushSubscription pushSubscription = null; - Call pushSubscriptionCall = mastodonNotificationsService.pushSubscription(token, endpoint, keys_p256dh, keys_auth, follow, favourite, reblog, mention, poll); + Call pushSubscriptionCall = mastodonNotificationsService.pushSubscription(token, endpoint, keys_p256dh, keys_auth, follow, favourite, reblog, mention, poll, status, updates, signup, report); if (pushSubscriptionCall != null) { try { Response pushSubscriptionResponse = pushSubscriptionCall.execute(); diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt index ed7710059..f737820eb 100644 --- a/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/462.txt @@ -14,6 +14,7 @@ Fixed: - Links to messages not handled by the app - CW when editing a message - Fix push notifications with several accounts +- New messages or edition notifications not pushed - Fix quotes with tags/mentions - Fix notifications - Fix sending multiple media