From 7546d795334acaa847a815e8a0fe6eae1c48d1ce Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 9 Dec 2022 18:07:44 +0100 Subject: [PATCH 01/42] Check status --- .../android/activities/ContextActivity.java | 114 ++++++++++++++---- .../android/helper/CrossActionHelper.java | 43 +++++++ .../timeline/FragmentMastodonContext.java | 31 ++++- .../ic_baseline_location_searching_24.xml | 10 ++ app/src/main/res/menu/menu_context.xml | 6 + app/src/main/res/values/strings.xml | 4 + 6 files changed, 177 insertions(+), 31 deletions(-) create mode 100644 app/src/main/res/drawable/ic_baseline_location_searching_24.xml diff --git a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java index 243e90b0..e486e14d 100644 --- a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java @@ -18,11 +18,13 @@ package app.fedilab.android.activities; import static app.fedilab.android.BaseMainActivity.currentAccount; import static app.fedilab.android.ui.drawer.StatusAdapter.sendAction; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; @@ -35,27 +37,32 @@ import androidx.preference.PreferenceManager; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; +import app.fedilab.android.client.entities.api.Account; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.StatusCache; import app.fedilab.android.databinding.ActivityConversationBinding; import app.fedilab.android.exception.DBException; +import app.fedilab.android.helper.CrossActionHelper; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.ui.fragment.timeline.FragmentMastodonContext; import app.fedilab.android.viewmodel.mastodon.StatusesVM; +import es.dmoral.toasty.Toasty; -public class ContextActivity extends BaseActivity { +public class ContextActivity extends BaseActivity implements FragmentMastodonContext.FirstMessage { public static boolean expand; public static boolean displayCW; public static Resources.Theme theme; Fragment currentFragment; + private Status firstMessage; + private String remote_instance; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - app.fedilab.android.databinding.ActivityConversationBinding binding = ActivityConversationBinding.inflate(getLayoutInflater()); + ActivityConversationBinding binding = ActivityConversationBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); ActionBar actionBar = getSupportActionBar(); @@ -75,8 +82,10 @@ public class ContextActivity extends BaseActivity { Bundle b = getIntent().getExtras(); displayCW = sharedpreferences.getBoolean(getString(R.string.SET_EXPAND_CW), false); Status focusedStatus = null; // or other values - if (b != null) + if (b != null) { focusedStatus = (Status) b.getSerializable(Helper.ARG_STATUS); + remote_instance = b.getString(Helper.ARG_REMOTE_INSTANCE, null); + } if (focusedStatus == null || currentAccount == null || currentAccount.mastodon_account == null) { finish(); return; @@ -84,29 +93,34 @@ public class ContextActivity extends BaseActivity { MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account); Bundle bundle = new Bundle(); bundle.putSerializable(Helper.ARG_STATUS, focusedStatus); - currentFragment = Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_content_main, new FragmentMastodonContext(), bundle, null, null); - StatusesVM timelinesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class); - timelinesVM.getStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id).observe(ContextActivity.this, status -> { - if (status != null) { - StatusCache statusCache = new StatusCache(); - statusCache.instance = BaseMainActivity.currentInstance; - statusCache.user_id = BaseMainActivity.currentUserID; - statusCache.status = status; - statusCache.status_id = status.id; - //Update cache - new Thread(() -> { - try { - new StatusCache(getApplication()).updateIfExists(statusCache); - Handler mainHandler = new Handler(Looper.getMainLooper()); - //Update UI - Runnable myRunnable = () -> sendAction(ContextActivity.this, Helper.ARG_STATUS_ACTION, status, null); - mainHandler.post(myRunnable); - } catch (DBException e) { - e.printStackTrace(); - } - }).start(); - } - }); + bundle.putString(Helper.ARG_REMOTE_INSTANCE, remote_instance); + FragmentMastodonContext fragmentMastodonContext = new FragmentMastodonContext(); + fragmentMastodonContext.firstMessage = this; + currentFragment = Helper.addFragment(getSupportFragmentManager(), R.id.nav_host_fragment_content_main, fragmentMastodonContext, bundle, null, null); + if (remote_instance == null) { + StatusesVM timelinesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class); + timelinesVM.getStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id).observe(ContextActivity.this, status -> { + if (status != null) { + StatusCache statusCache = new StatusCache(); + statusCache.instance = BaseMainActivity.currentInstance; + statusCache.user_id = BaseMainActivity.currentUserID; + statusCache.status = status; + statusCache.status_id = status.id; + //Update cache + new Thread(() -> { + try { + new StatusCache(getApplication()).updateIfExists(statusCache); + Handler mainHandler = new Handler(Looper.getMainLooper()); + //Update UI + Runnable myRunnable = () -> sendAction(ContextActivity.this, Helper.ARG_STATUS_ACTION, status, null); + mainHandler.post(myRunnable); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); + } + }); + } } @@ -126,6 +140,10 @@ public class ContextActivity extends BaseActivity { } else { itemDisplayCW.setIcon(R.drawable.ic_outline_remove_red_eye_24); } + MenuItem action_remote = menu.findItem(R.id.action_remote); + if (remote_instance != null) { + action_remote.setVisible(false); + } return true; } @@ -151,8 +169,52 @@ public class ContextActivity extends BaseActivity { ((FragmentMastodonContext) currentFragment).refresh(); } invalidateOptionsMenu(); + } else if (item.getItemId() == R.id.action_remote) { + + if (firstMessage == null) { + Toasty.warning(ContextActivity.this, getString(R.string.toast_try_later), Toasty.LENGTH_SHORT).show(); + return true; + } + if (firstMessage.account.acct != null) { + String[] splitAcct = firstMessage.account.acct.split("@"); + String instance; + if (splitAcct.length > 1) { + instance = splitAcct[1]; + } else { + Toasty.info(ContextActivity.this, getString(R.string.toast_on_your_instance), Toasty.LENGTH_SHORT).show(); + return true; + } + Log.v(Helper.TAG, "firstMessage.uri: " + firstMessage.uri); + Log.v(Helper.TAG, "instance: " + instance); + CrossActionHelper.fetchStatusInRemoteInstance(ContextActivity.this, firstMessage.uri, instance, new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { + Log.v(Helper.TAG, ">status: " + status); + if (status != null) { + Intent intentContext = new Intent(ContextActivity.this, ContextActivity.class); + intentContext.putExtra(Helper.ARG_STATUS, status); + intentContext.putExtra(Helper.ARG_REMOTE_INSTANCE, true); + intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intentContext); + } else { + Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show(); + } + } + + @Override + public void federatedAccount(Account account) { + Log.v(Helper.TAG, ">account: " + account); + } + }); + } else { + Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show(); + } } return true; } + @Override + public void get(Status status) { + firstMessage = status; + } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java b/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java index 40e62117..be38d26c 100644 --- a/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java @@ -20,6 +20,7 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.util.Log; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; @@ -439,6 +440,48 @@ public class CrossActionHelper { } + /** + * Fetch and federate the remote status + */ + public static void fetchStatusInRemoteInstance(@NonNull Context context, String url, String instance, Callback callback) { + + MastodonSearchService mastodonSearchService = init(context, instance); + new Thread(() -> { + Call resultsCall = mastodonSearchService.search(null, url, null, "statuses", null, null, null, null, null, null, null); + Results results = null; + Log.v(Helper.TAG, ">request: " + resultsCall.request()); + if (resultsCall != null) { + try { + Response resultsResponse = resultsCall.execute(); + if (resultsResponse.isSuccessful()) { + + results = resultsResponse.body(); + if (results != null) { + if (results.statuses == null) { + results.statuses = new ArrayList<>(); + } + } + } else { + Log.v(Helper.TAG, ">err: " + resultsResponse.errorBody().string()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + Results finalResults = results; + Runnable myRunnable = () -> { + Log.v(Helper.TAG, ">finalResults.statuses " + finalResults.statuses); + if (finalResults != null && finalResults.statuses != null && finalResults.statuses.size() > 0) { + callback.federatedStatus(finalResults.statuses.get(0)); + } + }; + mainHandler.post(myRunnable); + + }).start(); + } + + /** * Fetch and federate the remote status */ 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 b3fd472d..33dc10c8 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 @@ -34,9 +34,9 @@ import androidx.recyclerview.widget.LinearLayoutManager; import java.util.ArrayList; import java.util.List; -import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; import app.fedilab.android.activities.ContextActivity; +import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.entities.api.Context; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.Timeline; @@ -54,6 +54,8 @@ public class FragmentMastodonContext extends Fragment { 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 @@ -116,8 +118,10 @@ public class FragmentMastodonContext extends Fragment { } }; private Status focusedStatus; + private String remote_instance; private Status firstStatus; private boolean pullToRefresh; + private String user_token, user_instance; /** * Return the position of the status in the ArrayList @@ -145,17 +149,26 @@ public class FragmentMastodonContext extends Fragment { pullToRefresh = false; if (getArguments() != null) { focusedStatus = (Status) getArguments().getSerializable(Helper.ARG_STATUS); + remote_instance = getArguments().getString(Helper.ARG_REMOTE_INSTANCE, null); + } + if (remote_instance != null) { + user_instance = remote_instance; + user_token = null; + } else { + user_instance = MainActivity.currentInstance; + user_token = MainActivity.currentToken; } if (focusedStatus == null) { getChildFragmentManager().beginTransaction().remove(this).commit(); } + binding = FragmentPaginationBinding.inflate(inflater, container, false); statusesVM = new ViewModelProvider(FragmentMastodonContext.this).get(StatusesVM.class); binding.recyclerView.setNestedScrollingEnabled(true); this.statuses = new ArrayList<>(); focusedStatus.isFocused = true; this.statuses.add(focusedStatus); - statusAdapter = new StatusAdapter(this.statuses, Timeline.TimeLineEnum.UNKNOWN, false, true, false); + statusAdapter = new StatusAdapter(this.statuses, Timeline.TimeLineEnum.UNKNOWN, false, true, remote_instance != null); binding.swipeContainer.setRefreshing(false); LinearLayoutManager mLayoutManager = new LinearLayoutManager(requireActivity()); binding.recyclerView.setLayoutManager(mLayoutManager); @@ -164,12 +177,12 @@ public class FragmentMastodonContext extends Fragment { if (this.statuses.size() > 0) { binding.swipeContainer.setRefreshing(true); pullToRefresh = true; - statusesVM.getContext(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id) + statusesVM.getContext(user_instance, user_token, focusedStatus.id) .observe(getViewLifecycleOwner(), this::initializeContextView); } }); if (focusedStatus != null) { - statusesVM.getContext(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, focusedStatus.id) + statusesVM.getContext(user_instance, user_token, focusedStatus.id) .observe(getViewLifecycleOwner(), this::initializeContextView); } LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(receive_action, new IntentFilter(Helper.RECEIVE_STATUS_ACTION)); @@ -196,7 +209,7 @@ public class FragmentMastodonContext extends Fragment { } else { id = focusedStatus.id; } - statusesVM.getContext(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, id) + statusesVM.getContext(user_instance, user_token, id) .observe(FragmentMastodonContext.this, this::initializeContextView); } } @@ -228,6 +241,10 @@ public class FragmentMastodonContext extends Fragment { } else { firstStatus = statuses.get(0); } + if (firstMessage != null) { + firstMessage.get(firstStatus); + } + int statusPosition = context.ancestors.size(); //Build the array of statuses statuses.addAll(0, context.ancestors); @@ -250,4 +267,8 @@ public class FragmentMastodonContext extends Fragment { super.onDestroyView(); } + + public interface FirstMessage { + void get(Status status); + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_baseline_location_searching_24.xml b/app/src/main/res/drawable/ic_baseline_location_searching_24.xml new file mode 100644 index 00000000..a32cb664 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_location_searching_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/menu/menu_context.xml b/app/src/main/res/menu/menu_context.xml index 31b56e66..63aabec8 100644 --- a/app/src/main/res/menu/menu_context.xml +++ b/app/src/main/res/menu/menu_context.xml @@ -6,9 +6,15 @@ android:icon="@drawable/ic_baseline_expand_more_24" android:title="@string/expand_conversation" app:showAsAction="ifRoom" /> + + \ 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 259a36f5..4dadf67f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2048,4 +2048,8 @@ Set custom colors Light - Custom colors Dark - Custom colors + Display remote conversation + Please, try again later. + The conversation started on your instance! + The app didn\'t find the remote message. \ No newline at end of file From 62356ff873d9e61611952f9a1ae926ef44703944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Sat, 10 Dec 2022 00:19:28 +0100 Subject: [PATCH 02/42] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 98.4% (959 of 974 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 | 469 ++++++++++++++----------- 1 file changed, 272 insertions(+), 197 deletions(-) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 0f48d25a..73072255 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -15,10 +15,10 @@ Média uložena Soubor: %1$s Heslo - Email + E-mail Účty Zprávy - Štítky + Tagy Uložit Instance Instance: mastodon.social @@ -53,21 +53,21 @@ Místní časová osa Ztlumení uživatelé Blokovaní uživatelé - Oznámení - Žádost o sledování + Upozornění + Žádosti o sledování Nastavení Poslat e-mail Naplánované zprávy Níže uvedené informace mohou popisovat uživatelský profil neúplně. Vložit smajlík Aplikace prozatím nenačetla uživatelské smajlíky. - Are you sure you want to logout @%1$s@%2$s? + Opravdu se chcete odhlásit od @%1$s@%2$s\? Žádné zprávy k zobrazení Přidat tuto zprávu k oblíbeným\? Odstranit tuto zprávu z oblíbených\? Boostnout tuto zprávu\? - Zrušit boost\? + Zrušit boost této zprávy\? Ztlumit Blokovat Nahlásit @@ -96,61 +96,57 @@ Záložky Přidat do záložek Odstranit záložku - Toot byl přidán do záložek! - Toot byl odstraněn ze záložek! + Status byl přidán do záložek! + Status byl odstraněn ze záložek! %d s %d m %d h %d d - %d second - %d seconds - %d seconds - %d seconds + %d sekunda + %d sekundy + %d sekund - %d minute - %d minutes - %d minutes - %d minutes + %d minuta + %d minuty + %d minut - %d hour - %d hours - %d hours - %d hours + %d hodina + %d hodiny + %d hodin - %d day - %d days - %d days - %d days + %d den + %d dny + %d dní Nastala chyba při výběru média! - Smazat médium? + Smazat médium\? Vaše zpráva je prázdná! Zpráva byla odeslána! - Citlivý obsah? + Citlivý obsah\? Žádné koncepty! Vyberte účet Vyberte účty - Odstranit koncept? + Odstranit koncept\? Popsat pro zrakově postižené Popis není dostupný! Release %1$s Vývojář: - Licence: + Licence: GNU GPL V3 - Zdrojový kód: + Zdrojový kód: Prohledat instance: Žádný účet k zobrazení - Není požadavek ke sledování + Žádný požadavek ke sledování Zprávy \n %1$s Sleduji \n %1$s @@ -167,14 +163,14 @@ %1$s je ztlumen do %2$s. \n Klikněte zde pro zrušení ztišení. Žádné upozornění k zobrazení - vás zmínil/a - wrote a new message - boostnul/a váš toot - si oblíbil/a váš toot + vás zmínil(a) + napsal(a) novou zprávu + boostnul(a) váš toot + si oblíbil(a) váš status vás sleduje - asked to follow you - Smazat všechna oznámení? - Všechna oznámení byla smazána! + vás chce sledovat + Smazat všechna upozornění\? + Všechna upozornění byla smazána! Sledující @@ -191,7 +187,7 @@ Zpráva byla odstraněna z oblíbených! Oops! Došlo k chybě! Došlo k chybě! Instance nevrátila autorizační kód! - Tato doména není platná! + Doména instance se zdá být neplatná! Došlo k chybě při přepínání mezi účty! Při vyhledávání došlo k chybě! Nelze vykonat akci @@ -199,18 +195,18 @@ Počet zpráv pro jedno nahrání Zakázat GIF avatary - Oznámení v případě sledování - Oznámení v případě boostnutí vašeho tootu - Oznámení v případě oblíbení vašeho tootu - Oznámení v případě, že vás někdo zmíní - Oznámení po skončení ankety - Notify for new posts - Zobrazit potvrzení před boostnutí + Upozornit, když vás někdo začne sledovat + Upozornit, když někdo boostne váš status + Upozornit, když si někdo oblíbí váš status + Upozornit, když vás někdo zmíní + Upozornit, když skončí anketa + Upozornit na nové příspěvky + Zobrazit potvrzení před boostnutím Zobrazit potvrzení před oblíbením - Oznámení? - Tichá oznámení - NSFW prodleva (vteřiny, 0 znamená vypnuto) - Media Description timeout (seconds, 0 means off) + Upozornit\? + Tichá upozornění + Prodleva NSFW (v sekundách, 0 znamená vypnuto) + Timeout pro popis médií (v sekundách, 0 znamená vypnuto) Vlastní sdílení Vaše vlastní sdílecí URL… Zamknout účet @@ -231,7 +227,7 @@ Žlutá Bílá - Následovat + Sledovat Odblokovat Ztlumit Zrušit ztlumení @@ -239,7 +235,7 @@ Sleduje vás První písmeno velké v odpovědích Změnit velikost obrázků - Resize videos + Změnit velikost videa Mb @@ -264,22 +260,22 @@ Přidat do seznamu Odstranit seznam Nový název seznamu - The account was added to the list! - You don\'t have any lists yet! + Účet byl přidán do seznamu! + Ještě nemáte žádný seznam! %1$s se přesunul do %2$s Média byla nahrána. Klikněte pro zobrazení. Proxy - Povolit proxy? + Povolit proxy\? Host Port Přihlašovací jméno Heslo Přidat podrobnosti zprávy při sdílení Podpořit aplikaci na Liberapay - Chyba v regulárním výrazu! - Časová osa nenalezena na této instanci! + V regulárním výrazu je chyba! + Na této instanci nebyly nalezeny žádné časové osy! Sledovat instanci Tuto instanci již sledujete! Partnerství @@ -292,13 +288,13 @@ Žádné filtry k zobrazení. Můžete vytvořit nový filtr klepnutím na tlačítko \"+\". Klíčové slovo nebo fráze Domovská časová osa - Veřejná časová osa - Oznámení + Veřejné časové osy + Upozornění Konverzace Velikost písmen ani varování o obsahu nebudou brána v potaz Zahodit místo skrytí Filtrované zprávy zmizí nezvratně i v případě, že je filtr později odstraněn - V případě, že klíčové slovo nebo fráze je pouze alfanumerické, filtr se uplatní pouze pokud odpovídá celému slovu + V případě, že klíčové slovo nebo fráze je pouze alfanumerické, filtr se uplatní, pouze pokud odpovídá celému slovu Celé slovo Kontext filtru Jeden nebo několik kontextů pro aplikaci filtru @@ -313,7 +309,7 @@ Nová zmínka Anketa skončila Záloha zpráv - New posts + Nové příspěvky Stahování médií Vybrat tón Zapnout rozvrh oznámení @@ -321,7 +317,7 @@ Zablokovat doménu Doména je blokována Načítám vzdálený toot - Peertube instance + Instance Peertube Použít Emoji One Informace Zobrazit náhled ve všech zprávách @@ -331,20 +327,20 @@ Ořezat zprávy delší než \'x\' řádků. 0 znamená vypnuto. Zobrazit více Zobrazit méně - Štítek již existuje! + Tag již existuje! Naplánovat boost - Boost je naplánováo! - Žádný naplánovaý boost k zobrazení! + Boost je naplánován! + Žádný naplánovaný boost k zobrazení! Otevřete nabídku Profilový obrázek Profilová hlavička Kontaktovat administrátora instance - MastoHost logo + Logo MastoHost Výběr emotikonů Ukázat celou konverzaci Uživatelský výběr emoji Favicon - Médium pro přidání popisu + Přidat k médiu popis (pro zrakově postižené) Nikdy 30 minut @@ -359,7 +355,7 @@ Pouze média Zobrazit NSFW Bot - Pixelfed instance + Instance Pixelfed Instance Mastodon Kterýkoliv Všechny @@ -368,7 +364,7 @@ Všechna slova (oddělená mezerami) Add some words to filter (space-separated) Změnit název sloupce - Misskey instance + Instance Misskey Populární Místní Kategorie @@ -376,19 +372,19 @@ Sdílet Zprávy (Server) Zprávy (Zařízení) - Časové osi + Časové osy Rozhraní Kontakty Při výběru zálohového souboru nastala chyba! Odhlásit účet Vše Kopírovat odkaz - volání http je blokováné aplikací - Seznam blokovaných domén + volání http je blokováno aplikací + Seznam blokovaných volání Odeslat Filtrovat časovou osu s hashtagy Žádné hashtagy - Připojit při sdílení URL obrázek + Při sdílení URL připojit obrázek Vytvořit anketu Volba %d @@ -396,7 +392,7 @@ Hotovo skončit po %s Hlasovat - Anketa, ve které jste hlasoval/a, skončila + Anketa, ve které jste hlasoval(a), skončila Vaše anketa skončila Kategorie Přesunout časovou osu @@ -404,14 +400,14 @@ Spravovat časové osy Seznam trvale smazán Sledovaná instance odstraněna - Připnuté značky odstraněny + Připnuté tagy odstraněny Vrátit zpět - Hlavní časové linie mohou být pouze skryty! + Hlavní časové osy mohou být pouze skryty! Vždy označovat média jako citlivá - GNU instance - Forward tags in replies - Long press to store media - Spravovat štítky + Instance GNU + V odpovědích přeposílat tagy + K uložení média dlouze stlačte + Spravovat tagy Zobrazované jméno Emoji Text @@ -419,81 +415,82 @@ Štětec Zahodit Ukladáno… - Image Saved Successfully! + Obrázek byl úspěšně uložen! Nepodařilo se uložit obrázek Přidat položku ankety Ztišit konverzaci - Unmute conversation - The conversation is no longer muted! - The conversation is muted + Zrušit umlčení konverzace + Konverzace už není umlčená! + Konverzace je umlčená Základní Regionální Umění Aktivismus - Hrání + Hraní Technologie Furry Jídlo - Logo of the instance + Logo instance Připojte se k Mastodonu Choose an instance by picking up a category, then tap on a check button. - %1$s users - Confirm password - I agree to %1$s and %2$s + %1$s uživatelů + Potvrdit heslo + Souhlasím s %1$s a %2$s pravidla serveru podmínky užití Registrovat se - This instance works with invitations. Your account will need to be manually approved by an administrator before being usable. - Passwords don\'t match! - The email doesn\'t seem to be valid! - You will be sent a confirmation e-mail + Tato instance funguje na pozvánky. Aby se dal váš účet používat, musí ho ručně schválit administrátor. + Hesla nesouhlasí! + E-mail se zdá být neplatný! + Poslali jsme vám potvrzovací e-mail Použijte minimálně 8 znaků Heslo musí mít minimálně 8 znaků - Username should only contain letters, numbers and underscores + Uživatelské jméno smí obsahovat jen písmena, číslice a podtržítka Účet vytvořen! Your account has been created!\n\n Think to validate your email within the 48 next hours.\n\n You can now connect your account by writing %1$s in the first field and click on Connect.\n\n Important: If your instance required validation, you will receive an email once it is validated! - Save the message in drafts? + Uložit zprávu do konceptů\? Administrace - Reports - Unresolved + Hlášení + Nevyřešeno Remote - Active - Pending + Aktivní + Čekající Disabled Suspended - Permissions + Oprávnění Disable Silence - Account + Účet Undo silence Undo disable Suspend Undo suspend - The application needs to access audio recording - Voice message + Zvuk + Hlasová zpráva During the time slot, the app will send notifications. You can reverse (ie: silent) this time slot with the right spinner. - Previews will not be cropped in timelines + Náhledy nebudou v časových osách oříznuty Automatically insert a line break after the mention to capitalize the first letter - Allow content creators to share statuses to their RSS feeds - Compose + Umožňuje tvůrcům obsahu sdílet statusy do jejich kanálů RSS + Vytváření Select - Add an instance - Enable crash reports - If enabled, a crash report will be created locally and then you will be able to share it. + Přidat instanci + Zapnout hlášení o pádech aplikace + Pokud je zapnuto, místně se vytvoří hlášení o pádu a pak ho budete moci sdílet. Fedilab přestal fungovat :( - Pošlete mi mailem údaje o chybě. Pomůžete tak při opravě :)\n\nMůžete přidat dodatečný obsah. Děkuji! - Visibility + Pošlete mi mailem údaje o chybě. Pomůžete tak při opravě :) +\n +\nMůžete přidat dodatečný obsah. Děkuji! + Viditelnost Disable custom animated emojis - Report account + Nahlásit účet - %d voter - %d voters - %d voters - %d voters + %d hlasující + %d hlasující + %d hlasujících Jediná volba @@ -508,82 +505,89 @@ 3 dny 7 dní - Your poll can\'t have duplicated options! - Clear cache when leaving - The cache (media, cached messages, data from the built-in browser) will be automatically cleared when leaving the application. - Do you want to unfollow this account? - Show confirmation dialog before unfollowing - Replace Medium links - Replace medium.com links with an open source alternative front-end focused on privacy. - Default: scribe.rip - Use a push notifications system for getting notifications in real time. - Add notes - Notes for the account - Allow to compress large photos into smaller sized photos with very less or negligible loss in quality of the image. - Allow compressing videos while maintaining their quality. - Order by - Links - Change the color of links (URLs, mentions, tags, etc.) in messages - Reblogs header + Vaše anketa má duplicitní volby! + Při opuštění vymazat cache + Cache (média, cachované zprávy, data z vestavěného prohlížeče) se při opuštění aplikace automaticky vymaže. + Chcete přestat sledovat tento účet\? + Před ukončením sledování zobrazit potvrzovací dialog + Medium + Použít alternativní frontend pro Medium + Doména frontendu pro Medium + Používat systém push notifikací pro získávání upozornění v reálném čase. + Přidat poznámky + Poznámky k účtu + Umožnit kompresi velkých fotografií na menší velikost s velmi malou až zanedbatelnou ztrátou kvality. + Umožnit kompresi videa při udržení kvality. + Řadit podle + Odkazy + Změnit ve zprávách barvu odkazů (URL, zmínek, tagů apod.) + Hlavička reblogů Change the color of display name at the top of messages Change the color of the user name at the top of messages - Change the color of the header for reblogs - Posts - Background color of posts in timelines - Reset colors + Změnit barvu hlavičky pro reblogy + Příspěvky + Barva pozadí příspěvků v časových osách + Resetovat barvy Tap here to reset all your custom colors Reset - Icons - Color of bottom icons in timelines - Logo of the instance - Edit profile + Ikony + Barva dolních ikon v časových osách + Logo instance + Upravit profil Make an action - Translation - Text color - Change the text color in messages - Use a custom theme - Theming - The theme was exported - The theme has been successfully exported in CSV - Import a theme + Překlad + Barva textu + Změnit barvu textu ve zprávách + Použít vlastní téma + Témata + Téma bylo exportováno + Téma bylo úspěšně exportováno do CSV + Importovat téma Tap here to import a theme from a previous export - Export the theme + Exportovat téma Tap here to export the current theme - An error occurred when selecting the theme file - User count - Status count - Instance count + Při výběru souboru s tématem došlo k chybě + Počet uživatelů + Počet statusů + Počet instancí End in %s - This instance is not available on https://instances.social - Display full link - Share link - Open with another app - Check redirect - This URL does not redirect - %1$s \n\nredirects to\n\n %2$s - Remove UTM parameters - The app will automatically remove UTM parameters from URLs before visiting a link. - %d people talking - Twitter accounts (via Nitter) - Twitter usernames space separated - Identity proofs - Verified identity - Verified by %1$s (%2$s) - Action disabled - Unfollow - Something went wrong, please check your download directory in settings. - Announcements - No announcements! - Add a reaction - Video cache in MB, zero means no cache. - Watermarks - Automatically add a watermark at the bottom of pictures. The text can be customized for each account. - No distributors found! - You need a distributor for receiving push notifications.\nYou will find more details at %1$s.\n\nYou can also disable push notifications in settings for ignoring that message. - Select a distributor + Tato instance není k dispozici na https://instances.social + Zobrazit úplný odkaz + Sdílet odkaz + Otevřít jinou aplikací + Zkontrolovat přesměrování + Tento URL není přesměrování + %1$s +\n +\npřesměrovává na +\n +\n %2$s + Odstranit parametry UTM + Aplikace bude před otevřením odkazu automaticky odstraňovat parametry UTM. + Hovoří %d lidí + Účty Twitteru (přes Nitter) + Uživatelská jména Twitteru oddělená mezerou + Ověření identity + Ověřená identita + Ověřil(a) %1$s (%2$s) + Akce vypnuta + Zrušit sledování + Došlo k nějaké chybě, zkontrolujte prosím nastavení adresáře pro stahování. + Oznámení + Žádná oznámení! + Přidat reakci + Video cache v MB, nula znamená žádnou cache. + Vodoznaky + Automaticky přidávat vodoznak do dolní části obrázků. Text lze pro každý účet samostatně nastavit. + Nenalezeni žádní distributoři! + Pro příjem push notifikací potřebujete distributora. +\nDalší podrobnosti najdete na %1$s. +\n +\nMůžete také ignorovat tuto zprávu tak, že push notifikace v nastavení vypnete. + Vybrat distributora Vymazat cache Víte, že to porušuje určitá pravidla - Typy oznámení k zobrazení + Typy upozornění k zobrazení Boostuje také: Jsem moderátor Naposledy aktivní @@ -592,13 +596,13 @@ Schváleno Jediný panel akcí Zpráva byla odeslána! - Typ hlasování: - Doba trvání hlasování: + Typ ankety: + Doba trvání ankety: Nejnovější Filtr Velikosti ikon Výchozí viditelnost zpráv: - Počet oznámení na jedno nahrání + Počet upozornění na jedno nahrání Doména frontendu Redditu Skrýt obsah < Je to spam @@ -609,10 +613,10 @@ „Mastodon není jediný web jako Twitter nebo Facebook, je to síť tisíců komunit provozovaných různými organizacemi a jednotlivci, kteří poskytují bezproblémové zážitky se sociálními médii.“ Oblíbené Aktualizace od lidí - Vymazat všechna oznámení - Označit všechna oznámení jako přečtená + Vymazat všechna upozornění + Označit všechna upozornění jako přečtená Zobrazit všechny kategorie - Opravdu chcete smazat všechna oznámení\? Nelze to vzít zpět. + Opravdu chcete smazat všechna upozornění\? Nelze to vzít zpět. Opravdu chcete smazat toto pole\? Je to něco jiného Která pravidla jsou porušována\? @@ -652,7 +656,7 @@ Můj účet Vymazat cache Poznámky k vydání - Vypnout oznámení + Vypnout upozornění Během tohoto časového úseku Základ tématu Původ nahlášeného účtu @@ -664,19 +668,19 @@ Nastavení byla úspěšně exportována Vlastní Nemám to rád(a) - Boostováno - Oblíbeno u + Boostoval(a) + Oblíbil(a) si Jen sledující Porušuje to pravidla serveru Doplňující komentáře Přeposlat na %1$s Výsledky hlasování - Report byl odeslán! + Hlášení bylo odesláno! Interakce Účet je objevitelný - Typ oznámení + Typ upozornění Témata od přispěvatelů - Zvuky oznámení + Zvuky upozornění Personál Moje aplikace Opravdu chcete odejít bez uložení obrázku\? @@ -709,7 +713,7 @@ Profil byl aktualizován! Název seznamu není platný! To není něco, co chcete vidět - Tento účet je z jiného serveru. Poslat mu také anonymizovanou kopii reportu\? + Tento účet je z jiného serveru. Poslat mu také anonymizovanou kopii hlášení\? Nemáte účet\? Ahoj! Zveme vás k připojení do Fediverse. Zmínky @@ -733,7 +737,7 @@ verze: %s \n %s uživatelů - %s statusů Odebrat status - Vybrat nejlepší shodu + Vyberte nejlepší shodu Zkontrolováno: %s Přidat status Nové hlášení @@ -752,9 +756,9 @@ Cachované zprávy Vybrat téma Zobrazit časové osy - Vybrat typy oznámení + Vybrat typy upozornění Sdílená zpráva byla upravena - Zprávy v cache o ostatní časové osy + Zprávy v cache pro ostatní časové osy Vynutit překlad do určitého jazyka. K resetu do výchozího nastavení vyberte první hodnotu Poslední IP Povolit @@ -832,4 +836,75 @@ Smazat klíčové slovo Přidat klíčové slovo Filtrováno: %1$s + Nastavit prodlevu před dalším načtením + Pokud je zapnuto, aplikace sbalí související upozornění + V upozorněních zobrazovat média + Budou se zobrazovat média v upozorněních na reblogy a oblíbení + Přiřazeno mně + Zrušit přiřazení + Ignorovat všechna hlášení z této domény. Nerelevantní pro pozastavení + Ignorovat všechna hlášení přicházející z této domény. Nerelevantní pro pozastavení + Obfuskovat název domény + Vyvýšené karty + Pokud je zapnuto, položky v časových osách budou mít stín a vyvýšení. + Přizpůsobit světlé téma + Nastavit vlastní barvy + Světlé – vlastní barvy + Umožňuje přizpůsobit tmavému barevnému tématu některé elementy ve zprávách. + Reblogy + Zvolte, zda má být základ tématu tmavý nebo světlý + Existují nějaké příspěvky dokládající toto hlášení\? + Oznámení · %1$s - %2$s + Pokud je zapnuto, všechny připnuté časové osy se budou zobrazovat v rozbalovací nabídce + Načíst upozornění + Vybrat logo + Týká se jen „veřejných“ odpovědí. Pokud je zapnuto, vaše odpovědi budou mít automaticky „neuvedenou“ viditelnost namísto „veřejné“ + Upozornění byla odstraněna z cache. + Vlastní varování + Hlášené statusy + Pozastavení účtu zrušeno + Účet pozastaven + Upravit seznam + Akce filtru + Poslal(a) hlášení + odeslal(a) hlášení + Načítat upozornění každých: + Tmavé – vlastní barvy + Agregovat upozornění + Deaktivace účtu zrušena + Zachovat upozornění + Blokace domény nezabrání vytváření položek účtů v databázi, ale retroaktivně a automaticky na tyto účty aplikuje určité moderační metody. + Přizpůsobit tmavé téma + Bude zobrazovat bublinové počitadlo pro nové zprávy u časových os + Skrýt filtrovaný obsah za varování zmiňující titulek filtru + Úplně skrýt filtrovaný obsah, jako kdyby neexistoval + Umožňuje nastavit vaše vlastní barvy pro témata. + Umožňuje přizpůsobit světlému barevnému tématu některé elementy ve zprávách. + Řadit seznamy + Odmítat hlášení + Částečně obfuskovat název domény v seznamu, pokud je zapnuto zveřejňování seznamu doménových omezení + Čas načítání upozornění + Pokud je zapnuto, aplikace bude mít jen jeden panel pro časové osy + %1$s upravil(a) %2$s + Účet deaktivován + Hlášení + Aktualizace + Domov a seznamy + Aplikaci se nepovedlo přidat účet do seznamu! + Registroval(a) se + Bez zájmu + Upozornit na aktualizace + Nová registrace (moderátoři) + Nové hlášení (moderátoři) + Odmítat hlášení + Komentář ohledně omezení této domény pro obecnou veřejnost, pokud je zapnuto zveřejňování seznamu doménových omezení. + Komentář ohledně omezení této domény pro interní použití moderátory. + Výběr režimu pro téma + Umožňuje omezit seznam jazyků ve výběru při vytváření zprávy. + Změnit logo aplikace na vašem zařízení + Přizpůsobuje tonalitu barevného schématu podle vaší osobní tapety. + Zprávy v cache pro domovskou časovou osu + Distributor pro push + Upravil(a) zprávu + Vyberte, kterou akci provést, pokud bude příspěvek vyhovovat filtru \ No newline at end of file From fd482317ddb24a101267495da4eb5abf6cf52ad0 Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Sat, 10 Dec 2022 00:19:28 +0100 Subject: [PATCH 03/42] Translated using Weblate (Gaelic) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 28.8% (281 of 974 strings) Translated using Weblate (Silesian) Currently translated at 62.0% (604 of 974 strings) Translated using Weblate (Russian) Currently translated at 61.9% (603 of 974 strings) Translated using Weblate (Portuguese) Currently translated at 71.3% (695 of 974 strings) Translated using Weblate (Norwegian Bokmål) Currently translated at 68.6% (669 of 974 strings) Translated using Weblate (Korean) Currently translated at 62.0% (604 of 974 strings) Translated using Weblate (Hungarian) Currently translated at 61.7% (601 of 974 strings) Co-authored-by: ButterflyOfFire Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/ Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/hu/ Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ko/ Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nb_NO/ Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/ Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/szl/ Translation: Fedilab/Strings --- app/src/main/res/values-gd/strings.xml | 2 +- app/src/main/res/values-hu/strings.xml | 8 ++++---- app/src/main/res/values-ko/strings.xml | 2 +- app/src/main/res/values-no/strings.xml | 8 ++++---- app/src/main/res/values-pt/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-szl/strings.xml | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml index 23daf82d..1f4be375 100644 --- a/app/src/main/res/values-gd/strings.xml +++ b/app/src/main/res/values-gd/strings.xml @@ -21,7 +21,7 @@ Facal-faire Brathan Co-roinn - " " + Iomraidhean Annsachdan Tha diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 20424b2d..d61207ed 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -32,10 +32,10 @@ Szöveg és ikon méret Következő Előző - Megnyitás a következővel: + Megnyitás a következővel Jóváhagyás Média - Megosztás a következővel: + Megosztás a következővel Megosztva a Fedilabon keresztül Válaszok Felhasználónév @@ -207,8 +207,8 @@ Fiók zárolása Változások mentése Előnézeti képek méretre szabása - Kezdet: - Befejezés: + Kezdet + Befejezés Beépített böngésző használata Egyéni lapok cw automatikus kibontása diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 4fa0fb93..3f8b11cd 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -208,7 +208,7 @@ 내장 브라우저 사용 커스텀 탭 CW를 자동으로 펼침 - LED 색 설정 + LED 색 설정: 파란색 청록색 diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index c7d4aee9..8e9f9cbd 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -582,19 +582,19 @@ Stopp opptak Antall kontoer per innlasting Musikk - Dette feltet må fylles ut. + Dette feltet må fylles ut! Twitter YouTube Domene for Twitter-grenseflate Bruk en alternativ grenseflate for Instagram Annet Legg til status - Er oppe. + Er oppe! Oppetid: %,.2f %% Fortsett Tilpasset Kun følgere - Er nede. + Er nede! Sjekket: %s Forstum %1$s Blokker %1$s @@ -604,7 +604,7 @@ \n %s brukere - %s statuser Bruk en alternativ grenseflate for YouTube Domene for YouTube-grenseflate - Instansen ser ikke ut til å være gyldig. + Instansen ser ikke ut til å være gyldig! Framhevet av Favorittmerket av F.eks: Sensitivt innhold diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 1838e8e8..ba8ba8bc 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -315,8 +315,8 @@ Ativar definição de momento Tem certeza de que quer bloquear %s?\n\nSeus seguidores desta instância serão removidos, e você não verá nenhum conteúdo ou notificação desta instância. Bloquear instância - Instância bloqueada! - Carregando toot remoto! + Instância bloqueada + Carregando toot remoto Instância Peertube Usar Emoji One Informação diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b4fa7896..e9e0e54a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -572,7 +572,7 @@ Отписаться Что-то пошло не так, пожалуйста, проверьте папку загрузок в настройках. Объявления - Объявлений пока нет. + Объявлений пока нет! Добавить реакцию Кэш видео в MB, ноль означает, нет кэша. Водяные знаки diff --git a/app/src/main/res/values-szl/strings.xml b/app/src/main/res/values-szl/strings.xml index a2207c43..bcbdf91d 100644 --- a/app/src/main/res/values-szl/strings.xml +++ b/app/src/main/res/values-szl/strings.xml @@ -297,7 +297,7 @@ Srogość liter we tekście ani we upozorniyniu ô zawartości niy majōm znaczynio Ôdciep zamiast kryć Filtrowane tuty zniknōm doimyntnie, nawet jak filter bydzie wymazany - Jak słowo kluczowe abo fraza sōm ino alfanumeryczne, to to bydzie użyte, jak bydzie pasować cołke słowo + Jak słowo kluczowe abo fraza sōm ino alfanumeryczne, to bydzie użyte, jak bydzie pasować cołke słowo Cołke słowo Kōnteksty filtra Jedyn abo wiyncyj kōntekstōw, kaj filter winiyn być użyty From e6a499fcc5fb7505da6c6c40659cd2a230034906 Mon Sep 17 00:00:00 2001 From: Eduardo Lima Date: Sat, 10 Dec 2022 00:19:29 +0100 Subject: [PATCH 04/42] Translated using Weblate (Portuguese) Currently translated at 71.3% (695 of 974 strings) Co-authored-by: Eduardo Lima Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/ Translation: Fedilab/Strings --- app/src/main/res/values-pt/strings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index ba8ba8bc..173da155 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -313,7 +313,9 @@ Baixar mídia Selecionar toque Ativar definição de momento - Tem certeza de que quer bloquear %s?\n\nSeus seguidores desta instância serão removidos, e você não verá nenhum conteúdo ou notificação desta instância. + Tem certeza que deseja bloquear %s\? +\n +\nVocê não verá nenhum conteúdo dessa instância em nenhuma linha do tempo pública ou em suas notificações. Seus seguidores dessa instância serão removidos. Bloquear instância Instância bloqueada Carregando toot remoto @@ -635,4 +637,5 @@ Diga-nos o que está havendo com este post Adicionar status Enviando mensagem %d/%d + Nova atualização \ No newline at end of file From 550f93b735af3ba0dec4e10d79802bbdc736ec28 Mon Sep 17 00:00:00 2001 From: Ajeje Brazorf Date: Sat, 10 Dec 2022 00:19:29 +0100 Subject: [PATCH 05/42] Translated using Weblate (Sardinian) Currently translated at 98.5% (960 of 974 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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index ec8a2d6b..4e939a05 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -532,7 +532,7 @@ Faghe un\'atzione Tradutzione Colore de su testu - Càmbia su colore de su testu in is ricuadros + Càmbia su colore de su testu in is messàgios Imprea unu tema personalizadu Temas As esportadu su tema From ebd4f9ba893387c88d120c9f509285063a5f6972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Sat, 10 Dec 2022 00:19:29 +0100 Subject: [PATCH 06/42] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (974 of 974 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 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 19d53d01..173e71ab 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -534,7 +534,7 @@ Bir eylem yap Çeviri Metin rengi - İçeriklerdeki metin rengini değiştir + Mesajlardaki metin rengini değiştir Kişisel tema kullan Tema Tema dışa aktarıldı @@ -907,4 +907,13 @@ Öntanımlı koyu tema Tema için bir mod seçin Kişisel duvar kağıdınızın renk düzeniyle ton olarak uyum sağlayın. + Yükseltilmiş kartlar + Özel renkler ayarla + Koyu - Özel renkler + Etkinleştirildiğinde, zaman çizelgelerindeki ögelerin bir gölgesi ve bir yüksekliği olacaktır. + Koyu tema için mesajlardaki bazı ögeleri özelleştirmeye izin verir. + Açık Temayı Özelleştir + Açık tema için mesajlardaki bazı ögeleri özelleştirmeye izin verir. + Koyu Temayı Özelleştir + Açık - Özel renkler \ No newline at end of file From 0f2b5db07be20f9bf06c32eefd76541f67c0bcb0 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 10 Dec 2022 00:19:30 +0100 Subject: [PATCH 07/42] Update translation files Updated by "Remove blank strings" hook in Weblate. Co-authored-by: Hosted Weblate Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ Translation: Fedilab/Strings --- app/src/main/res/values-gd/strings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml index 1f4be375..3ef98dd5 100644 --- a/app/src/main/res/values-gd/strings.xml +++ b/app/src/main/res/values-gd/strings.xml @@ -21,7 +21,6 @@ Facal-faire Brathan Co-roinn - Iomraidhean Annsachdan Tha From a8eb33f3dd8ab0bf551248db6aba287e92054658 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 10 Dec 2022 10:38:01 +0100 Subject: [PATCH 08/42] Allow to check remote conversations --- .../android/activities/ContextActivity.java | 37 ++++++++++--------- .../android/helper/CrossActionHelper.java | 5 --- .../app/fedilab/android/helper/Helper.java | 2 + .../android/ui/drawer/StatusAdapter.java | 28 +++++++------- .../main/res/layout/activity_conversation.xml | 2 + 5 files changed, 39 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java index e486e14d..0d2ae793 100644 --- a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java @@ -24,7 +24,6 @@ import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.util.Log; import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; @@ -35,14 +34,15 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; -import app.fedilab.android.client.entities.api.Account; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.StatusCache; import app.fedilab.android.databinding.ActivityConversationBinding; import app.fedilab.android.exception.DBException; -import app.fedilab.android.helper.CrossActionHelper; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; import app.fedilab.android.ui.fragment.timeline.FragmentMastodonContext; @@ -143,6 +143,8 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon MenuItem action_remote = menu.findItem(R.id.action_remote); if (remote_instance != null) { action_remote.setVisible(false); + } else { + action_remote.setVisible(firstMessage != null && !firstMessage.visibility.equalsIgnoreCase("direct") && !firstMessage.visibility.equalsIgnoreCase("private")); } return true; } @@ -184,28 +186,28 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon Toasty.info(ContextActivity.this, getString(R.string.toast_on_your_instance), Toasty.LENGTH_SHORT).show(); return true; } - Log.v(Helper.TAG, "firstMessage.uri: " + firstMessage.uri); - Log.v(Helper.TAG, "instance: " + instance); - CrossActionHelper.fetchStatusInRemoteInstance(ContextActivity.this, firstMessage.uri, instance, new CrossActionHelper.Callback() { - @Override - public void federatedStatus(Status status) { - Log.v(Helper.TAG, ">status: " + status); + Pattern pattern = Helper.statusIdInUrl; + Matcher matcher = pattern.matcher(firstMessage.uri); + String remoteId = null; + if (matcher.find()) { + remoteId = matcher.group(1); + } + if (remoteId != null) { + StatusesVM statusesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class); + statusesVM.getStatus(instance, null, remoteId).observe(ContextActivity.this, status -> { if (status != null) { Intent intentContext = new Intent(ContextActivity.this, ContextActivity.class); intentContext.putExtra(Helper.ARG_STATUS, status); - intentContext.putExtra(Helper.ARG_REMOTE_INSTANCE, true); + intentContext.putExtra(Helper.ARG_REMOTE_INSTANCE, instance); intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intentContext); } else { Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show(); } - } - - @Override - public void federatedAccount(Account account) { - Log.v(Helper.TAG, ">account: " + account); - } - }); + }); + } else { + Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show(); + } } else { Toasty.warning(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show(); } @@ -216,5 +218,6 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon @Override public void get(Status status) { firstMessage = status; + invalidateOptionsMenu(); } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java b/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java index be38d26c..c9c85dbd 100644 --- a/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/CrossActionHelper.java @@ -20,7 +20,6 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.util.Log; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; @@ -449,7 +448,6 @@ public class CrossActionHelper { new Thread(() -> { Call resultsCall = mastodonSearchService.search(null, url, null, "statuses", null, null, null, null, null, null, null); Results results = null; - Log.v(Helper.TAG, ">request: " + resultsCall.request()); if (resultsCall != null) { try { Response resultsResponse = resultsCall.execute(); @@ -461,8 +459,6 @@ public class CrossActionHelper { results.statuses = new ArrayList<>(); } } - } else { - Log.v(Helper.TAG, ">err: " + resultsResponse.errorBody().string()); } } catch (IOException e) { e.printStackTrace(); @@ -471,7 +467,6 @@ public class CrossActionHelper { Handler mainHandler = new Handler(Looper.getMainLooper()); Results finalResults = results; Runnable myRunnable = () -> { - Log.v(Helper.TAG, ">finalResults.statuses " + finalResults.statuses); if (finalResults != null && finalResults.statuses != null && finalResults.statuses.size() > 0) { callback.federatedStatus(finalResults.statuses.get(0)); } 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 8b10a874..2b1aa30a 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -343,6 +343,8 @@ public class Helper { public static final Pattern codePattern = Pattern.compile("code=([\\w-]+)"); public static final Pattern nitterIDPattern = Pattern.compile("/status/(\\d+)"); public static final Pattern emailPattern = Pattern.compile("(\\s+[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)"); + public static final Pattern statusIdInUrl = Pattern.compile("statuses/(\\w+)"); + /*public static final Pattern urlPattern = Pattern.compile( "(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,10}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))", 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 1bb6e761..9cf4478a 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 @@ -1453,25 +1453,27 @@ public class StatusAdapter extends RecyclerView.Adapter } return; } - if (context instanceof ContextActivity) { + if (context instanceof ContextActivity && !remote) { Bundle bundle = new Bundle(); bundle.putSerializable(Helper.ARG_STATUS, statusToDeal); Fragment fragment = Helper.addFragment(((AppCompatActivity) context).getSupportFragmentManager(), R.id.nav_host_fragment_content_main, new FragmentMastodonContext(), bundle, null, FragmentMastodonContext.class.getName()); ((ContextActivity) context).setCurrentFragment((FragmentMastodonContext) fragment); } else { if (remote) { - Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show(); - searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1) - .observe((LifecycleOwner) context, results -> { - if (results != null && results.statuses != null && results.statuses.size() > 0) { - Status fetchedStatus = results.statuses.get(0); - Intent intent = new Intent(context, ContextActivity.class); - intent.putExtra(Helper.ARG_STATUS, fetchedStatus); - context.startActivity(intent); - } else { - Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show(); - } - }); + if (!(context instanceof ContextActivity)) { //We are not already checking a remote conversation + Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show(); + searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1) + .observe((LifecycleOwner) context, results -> { + if (results != null && results.statuses != null && results.statuses.size() > 0) { + Status fetchedStatus = results.statuses.get(0); + Intent intent = new Intent(context, ContextActivity.class); + intent.putExtra(Helper.ARG_STATUS, fetchedStatus); + context.startActivity(intent); + } else { + Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show(); + } + }); + } } else { Intent intent = new Intent(context, ContextActivity.class); intent.putExtra(Helper.ARG_STATUS, statusToDeal); diff --git a/app/src/main/res/layout/activity_conversation.xml b/app/src/main/res/layout/activity_conversation.xml index 21bb55f4..ac77201d 100644 --- a/app/src/main/res/layout/activity_conversation.xml +++ b/app/src/main/res/layout/activity_conversation.xml @@ -50,6 +50,8 @@ From 57551a716ed0a7e63f29f17adb1ac31583c51b43 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 10 Dec 2022 10:57:28 +0100 Subject: [PATCH 09/42] Release 3.10.1 --- app/build.gradle | 4 ++-- app/src/main/assets/release_notes/notes.json | 5 +++++ .../app/fedilab/android/activities/ContextActivity.java | 8 +++++++- .../fastlane/metadata/android/en/changelogs/444.txt | 4 ++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/444.txt diff --git a/app/build.gradle b/app/build.gradle index ef78a3c7..36b33efe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 32 - versionCode 443 - versionName "3.10.0" + versionCode 444 + versionName "3.10.1" 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 0a3ee24c..f50109d6 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.10.1", + "code": "444", + "note": "Added:\n- Display all messages in threads from remote instances (when possible)\n* Only public messages for instances using the Mastodon API\n* A dedicated button is displayed at the top right when conditions are filled." + }, { "version": "3.10.0", "code": "443", diff --git a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java index 0d2ae793..5a87a62d 100644 --- a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java @@ -144,7 +144,13 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon if (remote_instance != null) { action_remote.setVisible(false); } else { - action_remote.setVisible(firstMessage != null && !firstMessage.visibility.equalsIgnoreCase("direct") && !firstMessage.visibility.equalsIgnoreCase("private")); + if (firstMessage != null && !firstMessage.visibility.equalsIgnoreCase("direct") && !firstMessage.visibility.equalsIgnoreCase("private")) { + Pattern pattern = Helper.statusIdInUrl; + Matcher matcher = pattern.matcher(firstMessage.uri); + action_remote.setVisible(matcher.find()); + } else { + action_remote.setVisible(false); + } } return true; } diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/444.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/444.txt new file mode 100644 index 00000000..2243e87e --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/444.txt @@ -0,0 +1,4 @@ +Added: +- Display all messages in threads from remote instances (when possible) +* Only public messages for instances using the Mastodon API +* A dedicated button is displayed at the top right when conditions are filled. \ No newline at end of file From c36d6f4bdd6cec4bdce3abf9dfa5f21f30c9e374 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 10 Dec 2022 17:01:31 +0100 Subject: [PATCH 10/42] Fix a display issue with notifications --- app/src/main/res/layout/drawer_status_notification.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/drawer_status_notification.xml b/app/src/main/res/layout/drawer_status_notification.xml index bb17fa7f..c7466a1a 100644 --- a/app/src/main/res/layout/drawer_status_notification.xml +++ b/app/src/main/res/layout/drawer_status_notification.xml @@ -14,8 +14,9 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + tools:visibility="visible"> - - \ No newline at end of file + \ No newline at end of file From 2ec714256136b0738f03cb40b4c8de4c96b3be54 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 10 Dec 2022 18:36:13 +0100 Subject: [PATCH 11/42] Fix a display issue with notifications --- .../app/fedilab/android/ui/drawer/NotificationAdapter.java | 6 ++---- 1 file changed, 2 insertions(+), 4 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 12911d4f..38deccd3 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 @@ -367,11 +367,9 @@ public class NotificationAdapter extends RecyclerView.Adapter 0) { - holderStatus.bindingNotification.status.mediaContainer.setVisibility(View.VISIBLE); - } else { + if (!displayMedia) { + holderStatus.bindingNotification.status.attachmentsListContainer.setVisibility(View.GONE); holderStatus.bindingNotification.status.mediaContainer.setVisibility(View.GONE); } String title = ""; From 7fc8f96eef910bf66227c7836db5cd1cdacfc1e5 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 10 Dec 2022 19:01:02 +0100 Subject: [PATCH 12/42] Fix visibility for description warning --- .../fedilab/android/ui/drawer/ComposeAdapter.java | 14 ++++++-------- .../res/drawable/ic_baseline_check_circle_24.xml | 2 +- .../main/res/drawable/ic_baseline_warning_24.xml | 4 ++-- .../main/res/layout/compose_attachment_item.xml | 10 +++++----- 4 files changed, 14 insertions(+), 16 deletions(-) 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 c4efd535..b911b523 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 @@ -1038,16 +1038,14 @@ public class ComposeAdapter extends RecyclerView.Adapter displayAttachments(holder, position, finalMediaPosition)); if (attachment.description == null || attachment.description.trim().isEmpty()) { composeAttachmentItemBinding.buttonDescription.setIconResource(R.drawable.ic_baseline_warning_24); - composeAttachmentItemBinding.buttonDescription.setStrokeColor(ThemeHelper.getNoDescriptionColorStateList(context)); - composeAttachmentItemBinding.buttonDescription.setTextColor(ContextCompat.getColor(context, R.color.no_description)); - Helper.changeDrawableColor(context, R.drawable.ic_baseline_warning_24, ContextCompat.getColor(context, R.color.no_description)); - composeAttachmentItemBinding.buttonDescription.setIconTint(ThemeHelper.getNoDescriptionColorStateList(context)); + composeAttachmentItemBinding.buttonDescription.setTextColor(ContextCompat.getColor(context, R.color.black)); + composeAttachmentItemBinding.buttonDescription.setIconTintResource(R.color.black); + composeAttachmentItemBinding.buttonDescription.setBackgroundTintList(ThemeHelper.getNoDescriptionColorStateList(context)); } else { - composeAttachmentItemBinding.buttonDescription.setIconTint(ThemeHelper.getHavingDescriptionColorStateList(context)); composeAttachmentItemBinding.buttonDescription.setIconResource(R.drawable.ic_baseline_check_circle_24); - composeAttachmentItemBinding.buttonDescription.setTextColor(ContextCompat.getColor(context, R.color.having_description)); - composeAttachmentItemBinding.buttonDescription.setStrokeColor(ThemeHelper.getHavingDescriptionColorStateList(context)); - Helper.changeDrawableColor(context, R.drawable.ic_baseline_check_circle_24, ContextCompat.getColor(context, R.color.having_description)); + composeAttachmentItemBinding.buttonDescription.setTextColor(ContextCompat.getColor(context, R.color.white)); + composeAttachmentItemBinding.buttonDescription.setIconTintResource(R.color.white); + composeAttachmentItemBinding.buttonDescription.setBackgroundTintList(ThemeHelper.getHavingDescriptionColorStateList(context)); } holder.binding.attachmentsList.addView(composeAttachmentItemBinding.getRoot()); mediaPosition++; diff --git a/app/src/main/res/drawable/ic_baseline_check_circle_24.xml b/app/src/main/res/drawable/ic_baseline_check_circle_24.xml index 8c3b7cda..5f7978c0 100644 --- a/app/src/main/res/drawable/ic_baseline_check_circle_24.xml +++ b/app/src/main/res/drawable/ic_baseline_check_circle_24.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/layout/compose_attachment_item.xml b/app/src/main/res/layout/compose_attachment_item.xml index 59815a2e..77b32b69 100644 --- a/app/src/main/res/layout/compose_attachment_item.xml +++ b/app/src/main/res/layout/compose_attachment_item.xml @@ -80,21 +80,21 @@ + app:layout_constraintTop_toBottomOf="@id/preview" /> Date: Sun, 11 Dec 2022 11:36:39 +0100 Subject: [PATCH 13/42] Fix issue #617 --- .../android/activities/ProfileActivity.java | 14 +++++++- .../endpoints/MastodonAccountsService.java | 6 ++++ .../android/client/entities/api/Account.java | 28 +++++++++++++++ .../viewmodel/mastodon/AccountsVM.java | 30 ++++++++++++++++ app/src/main/res/layout/activity_profile.xml | 35 +++++++++++++++---- 5 files changed, 105 insertions(+), 8 deletions(-) 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 5c34875e..ce355124 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -188,6 +188,16 @@ public class ProfileActivity extends BaseActivity { LocalBroadcastManager.getInstance(ProfileActivity.this).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA)); } + + private void updateViewWithNewData(Account account) { + if (account != null) { + if (account.role != null && account.role.highlighted) { + binding.accountRole.setText(account.role.name); + binding.accountRole.setVisibility(View.VISIBLE); + } + } + } + private void initializeView(Account account) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ProfileActivity.this); if (account == null) { @@ -497,7 +507,9 @@ public class ProfileActivity extends BaseActivity { }); } }); - + if (accountInstance != null) { + accountsVM.lookUpAccount(accountInstance, account.username).observe(ProfileActivity.this, this::updateViewWithNewData); + } } diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java index a2ec0d5f..398c43dc 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonAccountsService.java @@ -105,6 +105,12 @@ public interface MastodonAccountsService { @Path("id") String id ); + //Get Account + @GET("accounts/lookup") + Call lookUpAccount( + @Query("acct") String acct + ); + //Get Account statuses @GET("accounts/{id}/statuses") Call> getAccountStatuses( 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 7a2bd1f2..ae0b71ae 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 @@ -73,12 +73,40 @@ public class Account implements Serializable { public List fields; @SerializedName("suspended") public boolean suspended; + @SerializedName("limited") + public boolean limited; @SerializedName("discoverable") public boolean discoverable; + @SerializedName("group") + public boolean group; @SerializedName("mute_expires_at") public Date mute_expires_at; @SerializedName("moved") 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) { diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java index 1d640b2b..5d4e17cd 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java @@ -296,6 +296,36 @@ public class AccountsVM extends AndroidViewModel { return accountMutableLiveData; } + + /** + * @param acct The acct of the account + * @return {@link LiveData} containing an {@link Account} + */ + public LiveData lookUpAccount(@NonNull String instance, @NonNull String acct) { + accountMutableLiveData = new MutableLiveData<>(); + MastodonAccountsService mastodonAccountsService = init(instance); + new Thread(() -> { + Account account = null; + Call accountCall = mastodonAccountsService.lookUpAccount(acct); + if (accountCall != null) { + + try { + Response accountResponse = accountCall.execute(); + if (accountResponse.isSuccessful()) { + account = accountResponse.body(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + Account finalAccount = account; + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> accountMutableLiveData.setValue(finalAccount); + mainHandler.post(myRunnable); + }).start(); + return accountMutableLiveData; + } + /** * @param id The id of the account * @return {@link LiveData} containing an {@link Account} diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 523b390d..7f3b6ac4 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -142,17 +142,38 @@ app:layout_constraintTop_toBottomOf="@id/avatar_container" tools:text="@tools:sample/first_names" /> - + app:layout_constraintTop_toBottomOf="@id/account_dn"> + + + + + + + app:layout_constraintTop_toBottomOf="@+id/account_un_container"> Date: Sun, 11 Dec 2022 11:53:40 +0100 Subject: [PATCH 14/42] Fix issue #617 - Update counters --- .../android/activities/ProfileActivity.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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 ce355124..97eb3c47 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -195,6 +195,20 @@ public class ProfileActivity extends BaseActivity { binding.accountRole.setText(account.role.name); binding.accountRole.setVisibility(View.VISIBLE); } + if (binding.accountTabLayout.getTabCount() > 2) { + TabLayout.Tab statusTab = binding.accountTabLayout.getTabAt(0); + TabLayout.Tab followingTab = binding.accountTabLayout.getTabAt(1); + TabLayout.Tab followerTab = binding.accountTabLayout.getTabAt(2); + if (statusTab != null) { + statusTab.setText(getString(R.string.status_cnt, Helper.withSuffix(account.statuses_count))); + } + if (followingTab != null) { + followingTab.setText(getString(R.string.following_cnt, Helper.withSuffix(account.following_count))); + } + if (followerTab != null) { + followerTab.setText(getString(R.string.followers_cnt, Helper.withSuffix(account.followers_count))); + } + } } } @@ -507,8 +521,10 @@ public class ProfileActivity extends BaseActivity { }); } }); - if (accountInstance != null) { + if (accountInstance != null && !accountInstance.equalsIgnoreCase(MainActivity.currentInstance)) { accountsVM.lookUpAccount(accountInstance, account.username).observe(ProfileActivity.this, this::updateViewWithNewData); + } else if (accountInstance != null && accountInstance.equalsIgnoreCase(MainActivity.currentInstance)) { + updateViewWithNewData(account); } } From 6cd4fc7d789c73e4c1cca9c4e1fc1c8c7c9e8cc6 Mon Sep 17 00:00:00 2001 From: Eduardo Lima Date: Sun, 11 Dec 2022 11:37:04 +0100 Subject: [PATCH 15/42] Translated using Weblate (Portuguese) Currently translated at 71.5% (697 of 974 strings) Co-authored-by: Eduardo Lima Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/ Translation: Fedilab/Strings --- app/src/main/res/values-pt/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 173da155..2bc08d3a 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -318,7 +318,7 @@ \nVocê não verá nenhum conteúdo dessa instância em nenhuma linha do tempo pública ou em suas notificações. Seus seguidores dessa instância serão removidos. Bloquear instância Instância bloqueada - Carregando toot remoto + Obtendo status remoto Instância Peertube Usar Emoji One Informação From ea2756f0135badf30dbaeb1c8822c99127e36201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Sun, 11 Dec 2022 11:37:04 +0100 Subject: [PATCH 16/42] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (978 of 978 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 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 173e71ab..05894d58 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -916,4 +916,8 @@ Açık tema için mesajlardaki bazı ögeleri özelleştirmeye izin verir. Koyu Temayı Özelleştir Açık - Özel renkler + Uzak görüşmeyi göster + Görüşme sizin sunucunuzda başladı! + Lütfen daha sonra tekrar deneyin. + Uygulama uzak mesajı bulamadı. \ No newline at end of file From 89467ce58b0b0ce38a7cfb8e210069125b5944eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Sun, 11 Dec 2022 11:37:04 +0100 Subject: [PATCH 17/42] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 98.7% (966 of 978 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 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 73072255..163702b3 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -907,4 +907,11 @@ Distributor pro push Upravil(a) zprávu Vyberte, kterou akci provést, pokud bude příspěvek vyhovovat filtru + Umožňuje vytvořit vaše vlastní téma + Odpovědi s neuvedenou viditelností + Zobrazit vzdálenou konverzaci + Konverzace začala na vaší instanci! + Aplikace nenašla vzdálenou zprávu. + Výběr z témat vytvořených přispěvateli + Zkuste to prosím znovu. \ No newline at end of file From 7cf79d33044d5f9b9666301e594ac88bc896fc5e Mon Sep 17 00:00:00 2001 From: Ajeje Brazorf Date: Sun, 11 Dec 2022 11:37:05 +0100 Subject: [PATCH 18/42] Translated using Weblate (Sardinian) Currently translated at 99.4% (973 of 978 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 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 4e939a05..d616e1c4 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -901,4 +901,17 @@ Allìnia tonalmente cun s\'ischema de colores de s\'isfundu personale tuo. Ti permitit de cunfigurare is colores personalizados tuos pro is temas. Tema iscuru predefinidu + Personaliza su tema iscuru + Cunfigura colores personalizados + Craru - Colores personalizados + Iscuru - Colores personalizados + S\'arresonada est incumintzada in s\'istàntzia tua! + Personaliza su tema craru + Cartas elevadas + Cando est abilitadu is elementos in is lìnias de tempus ant a tènnere un\'umbra e un\'artària. + Permitit de personalizare unos cantos elementos in is messàgios pro su tema iscuru. + Ammustra s\'arresonada remota + Permitit de personalizare unos cantos elementos in is messàgios pro su tema craru. + Torra a proare prus a tardu. + S\'aplicatzione no at agatadu su messàgiu remotu. \ No newline at end of file From 4dab4f34a42693964deca396c1f298f3b6dc3a3b Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 11 Dec 2022 11:37:05 +0100 Subject: [PATCH 19/42] Translated using Weblate (Chinese (Simplified)) Currently translated at 65.3% (639 of 978 strings) Co-authored-by: Eric Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/ Translation: Fedilab/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 65ef9b63..795a5c6a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -527,7 +527,7 @@ 添加操作 翻译 文本颜色 - 更改点的文本颜色 + 更改消息中文本的颜色 使用自定义主题 主题 主题已导出 From 8310b03b617daa428af75c7432fa806b1fd888d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?jos=C3=A9=20m?= Date: Sun, 11 Dec 2022 11:37:05 +0100 Subject: [PATCH 20/42] Translated using Weblate (Galician) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (978 of 978 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 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 9fa1310b..d23d3869 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -903,4 +903,17 @@ Segue a tonalidade do fondo de pantalla para axustar o esquema de cores. Decorado claro por defecto Decorado escuro por defecto + Personalizar Decorado Claro + Permite personalizar algúns elementos nas mensaxes para o decorado claro. + Permite personalizar algúns elementos da mensaxe no decorado escuro. + Establecer cores + Claro - Cores personais + Mostrar conversa remota + Inténtao outra vez máis tarde. + A app non atopa a mensaxe remota. + Se o activas, os elementos nas cronoloxías terán unha sombra e elevación. + Personalizar Decorado Escuro + A conversa comezou na túa instancia! + Escuro - Cores personais + Tarxetas elevadas \ No newline at end of file From 34a1ae16d8f4e3e20da9937827abeb4e7a50b094 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 11 Dec 2022 17:09:57 +0100 Subject: [PATCH 21/42] Fix issue #621 - Mentions in bio does not open the correct account --- .../android/helper/SpannableHelper.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 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 9508f750..0d5b7bf3 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -53,6 +53,11 @@ import androidx.preference.PreferenceManager; import com.bumptech.glide.Glide; +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; import java.net.MalformedURLException; @@ -127,6 +132,19 @@ public class SpannableHelper { if (text == null) { return null; } + 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
"); Pattern imgPattern = Pattern.compile("]*src=\"([^\"]+)\"[^>]*>"); Matcher matcherImg = imgPattern.matcher(text); @@ -178,7 +196,7 @@ public class SpannableHelper { content.removeSpan(span); } //Make tags, mentions, groups - interaction(context, content, status, mentionList, forceMentions); + interaction(context, content, status, mentionList, forceMentions, mentionsMap); //Make all links linkify(context, content, urlDetails); linkifyURL(context, content, urlDetails); @@ -759,7 +777,7 @@ public class SpannableHelper { } } - private static void interaction(Context context, Spannable content, Status status, List mentions, boolean forceMentions) { + 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(); @@ -837,8 +855,9 @@ public class SpannableHelper { 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); @@ -861,11 +880,19 @@ public class SpannableHelper { 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, word.trim()); + b.putString(Helper.ARG_MENTION, acct != null ? acct : word.trim()); } intent.putExtras(b); From 072240edd060be540a7281a85d93eb4360ac9d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?jos=C3=A9=20m?= Date: Sun, 11 Dec 2022 17:49:41 +0100 Subject: [PATCH 22/42] Translated using Weblate (Galician) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 7.5% (4 of 53 strings) Co-authored-by: josé m Translate-URL: https://hosted.weblate.org/projects/fedilab/description/gl/ Translation: Fedilab/description --- src/fdroid/fastlane/metadata/android/gl/changelogs/390.txt | 5 +++++ src/fdroid/fastlane/metadata/android/gl/title.txt | 1 + 2 files changed, 6 insertions(+) create mode 100644 src/fdroid/fastlane/metadata/android/gl/changelogs/390.txt create mode 100644 src/fdroid/fastlane/metadata/android/gl/title.txt diff --git a/src/fdroid/fastlane/metadata/android/gl/changelogs/390.txt b/src/fdroid/fastlane/metadata/android/gl/changelogs/390.txt new file mode 100644 index 00000000..d810d33a --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/gl/changelogs/390.txt @@ -0,0 +1,5 @@ +Nova versión de Fedilab con novas funcións. +- Agora podes escribir fíos +- Ver o fío completo ao responder +- Soporte para caché +- Novo deseño diff --git a/src/fdroid/fastlane/metadata/android/gl/title.txt b/src/fdroid/fastlane/metadata/android/gl/title.txt new file mode 100644 index 00000000..e6f369e8 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/gl/title.txt @@ -0,0 +1 @@ +Fedilab From 529fbaede81444dfa20b1b61b8ad8b959682a36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Mon, 12 Dec 2022 02:51:26 +0100 Subject: [PATCH 23/42] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 98.8% (967 of 978 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 | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 163702b3..abd45690 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -914,4 +914,5 @@ Aplikace nenašla vzdálenou zprávu. Výběr z témat vytvořených přispěvateli Zkuste to prosím znovu. + Nastavte svůj max. počet znaků \ No newline at end of file From f6c0d8345bd69791d4d785d68b9bf0d4cb73a413 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 09:17:50 +0100 Subject: [PATCH 24/42] Fix issue #622 - Rollback to previous view for notifications --- app/src/main/res/layout/drawer_status_notification.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/drawer_status_notification.xml b/app/src/main/res/layout/drawer_status_notification.xml index c7466a1a..bb17fa7f 100644 --- a/app/src/main/res/layout/drawer_status_notification.xml +++ b/app/src/main/res/layout/drawer_status_notification.xml @@ -14,9 +14,8 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + app:layout_constraintTop_toBottomOf="@+id/status"> -
\ No newline at end of file + + \ No newline at end of file From 1b643bcb1d1ed0875fc9ed8b40e6f9a334c81714 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 11:57:41 +0100 Subject: [PATCH 25/42] Fix issue #615 - add reverse option for tags + Change label descriptions --- .../android/activities/HashTagActivity.java | 264 ++++++++++++------ .../endpoints/MastodonFiltersService.java | 2 +- .../timeline/FragmentMastodonTimeline.java | 1 - .../android/viewmodel/mastodon/FiltersVM.java | 20 ++ app/src/main/res/drawable/tag_follow.xml | 9 + app/src/main/res/drawable/tag_muted.xml | 9 + app/src/main/res/drawable/tag_pin.xml | 9 + app/src/main/res/drawable/tag_pin_off.xml | 9 + app/src/main/res/drawable/tag_unfollow.xml | 9 + app/src/main/res/drawable/tag_unmuted.xml | 9 + app/src/main/res/menu/menu_hashtag.xml | 10 +- app/src/main/res/values/strings.xml | 5 + 12 files changed, 262 insertions(+), 94 deletions(-) create mode 100644 app/src/main/res/drawable/tag_follow.xml create mode 100644 app/src/main/res/drawable/tag_muted.xml create mode 100644 app/src/main/res/drawable/tag_pin.xml create mode 100644 app/src/main/res/drawable/tag_pin_off.xml create mode 100644 app/src/main/res/drawable/tag_unfollow.xml create mode 100644 app/src/main/res/drawable/tag_unmuted.xml 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 d2b5d1c9..850bfac6 100644 --- a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java @@ -26,6 +26,7 @@ import android.view.MenuItem; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.ViewModelProvider; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -56,11 +57,14 @@ public class HashTagActivity extends BaseActivity { public static int position; private String tag; - private boolean pinnedTag; - private boolean followedTag; - private boolean mutedTag; + private Boolean pinnedTag; + private Boolean followedTag; + private Boolean mutedTag; private TagVM tagVM; private Filter fedilabFilter; + private Filter.KeywordsAttributes keyword; + private PinnedTimeline pinnedTimeline; + private Pinned pinned; @Override protected void onCreate(Bundle savedInstanceState) { @@ -75,9 +79,9 @@ public class HashTagActivity extends BaseActivity { } if (tag == null) finish(); - pinnedTag = false; - followedTag = false; - mutedTag = false; + pinnedTag = null; + followedTag = null; + mutedTag = null; setSupportActionBar(binding.toolbar); ActionBar actionBar = getSupportActionBar(); //Remove title @@ -100,19 +104,24 @@ public class HashTagActivity extends BaseActivity { ReorderVM reorderVM = new ViewModelProvider(HashTagActivity.this).get(ReorderVM.class); reorderVM.getAllPinned().observe(HashTagActivity.this, pinned -> { if (pinned != null) { + this.pinned = pinned; + pinnedTag = false; if (pinned.pinnedTimelines != null) { for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { if (pinnedTimeline.tagTimeline != null) { if (pinnedTimeline.tagTimeline.name.equalsIgnoreCase(tag)) { + this.pinnedTimeline = pinnedTimeline; pinnedTag = true; - invalidateOptionsMenu(); + break; } } } + invalidateOptionsMenu(); } } }); if (MainActivity.filterFetched && MainActivity.mainFilters != null) { + mutedTag = false; for (Filter filter : MainActivity.mainFilters) { if (filter.title.equalsIgnoreCase(Helper.FEDILAB_MUTED_HASHTAGS)) { fedilabFilter = filter; @@ -120,17 +129,14 @@ public class HashTagActivity extends BaseActivity { for (Filter.KeywordsAttributes keywordsAttributes : filter.keywords) { if (fetch.equalsIgnoreCase(keywordsAttributes.keyword)) { mutedTag = true; + keyword = keywordsAttributes; invalidateOptionsMenu(); break; } } - mutedTag = false; - invalidateOptionsMenu(); - break; } } - } else { - mutedTag = true; + invalidateOptionsMenu(); } Bundle bundle = new Bundle(); @@ -158,89 +164,125 @@ public class HashTagActivity extends BaseActivity { finish(); return true; } else if (item.getItemId() == R.id.action_add_timeline) { - new Thread(() -> { - try { - Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount); - boolean canBeAdded = true; - boolean update = true; - if (pinned == null) { - pinned = new Pinned(); - pinned.pinnedTimelines = new ArrayList<>(); - update = false; - } else { - for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { - if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { - if (pinnedTimeline.tagTimeline.name.compareTo(tag.trim()) == 0) { - canBeAdded = false; - } - } - } - } - if (!canBeAdded) { - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> Toasty.warning(HashTagActivity.this, getString(R.string.tags_already_stored), Toasty.LENGTH_SHORT).show(); - mainHandler.post(myRunnable); - return; - } - PinnedTimeline pinnedTimeline = new PinnedTimeline(); - pinnedTimeline.type = Timeline.TimeLineEnum.TAG; - pinnedTimeline.position = pinned.pinnedTimelines.size(); - pinnedTimeline.displayed = true; - TagTimeline tagTimeline = new TagTimeline(); - tagTimeline.name = tag.trim(); - tagTimeline.isNSFW = false; - tagTimeline.isART = false; - pinnedTimeline.tagTimeline = tagTimeline; - pinned.pinnedTimelines.add(pinnedTimeline); - if (update) { + + if (pinnedTag) { + AlertDialog.Builder unpinConfirm = new AlertDialog.Builder(HashTagActivity.this, Helper.dialogStyle()); + unpinConfirm.setMessage(getString(R.string.unpin_timeline_description)); + unpinConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + unpinConfirm.setPositiveButton(R.string.yes, (dialog, which) -> { + pinned.pinnedTimelines.remove(pinnedTimeline); + try { new Pinned(HashTagActivity.this).updatePinned(pinned); - } else { - new Pinned(HashTagActivity.this).insertPinned(pinned); + } catch (DBException e) { + e.printStackTrace(); } + pinnedTag = false; + invalidateOptionsMenu(); Bundle b = new Bundle(); b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true); Intent intentBD = new Intent(Helper.BROADCAST_DATA); intentBD.putExtras(b); LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD); - pinnedTag = true; - invalidateOptionsMenu(); - } catch (DBException e) { - e.printStackTrace(); - } - }).start(); + dialog.dismiss(); + }); + unpinConfirm.show(); + } else { + new Thread(() -> { + try { + Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount); + boolean canBeAdded = true; + boolean update = true; + if (pinned == null) { + pinned = new Pinned(); + pinned.pinnedTimelines = new ArrayList<>(); + update = false; + } else { + for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { + if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { + if (pinnedTimeline.tagTimeline.name.compareTo(tag.trim()) == 0) { + canBeAdded = false; + } + } + } + } + if (!canBeAdded) { + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> Toasty.warning(HashTagActivity.this, getString(R.string.tags_already_stored), Toasty.LENGTH_SHORT).show(); + mainHandler.post(myRunnable); + return; + } + pinnedTimeline = new PinnedTimeline(); + pinnedTimeline.type = Timeline.TimeLineEnum.TAG; + pinnedTimeline.position = pinned.pinnedTimelines.size(); + pinnedTimeline.displayed = true; + TagTimeline tagTimeline = new TagTimeline(); + tagTimeline.name = tag.trim(); + tagTimeline.isNSFW = false; + tagTimeline.isART = false; + pinnedTimeline.tagTimeline = tagTimeline; + pinned.pinnedTimelines.add(pinnedTimeline); + if (update) { + new Pinned(HashTagActivity.this).updatePinned(pinned); + } else { + new Pinned(HashTagActivity.this).insertPinned(pinned); + } + Bundle b = new Bundle(); + b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true); + Intent intentBD = new Intent(Helper.BROADCAST_DATA); + intentBD.putExtras(b); + LocalBroadcastManager.getInstance(HashTagActivity.this).sendBroadcast(intentBD); + pinnedTag = true; + invalidateOptionsMenu(); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); + } } else if (item.getItemId() == R.id.action_follow_tag) { - tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { - if (returnedTag != null) { - followedTag = returnedTag.following; - invalidateOptionsMenu(); - } - }); + if (!followedTag) { + tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + if (returnedTag != null) { + followedTag = returnedTag.following; + invalidateOptionsMenu(); + } + }); + } else { + tagVM.unfollow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + if (returnedTag != null) { + followedTag = returnedTag.following; + invalidateOptionsMenu(); + } + }); + } } else if (item.getItemId() == R.id.action_mute) { - if (MainActivity.mainFilters == null || fedilabFilter == null) { - MainActivity.mainFilters = new ArrayList<>(); - 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(HashTagActivity.this).get(FiltersVM.class); - filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) - .observe(HashTagActivity.this, filter -> { - if (filter != null) { - MainActivity.mainFilters.add(filter); - mutedTag = false; - fedilabFilter = filter; - muteTags(); - invalidateOptionsMenu(); - } - }); + if (!mutedTag) { + if (MainActivity.mainFilters == null || fedilabFilter == null) { + MainActivity.mainFilters = new ArrayList<>(); + 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"); + FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); + filtersVM.addFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) + .observe(HashTagActivity.this, filter -> { + if (filter != null) { + MainActivity.mainFilters.add(filter); + mutedTag = false; + fedilabFilter = filter; + muteTags(); + invalidateOptionsMenu(); + } + }); + } else { + muteTags(); + } } else { - muteTags(); + unmuteTags(); } } @@ -249,6 +291,24 @@ public class HashTagActivity extends BaseActivity { } + private void unmuteTags() { + String search = tag.startsWith("#") ? tag : "#" + tag; + for (Filter.KeywordsAttributes keywordsAttributes : fedilabFilter.keywords) { + if (search.equalsIgnoreCase(keywordsAttributes.keyword)) { + keyword = keywordsAttributes; + break; + } + } + if (keyword != null && keyword.id != null) { + FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); + filtersVM.removeKeyword(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, keyword.id); + fedilabFilter.keywords.remove(keyword); + mutedTag = false; + invalidateOptionsMenu(); + } + } + + private void muteTags() { Filter.FilterParams filterParams = new Filter.FilterParams(); filterParams.id = fedilabFilter.id; @@ -261,6 +321,7 @@ public class HashTagActivity extends BaseActivity { FiltersVM filtersVM = new ViewModelProvider(HashTagActivity.this).get(FiltersVM.class); filtersVM.editFilter(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, filterParams) .observe(HashTagActivity.this, filter -> { + fedilabFilter = filter; mutedTag = true; invalidateOptionsMenu(); }); @@ -272,13 +333,42 @@ public class HashTagActivity extends BaseActivity { MenuItem pin = menu.findItem(R.id.action_add_timeline); MenuItem follow = menu.findItem(R.id.action_follow_tag); MenuItem mute = menu.findItem(R.id.action_mute); - if (pinnedTag && pin != null) { + if (pinnedTag != null) { + pin.setVisible(true); + if (pinnedTag) { + pin.setIcon(R.drawable.tag_pin_off); + pin.setTitle(getString(R.string.unpin_tag)); + } else { + pin.setTitle(getString(R.string.unpin_tag)); + pin.setIcon(R.drawable.tag_pin); + } + } else { pin.setVisible(false); } - if (followedTag && follow != null) { + if (followedTag != null) { + follow.setVisible(true); + if (followedTag) { + follow.setTitle(getString(R.string.unfollow_tag)); + follow.setIcon(R.drawable.tag_unfollow); + } else { + follow.setTitle(getString(R.string.follow_tag)); + follow.setIcon(R.drawable.tag_follow); + } + } else { follow.setVisible(false); } - mute.setVisible(!mutedTag); + if (mutedTag != null) { + mute.setVisible(true); + if (mutedTag) { + mute.setTitle(getString(R.string.unmute_tag_action)); + mute.setIcon(R.drawable.tag_unmuted); + } else { + mute.setTitle(getString(R.string.mute_tag_action)); + mute.setIcon(R.drawable.tag_muted); + } + } else { + mute.setVisible(false); + } return super.onCreateOptionsMenu(menu); } diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java index 88216303..8a438bbc 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonFiltersService.java @@ -96,7 +96,7 @@ public interface MastodonFiltersService { ); //Remove a keyword for a filter - @DELETE("filter_keywords/{id}") + @DELETE("filters/keywords/{id}") Call removeKeywordFilter( @Header("Authorization") String token, @Path("id") String 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 23651375..a4b57d8a 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 @@ -361,7 +361,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (timelineType != null) { slug = timelineType != Timeline.TimeLineEnum.ART ? timelineType.getValue() + (ident != null ? "|" + ident : "") : Timeline.TimeLineEnum.TAG.getValue() + (ident != null ? "|" + ident : ""); } - LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(receive_action, new IntentFilter(Helper.RECEIVE_STATUS_ACTION)); binding = FragmentPaginationBinding.inflate(inflater, container, false); return binding.getRoot(); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java index b85f587a..ca73a5e8 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/FiltersVM.java @@ -212,4 +212,24 @@ public class FiltersVM extends AndroidViewModel { }).start(); } + + /** + * Remove a filter + * + * @param id ID of the filter + */ + public void removeKeyword(@NonNull String instance, String token, @NonNull String id) { + MastodonFiltersService mastodonAccountsService = initV2(instance); + new Thread(() -> { + Call removeFilterCall = mastodonAccountsService.removeKeywordFilter(token, id); + if (removeFilterCall != null) { + try { + removeFilterCall.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + } diff --git a/app/src/main/res/drawable/tag_follow.xml b/app/src/main/res/drawable/tag_follow.xml new file mode 100644 index 00000000..247fb35c --- /dev/null +++ b/app/src/main/res/drawable/tag_follow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_muted.xml b/app/src/main/res/drawable/tag_muted.xml new file mode 100644 index 00000000..4000c43f --- /dev/null +++ b/app/src/main/res/drawable/tag_muted.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_pin.xml b/app/src/main/res/drawable/tag_pin.xml new file mode 100644 index 00000000..07091cb1 --- /dev/null +++ b/app/src/main/res/drawable/tag_pin.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_pin_off.xml b/app/src/main/res/drawable/tag_pin_off.xml new file mode 100644 index 00000000..95d54cf5 --- /dev/null +++ b/app/src/main/res/drawable/tag_pin_off.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_unfollow.xml b/app/src/main/res/drawable/tag_unfollow.xml new file mode 100644 index 00000000..35f5cb4a --- /dev/null +++ b/app/src/main/res/drawable/tag_unfollow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tag_unmuted.xml b/app/src/main/res/drawable/tag_unmuted.xml new file mode 100644 index 00000000..4fc63b7a --- /dev/null +++ b/app/src/main/res/drawable/tag_unmuted.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/menu_hashtag.xml b/app/src/main/res/menu/menu_hashtag.xml index f35647d2..610310c3 100644 --- a/app/src/main/res/menu/menu_hashtag.xml +++ b/app/src/main/res/menu/menu_hashtag.xml @@ -3,17 +3,17 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> \ 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 4dadf67f..de2d5e37 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2052,4 +2052,9 @@ Please, try again later. The conversation started on your instance! The app didn\'t find the remote message. + Mute tag + Unmute tag + Pin tag + Unpin tag + Unfollow tag \ No newline at end of file From 5a0eff4ae838660ab853290b9b0c10973ffc365e Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 12:18:19 +0100 Subject: [PATCH 26/42] Fix issue #623 - Allow to display the translate button at the bottom. --- .../android/ui/drawer/StatusAdapter.java | 91 ++++++++++++------- app/src/main/res/layout/drawer_status.xml | 22 ++++- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/pref_timelines.xml | 7 ++ 4 files changed, 85 insertions(+), 37 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 9cf4478a..446dce13 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 @@ -395,6 +395,7 @@ public class StatusAdapter extends RecyclerView.Adapter 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 displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK), true); + boolean displayTranslate = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_TRANSLATE), false); boolean displayCounters = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COUNTER_FAV_BOOST), false); String loadMediaType = sharedpreferences.getString(context.getString(R.string.SET_LOAD_MEDIA_TYPE), "ALWAYS"); @@ -628,6 +629,11 @@ public class StatusAdapter extends RecyclerView.Adapter } else { holder.binding.actionButtonBookmark.setVisibility(View.GONE); } + if (displayTranslate) { + holder.binding.actionButtonTranslate.setVisibility(View.VISIBLE); + } else { + holder.binding.actionButtonTranslate.setVisibility(View.GONE); + } //--- ACTIONS --- holder.binding.actionButtonBookmark.setChecked(statusToDeal.bookmarked); //---> BOOKMARK/UNBOOKMARK @@ -635,6 +641,9 @@ public class StatusAdapter extends RecyclerView.Adapter CrossActionHelper.doCrossAction(context, CrossActionHelper.TypeOfCrossAction.BOOKMARK_ACTION, null, statusToDeal); return true; }); + holder.binding.actionButtonTranslate.setOnClickListener(v -> { + translate(context, statusToDeal, holder, adapter); + }); holder.binding.actionButtonBookmark.setOnClickListener(v -> { if (remote) { Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show(); @@ -887,6 +896,11 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.actionButtonReply.getLayoutParams().width = (int) (normalSize * scaleIcon); holder.binding.actionButtonReply.getLayoutParams().height = (int) (normalSize * scaleIcon); holder.binding.actionButtonReply.requestLayout(); + + holder.binding.actionButtonTranslate.getLayoutParams().width = (int) (normalSize * scaleIcon); + holder.binding.actionButtonTranslate.getLayoutParams().height = (int) (normalSize * scaleIcon); + holder.binding.actionButtonTranslate.requestLayout(); + holder.binding.actionButtonBoost.setImageSize((int) (normalSize * scaleIcon)); holder.binding.actionButtonFavorite.setImageSize((int) (normalSize * scaleIcon)); holder.binding.actionButtonBookmark.setImageSize((int) (normalSize * scaleIcon)); @@ -1676,41 +1690,7 @@ public class StatusAdapter extends RecyclerView.Adapter })); builderInner.show(); } else if (itemId == R.id.action_translate) { - MyTransL.translatorEngine et = MyTransL.translatorEngine.LIBRETRANSLATE; - final MyTransL myTransL = MyTransL.getInstance(et); - myTransL.setObfuscation(true); - Params params = new Params(); - params.setSplit_sentences(false); - params.setFormat(Params.fType.TEXT); - params.setSource_lang("auto"); - myTransL.setLibretranslateDomain("translate.fedilab.app"); - String statusToTranslate; - String translate = sharedpreferences.getString(context.getString(R.string.SET_LIVE_TRANSLATE), MyTransL.getLocale()); - if (translate != null && translate.equalsIgnoreCase("default")) { - translate = MyTransL.getLocale(); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - statusToTranslate = Html.fromHtml(statusToDeal.content, Html.FROM_HTML_MODE_LEGACY).toString(); - else - statusToTranslate = Html.fromHtml(statusToDeal.content).toString(); - myTransL.translate(statusToTranslate, translate, params, new Results() { - @Override - public void onSuccess(Translate translate) { - if (translate.getTranslatedContent() != null) { - statusToDeal.translationShown = true; - statusToDeal.translationContent = translate.getTranslatedContent(); - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - } else { - Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show(); - } - } - - @Override - public void onFail(HttpsConnectionException httpsConnectionException) { - - } - }); + translate(context, statusToDeal, holder, adapter); return true; } else if (itemId == R.id.action_report) { Intent intent = new Intent(context, ReportActivity.class); @@ -1918,6 +1898,46 @@ public class StatusAdapter extends RecyclerView.Adapter } + private static void translate(Context context, Status statusToDeal, + StatusViewHolder holder, + RecyclerView.Adapter adapter) { + MyTransL.translatorEngine et = MyTransL.translatorEngine.LIBRETRANSLATE; + final MyTransL myTransL = MyTransL.getInstance(et); + myTransL.setObfuscation(true); + Params params = new Params(); + params.setSplit_sentences(false); + params.setFormat(Params.fType.TEXT); + params.setSource_lang("auto"); + myTransL.setLibretranslateDomain("translate.fedilab.app"); + String statusToTranslate; + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + String translate = sharedpreferences.getString(context.getString(R.string.SET_LIVE_TRANSLATE), MyTransL.getLocale()); + if (translate != null && translate.equalsIgnoreCase("default")) { + translate = MyTransL.getLocale(); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + statusToTranslate = Html.fromHtml(statusToDeal.content, Html.FROM_HTML_MODE_LEGACY).toString(); + else + statusToTranslate = Html.fromHtml(statusToDeal.content).toString(); + myTransL.translate(statusToTranslate, translate, params, new Results() { + @Override + public void onSuccess(Translate translate) { + if (translate.getTranslatedContent() != null) { + statusToDeal.translationShown = true; + statusToDeal.translationContent = translate.getTranslatedContent(); + adapter.notifyItemChanged(holder.getBindingAdapterPosition()); + } else { + Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show(); + } + } + + @Override + public void onFail(HttpsConnectionException httpsConnectionException) { + + } + }); + } private static void loadAndAddAttachment(Context context, LayoutMediaBinding layoutMediaBinding, StatusViewHolder holder, @@ -2207,6 +2227,7 @@ public class StatusAdapter extends RecyclerView.Adapter Helper.changeDrawableColor(context, R.drawable.ic_person, theme_icons_color); Helper.changeDrawableColor(context, R.drawable.ic_bot, theme_icons_color); Helper.changeDrawableColor(context, R.drawable.ic_round_reply_24, theme_icons_color); + Helper.changeDrawableColor(context, holder.binding.actionButtonTranslate, theme_icons_color); holder.binding.actionButtonFavorite.setInActiveImageTintColor(theme_icons_color); holder.binding.actionButtonBookmark.setInActiveImageTintColor(theme_icons_color); holder.binding.actionButtonBoost.setInActiveImageTintColor(theme_icons_color); diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index 23a23740..9f746642 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -659,7 +659,7 @@ + + SET_FILTER_REGEX_PUBLIC SET_NOTIF_VALIDATION SET_DISPLAY_BOOKMARK + SET_DISPLAY_TRANSLATE SET_NOTIF_VALIDATION_FAV SET_DISPLAY_COUNTER_FAV_BOOST SET_INNER_MARKER @@ -1423,6 +1424,7 @@ Poll type: Poll duration: Always display bookmark button + Always display translate button Display Bottom menu Top bar menu diff --git a/app/src/main/res/xml/pref_timelines.xml b/app/src/main/res/xml/pref_timelines.xml index 04f2a8b8..4afdb7d7 100644 --- a/app/src/main/res/xml/pref_timelines.xml +++ b/app/src/main/res/xml/pref_timelines.xml @@ -42,6 +42,13 @@ app:singleLineTitle="false" app:title="@string/set_display_bookmark_indication" /> + + Date: Mon, 12 Dec 2022 14:51:34 +0100 Subject: [PATCH 27/42] Fix issue #603 - Fix status bar color --- .../app/fedilab/android/activities/BaseActivity.java | 9 +++++++++ .../android/activities/BaseAlertDialogActivity.java | 9 +++++++++ .../app/fedilab/android/activities/BaseBarActivity.java | 9 +++++++++ .../android/activities/BaseTransparentActivity.java | 9 +++++++++ 4 files changed, 36 insertions(+) diff --git a/app/src/main/java/app/fedilab/android/activities/BaseActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseActivity.java index 2f2b870f..e7ba4af8 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -81,6 +84,9 @@ public class BaseActivity extends AppCompatActivity { break; case "BLACK": setTheme(R.style.BlackAppTheme); + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); currentThemeId = R.style.BlackAppTheme; break; case "DRACULA": @@ -115,6 +121,9 @@ public class BaseActivity extends AppCompatActivity { case "BLACK": AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); setTheme(R.style.BlackAppTheme); + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); currentThemeId = R.style.BlackAppTheme; break; case "DRACULA": diff --git a/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java index 48b51a25..734121bf 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -74,6 +77,9 @@ public class BaseAlertDialogActivity extends AppCompatActivity { setTheme(R.style.SolarizedAlertDialog); break; case "BLACK": + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); setTheme(R.style.BlackAlertDialog); break; case "DRACULA": @@ -102,6 +108,9 @@ public class BaseAlertDialogActivity extends AppCompatActivity { break; case "BLACK": AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); setTheme(R.style.BlackAlertDialog); break; case "DRACULA": diff --git a/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java index e8f0111e..2776d2ec 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -73,6 +76,9 @@ public class BaseBarActivity extends AppCompatActivity { setTheme(R.style.SolarizedAppThemeBar); break; case "BLACK": + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); setTheme(R.style.BlackAppThemeBar); break; case "DRACULA": @@ -102,6 +108,9 @@ public class BaseBarActivity extends AppCompatActivity { break; case "BLACK": AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); setTheme(R.style.BlackAppThemeBar); break; case "DRACULA": diff --git a/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java index 77f2df73..0f266864 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -73,6 +76,9 @@ public class BaseTransparentActivity extends AppCompatActivity { setTheme(R.style.TransparentSolarized); break; case "BLACK": + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); setTheme(R.style.TransparentBlack); break; case "DRACULA": @@ -102,6 +108,9 @@ public class BaseTransparentActivity extends AppCompatActivity { break; case "BLACK": AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); setTheme(R.style.TransparentBlack); break; case "DRACULA": From 173043a6845f52dd4765f69dd4c8294b61b5d453 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 15:36:05 +0100 Subject: [PATCH 28/42] Fix issue #614 - background color for Android 5 --- app/src/main/res/layout/drawer_status.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index 9f746642..4cdd044a 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -598,7 +598,7 @@ Date: Mon, 12 Dec 2022 15:50:47 +0100 Subject: [PATCH 29/42] Small fix in login --- .../java/app/fedilab/android/activities/LoginActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java index d70c9339..d86c795d 100644 --- a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java @@ -58,7 +58,7 @@ public class LoginActivity extends BaseActivity { public static boolean requestedAdmin; @SuppressLint("ApplySharedPref") - public static void proceedLogin(Activity activity, Account account) { + public void proceedLogin(Activity activity, Account account) { new Thread(() -> { try { //update the database @@ -74,8 +74,8 @@ public class LoginActivity extends BaseActivity { //The user is now authenticated, it will be redirected to MainActivity Runnable myRunnable = () -> { Intent mainActivity = new Intent(activity, MainActivity.class); - activity.startActivity(mainActivity); - activity.finish(); + startActivity(mainActivity); + finish(); }; mainHandler.post(myRunnable); } catch (DBException e) { From 792b0ca77e52c80a535c28b9262bb0d8c48987c4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 16:15:58 +0100 Subject: [PATCH 30/42] Fix issue #599 - Edit messages in thread are duplicated --- .../main/java/app/fedilab/android/jobs/ComposeWorker.java | 4 +++- .../ui/fragment/timeline/FragmentMastodonContext.java | 7 +++++++ 2 files changed, 10 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 f8c7643e..46c90ca7 100644 --- a/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java +++ b/app/src/main/java/app/fedilab/android/jobs/ComposeWorker.java @@ -231,7 +231,9 @@ public class ComposeWorker extends Worker { if (statusResponse.isSuccessful()) { Status statusReply = statusResponse.body(); if (statusReply != null) { - StatusAdapter.sendAction(context, Helper.ARG_STATUS_POSTED, statusReply, null); + if (dataPost.statusEditId == null) { + StatusAdapter.sendAction(context, Helper.ARG_STATUS_POSTED, statusReply, null); + } } if (firstSendMessage == null && statusReply != null) { firstSendMessage = statusReply; 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 33dc10c8..ffa1d129 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 @@ -66,6 +66,7 @@ public class FragmentMastodonContext extends Fragment { String delete_statuses_for_user = b.getString(Helper.ARG_STATUS_ACCOUNT_ID_DELETED); Status status_to_delete = (Status) b.getSerializable(Helper.ARG_STATUS_DELETED); Status statusPosted = (Status) b.getSerializable(Helper.ARG_STATUS_POSTED); + Status status_to_update = (Status) b.getSerializable(Helper.ARG_STATUS_UPDATED); if (receivedStatus != null && statusAdapter != null) { int position = getPosition(receivedStatus); if (position >= 0) { @@ -97,6 +98,12 @@ public class FragmentMastodonContext extends Fragment { statuses.remove(position); statusAdapter.notifyItemRemoved(position); } + } else if (status_to_update != null && statusAdapter != null) { + int position = getPosition(status_to_update); + if (position >= 0) { + statuses.set(position, status_to_update); + statusAdapter.notifyItemChanged(position); + } } else if (statusPosted != null && statusAdapter != null) { if (requireActivity() instanceof ContextActivity) { int i = 0; From 2c3211347616c2e66ad0ffecdb11ae8da0bec786 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 17:30:23 +0100 Subject: [PATCH 31/42] Some fixes when resuming --- .../ui/fragment/timeline/FragmentMastodonNotification.java | 3 +++ .../ui/fragment/timeline/FragmentNotificationContainer.java | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java index 0bef27f8..50d5ccff 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java @@ -345,6 +345,9 @@ public class FragmentMastodonNotification extends Fragment implements Notificati route(null, false); } } + if (notificationList != null && notificationList.size() > 0) { + route(FragmentMastodonTimeline.DIRECTION.FETCH_NEW, true); + } } /** diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java index 9b459689..8dfb7c30 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java @@ -212,9 +212,7 @@ public class FragmentNotificationContainer extends Fragment { } }); dialogBuilder.setOnDismissListener(dialogInterface -> doAction(changes.get(), excludedCategoriesList)); - dialogBuilder.setPositiveButton(R.string.close, (dialog, id) -> { - dialog.dismiss(); - }); + dialogBuilder.setPositiveButton(R.string.close, (dialog, id) -> dialog.dismiss()); AlertDialog alertDialog = dialogBuilder.create(); alertDialog.show(); }); From bd8d3405b2dd89844aba8e137ee57c48ba1d8ae4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 18:13:06 +0100 Subject: [PATCH 32/42] Fix contact not added when composing --- .../android/activities/ComposeActivity.java | 9 ++++--- .../ui/drawer/AccountsReplyAdapter.java | 1 - .../android/ui/drawer/ComposeAdapter.java | 27 ++++++++++++++----- 3 files changed, 25 insertions(+), 12 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 c9cedf5b..f5244ea6 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -402,8 +402,8 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana return true; } - private void onRetrieveContact(PopupContactBinding binding, List accounts) { - binding.loader.setVisibility(View.GONE); + private void onRetrieveContact(PopupContactBinding popupContactBinding, List accounts) { + popupContactBinding.loader.setVisibility(View.GONE); if (accounts == null) { accounts = new ArrayList<>(); } @@ -413,8 +413,9 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana checkedValues.add(composeAdapter.getLastComposeContent().contains("@" + account.acct)); } AccountsReplyAdapter contactAdapter = new AccountsReplyAdapter(contacts, checkedValues); - binding.lvAccountsSearch.setAdapter(contactAdapter); - binding.lvAccountsSearch.setLayoutManager(new LinearLayoutManager(ComposeActivity.this)); + contactAdapter.actionDone = ComposeActivity.this; + popupContactBinding.lvAccountsSearch.setAdapter(contactAdapter); + popupContactBinding.lvAccountsSearch.setLayoutManager(new LinearLayoutManager(ComposeActivity.this)); } @Override diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AccountsReplyAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AccountsReplyAdapter.java index 2b23a0e5..c0b378bf 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/AccountsReplyAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/AccountsReplyAdapter.java @@ -34,7 +34,6 @@ public class AccountsReplyAdapter extends RecyclerView.Adapter accounts, List checked) { this.accounts = accounts; this.checked = new boolean[checked.size()]; 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 b911b523..b9fa08c5 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 @@ -142,6 +142,7 @@ public class ComposeAdapter extends RecyclerView.Adapter 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; @@ -298,6 +299,7 @@ public class ComposeAdapter extends RecyclerView.Adapter //Used to write contact when composing public void updateContent(boolean checked, String acct) { - if (checked) { - if (!statusList.get(statusList.size() - 1).text.contains(acct)) - statusList.get(statusList.size() - 1).text = String.format("%s %s", acct, statusList.get(statusList.size() - 1).text); - } else { - statusList.get(statusList.size() - 1).text = statusList.get(statusList.size() - 1).text.replaceAll("\\s*" + acct, ""); + if (currentCursorPosition < statusList.size()) { + if (checked) { + if (statusList.get(currentCursorPosition).text == null) { + statusList.get(currentCursorPosition).text = ""; + } + if (!statusList.get(currentCursorPosition).text.contains(acct)) { + statusList.get(currentCursorPosition).text = String.format("@%s %s", acct, statusList.get(currentCursorPosition).text); + } + } else { + statusList.get(currentCursorPosition).text = statusList.get(currentCursorPosition).text.replaceAll("\\b@" + acct, ""); + } + notifyItemChanged(currentCursorPosition); } - notifyItemChanged(statusList.size() - 1); } //Put cursor to the end after changing contacts @@ -1316,6 +1324,11 @@ public class ComposeAdapter extends RecyclerView.Adapter { + if (focused) { + currentCursorPosition = position; + } + }); if (statusDraft.cursorPosition <= holder.binding.content.length()) { holder.binding.content.setSelection(statusDraft.cursorPosition); } From c59b1e6f3fcf2ce486d678bfc35326e7efdd9299 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 18:19:27 +0100 Subject: [PATCH 33/42] Fix tag colors --- .../main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java | 2 +- app/src/main/res/drawable/tag_follow.xml | 2 +- app/src/main/res/drawable/tag_muted.xml | 2 +- app/src/main/res/drawable/tag_pin.xml | 2 +- app/src/main/res/drawable/tag_pin_off.xml | 2 +- app/src/main/res/drawable/tag_unfollow.xml | 2 +- app/src/main/res/drawable/tag_unmuted.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) 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 b9fa08c5..aff2ad16 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 @@ -869,7 +869,7 @@ public class ComposeAdapter extends RecyclerView.Adapter diff --git a/app/src/main/res/drawable/tag_muted.xml b/app/src/main/res/drawable/tag_muted.xml index 4000c43f..93125f55 100644 --- a/app/src/main/res/drawable/tag_muted.xml +++ b/app/src/main/res/drawable/tag_muted.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/tag_pin.xml b/app/src/main/res/drawable/tag_pin.xml index 07091cb1..4d3bb51d 100644 --- a/app/src/main/res/drawable/tag_pin.xml +++ b/app/src/main/res/drawable/tag_pin.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/tag_pin_off.xml b/app/src/main/res/drawable/tag_pin_off.xml index 95d54cf5..d8223d50 100644 --- a/app/src/main/res/drawable/tag_pin_off.xml +++ b/app/src/main/res/drawable/tag_pin_off.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/tag_unfollow.xml b/app/src/main/res/drawable/tag_unfollow.xml index 35f5cb4a..06b2a0e8 100644 --- a/app/src/main/res/drawable/tag_unfollow.xml +++ b/app/src/main/res/drawable/tag_unfollow.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/tag_unmuted.xml b/app/src/main/res/drawable/tag_unmuted.xml index 4fc63b7a..6f15b551 100644 --- a/app/src/main/res/drawable/tag_unmuted.xml +++ b/app/src/main/res/drawable/tag_unmuted.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> From 6fc8275aee921c966596778152c5ac962bc95998 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 18:29:49 +0100 Subject: [PATCH 34/42] Automatically attach tag to message when composing from a tag timeline --- .../android/activities/HashTagActivity.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) 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 850bfac6..7bf49af5 100644 --- a/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/HashTagActivity.java @@ -57,6 +57,7 @@ public class HashTagActivity extends BaseActivity { public static int position; private String tag; + private String stripTag; private Boolean pinnedTag; private Boolean followedTag; private Boolean mutedTag; @@ -82,6 +83,7 @@ public class HashTagActivity extends BaseActivity { pinnedTag = null; followedTag = null; mutedTag = null; + stripTag = tag.replaceAll("#", ""); setSupportActionBar(binding.toolbar); ActionBar actionBar = getSupportActionBar(); //Remove title @@ -95,7 +97,7 @@ public class HashTagActivity extends BaseActivity { } tagVM = new ViewModelProvider(HashTagActivity.this).get(TagVM.class); - tagVM.getTag(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + tagVM.getTag(MainActivity.currentInstance, MainActivity.currentToken, stripTag).observe(this, returnedTag -> { if (returnedTag != null) { followedTag = returnedTag.following; invalidateOptionsMenu(); @@ -109,7 +111,7 @@ public class HashTagActivity extends BaseActivity { if (pinned.pinnedTimelines != null) { for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { if (pinnedTimeline.tagTimeline != null) { - if (pinnedTimeline.tagTimeline.name.equalsIgnoreCase(tag)) { + if (pinnedTimeline.tagTimeline.name.equalsIgnoreCase(stripTag)) { this.pinnedTimeline = pinnedTimeline; pinnedTag = true; break; @@ -147,12 +149,12 @@ public class HashTagActivity extends BaseActivity { Intent intentToot = new Intent(HashTagActivity.this, ComposeActivity.class); StatusDraft statusDraft = new StatusDraft(); Status status = new Status(); - status.text = "#" + tag; + status.text = "#" + stripTag; List statuses = new ArrayList<>(); statuses.add(status); statusDraft.statusDraftList = statuses; Bundle _b = new Bundle(); - _b.putSerializable(Helper.ARG_TAG_TIMELINE, statusDraft); + _b.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft); intentToot.putExtras(_b); startActivity(intentToot); }); @@ -199,7 +201,7 @@ public class HashTagActivity extends BaseActivity { } else { for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) { if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { - if (pinnedTimeline.tagTimeline.name.compareTo(tag.trim()) == 0) { + if (pinnedTimeline.tagTimeline.name.compareTo(stripTag.trim()) == 0) { canBeAdded = false; } } @@ -216,7 +218,7 @@ public class HashTagActivity extends BaseActivity { pinnedTimeline.position = pinned.pinnedTimelines.size(); pinnedTimeline.displayed = true; TagTimeline tagTimeline = new TagTimeline(); - tagTimeline.name = tag.trim(); + tagTimeline.name = stripTag.trim(); tagTimeline.isNSFW = false; tagTimeline.isART = false; pinnedTimeline.tagTimeline = tagTimeline; @@ -240,14 +242,14 @@ public class HashTagActivity extends BaseActivity { } } else if (item.getItemId() == R.id.action_follow_tag) { if (!followedTag) { - tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + tagVM.follow(MainActivity.currentInstance, MainActivity.currentToken, stripTag).observe(this, returnedTag -> { if (returnedTag != null) { followedTag = returnedTag.following; invalidateOptionsMenu(); } }); } else { - tagVM.unfollow(MainActivity.currentInstance, MainActivity.currentToken, tag).observe(this, returnedTag -> { + tagVM.unfollow(MainActivity.currentInstance, MainActivity.currentToken, stripTag).observe(this, returnedTag -> { if (returnedTag != null) { followedTag = returnedTag.following; invalidateOptionsMenu(); From 5f977d042286abb3ed8614b2548f2b353801f782 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 12 Dec 2022 18:36:56 +0100 Subject: [PATCH 35/42] Release 3.10.2 --- app/build.gradle | 4 ++-- app/src/main/assets/release_notes/notes.json | 5 +++++ .../fastlane/metadata/android/en/changelogs/445.txt | 11 +++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/445.txt diff --git a/app/build.gradle b/app/build.gradle index 36b33efe..7e631fb5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 32 - versionCode 444 - versionName "3.10.1" + versionCode 445 + versionName "3.10.2" 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 f50109d6..01903334 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.10.2", + "code": "445", + "note": "Added:\n- Allow to unmute/unfollow/unpin a tag from tag timelines\n- Automatically add the tag when composing from a tag timeline\n- Add a translate button at the bottom of messages (default: disabled)\n- Add account role in profiles\n\nFixed:\n- Contact not working when composing\n- Status bar for black theme\n- Message duplicated in conversations when edited\n- Color issue on Android 5" + }, { "version": "3.10.1", "code": "444", diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/445.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/445.txt new file mode 100644 index 00000000..14930189 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/445.txt @@ -0,0 +1,11 @@ +Added: +- Allow to unmute/unfollow/unpin a tag from tag timelines +- Automatically add the tag when composing from a tag timeline +- Add a translate button at the bottom of messages (default: disabled) +- Add account role in profiles + +Fixed: +- Contact not working when composing +- Status bar for black theme +- Message duplicated in conversations when edited +- Color issue on Android 5 \ No newline at end of file From 79adda705949c7a5823891b7c90b9983d7340d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Jel=C3=ADnek?= Date: Tue, 13 Dec 2022 09:48:52 +0100 Subject: [PATCH 36/42] Translated using Weblate (Czech) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 98.6% (972 of 985 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 | 45 +++++++++++++++----------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index abd45690..d2b43093 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -150,7 +150,8 @@ Zprávy \n %1$s Sleduji \n %1$s - Sledující \n %1$s + Sledující +\n %1$s Odmítnout Žádné naplánované zprávy k zobrazení! @@ -165,7 +166,7 @@ Žádné upozornění k zobrazení vás zmínil(a) napsal(a) novou zprávu - boostnul(a) váš toot + boostnul(a) váš status si oblíbil(a) váš status vás sleduje vás chce sledovat @@ -256,9 +257,9 @@ Odstranit Seznamy - Jsi si jist/a, že chceš trvale odstranit tento seznam? + Opravdu chcete trvale smazat tento seznam\? Přidat do seznamu - Odstranit seznam + Smazat seznam Nový název seznamu Účet byl přidán do seznamu! Ještě nemáte žádný seznam! @@ -316,7 +317,7 @@ Určitě chcete zablokovat %s?\n\nJiž z této domény neuvidíte ve všech veřejných časových osách ani v oznámeních žádný obsah. Vaši sledující z této domény budou odstraněni. Zablokovat doménu Doména je blokována - Načítám vzdálený toot + Načítám vzdálený status Instance Peertube Použít Emoji One Informace @@ -400,7 +401,7 @@ Spravovat časové osy Seznam trvale smazán Sledovaná instance odstraněna - Připnuté tagy odstraněny + Připnutý tag odstraněn Vrátit zpět Hlavní časové osy mohou být pouze skryty! Vždy označovat média jako citlivá @@ -447,11 +448,13 @@ Heslo musí mít minimálně 8 znaků Uživatelské jméno smí obsahovat jen písmena, číslice a podtržítka Účet vytvořen! - Your account has been created!\n\n - Think to validate your email within the 48 next hours.\n\n - You can now connect your account by writing %1$s in the first field and click on Connect.\n\n - Important: If your instance required validation, you will receive an email once it is validated! - + Váš účet byl vytvořen! +\n +\n Nezapomeňte ověřit e-mail během příštích 48 hodin. +\n +\n Nyní se můžete připojit ke svému účtu napsáním %1$s do prvního pole a kliknutím na Připojit. +\n +\n Důležité: Pokud vaše instance vyžaduje ověření, po jeho provedení dostanete e-mailovou zprávu! Uložit zprávu do konceptů\? Administrace Hlášení @@ -459,16 +462,16 @@ Remote Aktivní Čekající - Disabled - Suspended + Vypnuto + Pozastaveno Oprávnění - Disable + Vypnout Silence Účet Undo silence - Undo disable - Suspend - Undo suspend + Zrušit vypnutí + Pozastavit + Zrušit pozastavení Zvuk Hlasová zpráva During the time slot, the app will send notifications. You can reverse (ie: silent) this time slot with the right spinner. @@ -534,7 +537,7 @@ Barva dolních ikon v časových osách Logo instance Upravit profil - Make an action + Provést akci Překlad Barva textu Změnit barvu textu ve zprávách @@ -913,6 +916,10 @@ Konverzace začala na vaší instanci! Aplikace nenašla vzdálenou zprávu. Výběr z témat vytvořených přispěvateli - Zkuste to prosím znovu. + Zkuste to prosím později znovu. Nastavte svůj max. počet znaků + Vždy zobrazovat tlačítko překladu + Připnout tag + Nesledovat tag + Odepnout tag \ No newline at end of file From c5bc6413b4f8b885b052ce9e653290ac4f9d8b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Tue, 13 Dec 2022 09:48:52 +0100 Subject: [PATCH 37/42] Translated using Weblate (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (985 of 985 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 05894d58..0c930bfa 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -920,4 +920,10 @@ Görüşme sizin sunucunuzda başladı! Lütfen daha sonra tekrar deneyin. Uygulama uzak mesajı bulamadı. + Etiketi sessize al + Etiketin sabitlemesini kaldır + Her zaman çevir düğmesini göster + Etiketin sesini aç + Etiketi sabitle + Etiketi takibi bırak \ No newline at end of file From 770eef7629ad7d17f47924600ffd9bbf06d09f24 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 13 Dec 2022 10:48:06 +0100 Subject: [PATCH 38/42] Convert to java --- .../android/activities/SettingsActivity.java | 57 ++++++ .../android/activities/SettingsActivity.kt | 56 ------ .../settings/FragmentSettingsCategories.java | 176 ++++++++++++++++++ .../settings/FragmentSettingsCategories.kt | 138 -------------- app/src/main/res/xml/pref_categories.xml | 2 + 5 files changed, 235 insertions(+), 194 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/activities/SettingsActivity.java delete mode 100644 app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt create mode 100644 app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.java delete mode 100644 app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.kt diff --git a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java new file mode 100644 index 00000000..a7eac52c --- /dev/null +++ b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.java @@ -0,0 +1,57 @@ +package app.fedilab.android.activities; +/* 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 androidx.navigation.ui.NavigationUI.setupActionBarWithNavController; + +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; +import androidx.navigation.ui.AppBarConfiguration; + +import app.fedilab.android.R; +import app.fedilab.android.databinding.ActivitySettingsBinding; + +public class SettingsActivity extends BaseBarActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + app.fedilab.android.databinding.ActivitySettingsBinding binding = ActivitySettingsBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + NavController navController = Navigation.findNavController(this, R.id.fragment_container); + AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder().build(); + setupActionBarWithNavController(this, navController, appBarConfiguration); + } + + @Override + public boolean onSupportNavigateUp() { + NavController navController = Navigation.findNavController(this, R.id.fragment_container); + return navController.navigateUp() || super.onSupportNavigateUp(); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + NavController navController = Navigation.findNavController(this, R.id.fragment_container); + if (item.getItemId() == android.R.id.home && navController.getCurrentDestination() != null && navController.getCurrentDestination().getId() == R.id.FragmentSettingsCategories) { + finish(); + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt deleted file mode 100644 index 32edbad4..00000000 --- a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt +++ /dev/null @@ -1,56 +0,0 @@ -package app.fedilab.android.activities -/* 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 android.os.Bundle -import android.view.MenuItem -import androidx.navigation.findNavController -import androidx.navigation.ui.AppBarConfiguration -import androidx.navigation.ui.navigateUp -import androidx.navigation.ui.setupActionBarWithNavController -import app.fedilab.android.R -import app.fedilab.android.databinding.ActivitySettingsBinding - -class SettingsActivity : BaseBarActivity() { - private lateinit var binding: ActivitySettingsBinding - private lateinit var appBarConfiguration: AppBarConfiguration - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - - binding = ActivitySettingsBinding.inflate(layoutInflater) - setContentView(binding.root) - val navController = findNavController(R.id.fragment_container) - appBarConfiguration = AppBarConfiguration.Builder().build() - setupActionBarWithNavController(navController, appBarConfiguration) - - } - - - override fun onSupportNavigateUp(): Boolean { - val navController = findNavController(R.id.fragment_container) - return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - val navController = findNavController(R.id.fragment_container) - if (item.itemId == android.R.id.home && navController.currentDestination?.id == R.id.FragmentSettingsCategories) { - finish() - } - return super.onOptionsItemSelected(item) - } - -} diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.java new file mode 100644 index 00000000..b8be1e3c --- /dev/null +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.java @@ -0,0 +1,176 @@ +package app.fedilab.android.ui.fragment.settings; +/* 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 android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import app.fedilab.android.R; +import app.fedilab.android.helper.SettingsStorage; +import es.dmoral.toasty.Toasty; + +public class FragmentSettingsCategories extends PreferenceFragmentCompat { + + private static final int REQUEST_CODE = 5412; + private static final int PICKUP_FILE = 452; + + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + addPreferencesFromResource(R.xml.pref_categories); + + + Preference pref_category_key_account = findPreference(getString(R.string.pref_category_key_account)); + if (pref_category_key_account != null) { + pref_category_key_account.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToAccount()); + return false; + }); + } + + Preference pref_category_key_timeline = findPreference(getString(R.string.pref_category_key_timeline)); + if (pref_category_key_timeline != null) { + pref_category_key_timeline.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToTimelines()); + return false; + }); + } + + Preference pref_category_key_notifications = findPreference(getString(R.string.pref_category_key_notifications)); + if (pref_category_key_notifications != null) { + pref_category_key_notifications.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToNotifications()); + return false; + }); + } + + Preference pref_category_key_interface = findPreference(getString(R.string.pref_category_key_interface)); + if (pref_category_key_interface != null) { + pref_category_key_interface.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToInterface()); + return false; + }); + } + + Preference pref_category_key_compose = findPreference(getString(R.string.pref_category_key_compose)); + if (pref_category_key_compose != null) { + pref_category_key_compose.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToCompose()); + return false; + }); + } + + Preference pref_category_key_languages = findPreference(getString(R.string.pref_category_key_languages)); + if (pref_category_key_languages != null) { + pref_category_key_languages.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToLanguage()); + return false; + }); + } + + Preference pref_category_key_privacy = findPreference(getString(R.string.pref_category_key_privacy)); + if (pref_category_key_privacy != null) { + pref_category_key_privacy.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToPrivacy()); + return false; + }); + } + + Preference pref_category_key_theming = findPreference(getString(R.string.pref_category_key_theming)); + if (pref_category_key_theming != null) { + pref_category_key_theming.setOnPreferenceClickListener(preference -> { + NavController navController = Navigation.findNavController(requireActivity(), R.id.fragment_container); + navController.navigate(FragmentSettingsCategoriesDirections.Companion.categoriesToTheming()); + return false; + }); + } + ActivityResultLauncher permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { + if (isGranted) { + SettingsStorage.saveSharedPreferencesToFile(requireActivity()); + } else { + ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); + } + }); + + Preference pref_export_settings = findPreference(getString(R.string.pref_export_settings)); + if (pref_export_settings != null) { + pref_export_settings.setOnPreferenceClickListener(preference -> { + permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE); + return false; + }); + } + + Preference pref_import_settings = findPreference(getString(R.string.pref_import_settings)); + if (pref_import_settings != null) { + pref_import_settings.setOnPreferenceClickListener(preference -> { + Intent openFileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + openFileIntent.addCategory(Intent.CATEGORY_OPENABLE); + openFileIntent.setType("text/plain"); + String[] mimeTypes = new String[]{"text/plain"}; + openFileIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); + startActivityForResult( + Intent.createChooser( + openFileIntent, + getString(R.string.load_settings)), PICKUP_FILE); + return false; + }); + } + } + + @SuppressWarnings("deprecation") + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + if (resultCode == Activity.RESULT_OK && requestCode == PICKUP_FILE) { + boolean result = data != null && SettingsStorage.loadSharedPreferencesFromFile(requireActivity(), data.getData()); + if (result) { + Toasty.success(requireActivity(), getString(R.string.data_import_settings_success), Toasty.LENGTH_LONG).show(); + } else { + Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); + } + } + } + + @SuppressWarnings("deprecation") + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == REQUEST_CODE) { + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + SettingsStorage.saveSharedPreferencesToFile(requireActivity()); + } else { + Toasty.error(requireActivity(), getString(R.string.permission_missing), Toasty.LENGTH_SHORT).show(); + } + } + } +} diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.kt b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.kt deleted file mode 100644 index 4be8b730..00000000 --- a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentSettingsCategories.kt +++ /dev/null @@ -1,138 +0,0 @@ -package app.fedilab.android.ui.fragment.settings -/* 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 android.Manifest -import android.app.Activity -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Bundle -import android.widget.Toast -import androidx.activity.result.contract.ActivityResultContracts -import androidx.navigation.fragment.findNavController -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import app.fedilab.android.BaseMainActivity.currentAccount -import app.fedilab.android.R -import app.fedilab.android.helper.SettingsStorage -import es.dmoral.toasty.Toasty - - -class FragmentSettingsCategories : PreferenceFragmentCompat() { - - private val REQUEST_CODE = 5412 - private val PICKUP_FILE = 452 - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.pref_categories, rootKey) - - findPreference(getString(R.string.pref_category_key_account))?.setOnPreferenceClickListener { - - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToAccount()) - - false - } - - findPreference(getString(R.string.pref_category_key_timeline))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToTimelines()) - false - } - - findPreference(getString(R.string.pref_category_key_notifications))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToNotifications()) - false - } - - findPreference(getString(R.string.pref_category_key_interface))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToInterface()) - false - } - - findPreference(getString(R.string.pref_category_key_compose))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToCompose()) - false - } - - findPreference(getString(R.string.pref_category_key_privacy))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToPrivacy()) - false - } - - findPreference(getString(R.string.pref_category_key_theming))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToTheming()) - false - } - @Suppress("DEPRECATION") val permissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestPermission() - ) { isGranted -> - if (isGranted) { - SettingsStorage.saveSharedPreferencesToFile(context) - } else { - requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_CODE) - } - } - findPreference(getString(R.string.pref_export_settings))?.setOnPreferenceClickListener { - permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) - false - } - - findPreference(getString(R.string.pref_import_settings))?.setOnPreferenceClickListener { - val openFileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT) - openFileIntent.addCategory(Intent.CATEGORY_OPENABLE) - openFileIntent.type = "text/plain" - val mimeTypes = arrayOf("text/plain") - openFileIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes) - - startActivityForResult( - Intent.createChooser( - openFileIntent, - getString(R.string.load_settings)), PICKUP_FILE) - false - } - - val adminPreference = findPreference(getString(R.string.pref_category_key_administration)) - adminPreference?.isVisible = currentAccount != null && currentAccount.admin - adminPreference?.setOnPreferenceClickListener { false } - - findPreference(getString(R.string.pref_category_key_languages))?.setOnPreferenceClickListener { - findNavController().navigate(FragmentSettingsCategoriesDirections.categoriesToLanguage()) - false - } - } - - @Deprecated("Deprecated in Java") - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (resultCode == Activity.RESULT_OK && requestCode == PICKUP_FILE) { - val result = SettingsStorage.loadSharedPreferencesFromFile(context, data?.data) - if (result) { - activity?.let { Toasty.success(it, getString(R.string.data_import_settings_success), Toasty.LENGTH_LONG).show() } - } else { - activity?.let { Toasty.error(it, getString(R.string.toast_error), Toasty.LENGTH_LONG).show() } - } - } - } - - @Deprecated("Deprecated in Java") - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - when (requestCode) { - REQUEST_CODE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - SettingsStorage.saveSharedPreferencesToFile(context) - } else { - Toast.makeText(context, getString(R.string.permission_missing), Toast.LENGTH_SHORT).show() - } - else -> {} - } - } -} diff --git a/app/src/main/res/xml/pref_categories.xml b/app/src/main/res/xml/pref_categories.xml index a7e6dfb4..3d2669c5 100644 --- a/app/src/main/res/xml/pref_categories.xml +++ b/app/src/main/res/xml/pref_categories.xml @@ -53,12 +53,14 @@ app:icon="@drawable/ic_theming" app:key="@string/pref_category_key_theming" /> + Date: Tue, 13 Dec 2022 12:04:35 +0100 Subject: [PATCH 39/42] Fix some crashes --- .../app/fedilab/android/BaseMainActivity.java | 2 +- .../android/activities/ComposeActivity.java | 8 +++++-- .../android/activities/LoginActivity.java | 23 +++++++++++-------- .../android/activities/ProfileActivity.java | 22 ++++++++++-------- .../android/ui/drawer/ComposeAdapter.java | 4 +++- .../ui/drawer/ConversationAdapter.java | 13 +++++++++-- .../android/ui/drawer/StatusAdapter.java | 4 ++-- 7 files changed, 50 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index 1f28b8be..9570e82b 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -697,7 +697,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt new ViewModelProvider(BaseMainActivity.this).get(AccountsVM.class).getConnectedAccount(currentInstance, currentToken) .observe(BaseMainActivity.this, mastodonAccount -> { //Initialize static var - if (mastodonAccount != null) { + if (mastodonAccount != null && currentAccount != null) { currentAccount.mastodon_account = mastodonAccount; displayReleaseNotesIfNeeded(BaseMainActivity.this, false); new Thread(() -> { 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 f5244ea6..1688d292 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -870,10 +870,14 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana private boolean canBeSent(StatusDraft statusDraft) { - if (statusDraft == null || statusDraft.statusDraftList == null || statusDraft.statusDraftList.isEmpty()) { + if (statusDraft == null) { return false; } - Status statusCheck = statusDraft.statusDraftList.get(0); + List statuses = statusDraft.statusDraftList; + if (statuses == null || statuses.size() == 0) { + return false; + } + Status statusCheck = statuses.get(0); if (statusCheck == null) { return false; } diff --git a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java index d86c795d..4b91601b 100644 --- a/app/src/main/java/app/fedilab/android/activities/LoginActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/LoginActivity.java @@ -111,18 +111,23 @@ public class LoginActivity extends BaseActivity { //API call to retrieve account information for the new token AccountsVM accountsVM = new ViewModelProvider(LoginActivity.this).get(AccountsVM.class); accountsVM.getConnectedAccount(currentInstanceLogin, account.token).observe(LoginActivity.this, mastodonAccount -> { - account.mastodon_account = mastodonAccount; - account.user_id = mastodonAccount.id; - //We check if user have really moderator rights - if (requestedAdmin) { - AdminVM adminVM = new ViewModelProvider(LoginActivity.this).get(AdminVM.class); - adminVM.getAccount(account.instance, account.token, account.user_id).observe(LoginActivity.this, adminAccount -> { - account.admin = adminAccount != null; + if (mastodonAccount != null) { + account.mastodon_account = mastodonAccount; + account.user_id = mastodonAccount.id; + //We check if user have really moderator rights + if (requestedAdmin) { + AdminVM adminVM = new ViewModelProvider(LoginActivity.this).get(AdminVM.class); + adminVM.getAccount(account.instance, account.token, account.user_id).observe(LoginActivity.this, adminAccount -> { + account.admin = adminAccount != null; + proceedLogin(LoginActivity.this, account); + }); + } else { proceedLogin(LoginActivity.this, account); - }); + } } else { - proceedLogin(LoginActivity.this, account); + Toasty.error(LoginActivity.this, getString(R.string.toast_token), Toast.LENGTH_LONG).show(); } + }); } else { Toasty.error(LoginActivity.this, getString(R.string.toast_token), Toast.LENGTH_LONG).show(); 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 97eb3c47..79ac5c58 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -903,16 +903,20 @@ public class ProfileActivity extends BaseActivity { if (relationship == null || !relationship.following) { accountsVM.follow(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, true, false) .observe(ProfileActivity.this, newRelationShip -> { - relationship = newRelationShip; - updateAccount(); - if (isChecked) { - timelinesVM.addAccountsList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, listsId[which], userIds).observe(ProfileActivity.this, success -> { - if (success == null || !success) { - Toasty.error(ProfileActivity.this, getString(R.string.toast_error_add_to_list), Toast.LENGTH_LONG).show(); - } - }); + if (newRelationShip != null) { + relationship = newRelationShip; + updateAccount(); + if (isChecked) { + timelinesVM.addAccountsList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, listsId[which], userIds).observe(ProfileActivity.this, success -> { + if (success == null || !success) { + Toasty.error(ProfileActivity.this, getString(R.string.toast_error_add_to_list), Toast.LENGTH_LONG).show(); + } + }); + } else { + timelinesVM.deleteAccountsList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, listsId[which], userIds); + } } else { - timelinesVM.deleteAccountsList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, listsId[which], userIds); + Toasty.error(ProfileActivity.this, getString(R.string.toast_error_add_to_list), Toast.LENGTH_LONG).show(); } }); } else { 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 aff2ad16..a4dd8a07 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 @@ -854,7 +854,9 @@ public class ComposeAdapter extends RecyclerView.Adapter 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 c98b9062..5651ca47 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 @@ -60,6 +60,7 @@ public class ConversationAdapter extends RecyclerView.Adapter conversations) { if (conversations == null) { @@ -194,7 +195,7 @@ public class ConversationAdapter extends RecyclerView.Adapter(holder.binding.spoiler), () -> notifyItemChanged(holder.getBindingAdapterPosition())), + new WeakReference<>(holder.binding.spoiler), () -> mRecyclerView.post(() -> notifyItemChanged(holder.getBindingAdapterPosition()))), TextView.BufferType.SPANNABLE); } else { holder.binding.spoiler.setVisibility(View.GONE); @@ -204,7 +205,7 @@ public class ConversationAdapter extends RecyclerView.Adapter(holder.binding.statusContent), () -> notifyItemChanged(holder.getBindingAdapterPosition())), + new WeakReference<>(holder.binding.statusContent), () -> mRecyclerView.post(() -> notifyItemChanged(holder.getBindingAdapterPosition()))), TextView.BufferType.SPANNABLE); //--- DATE --- holder.binding.lastMessageDate.setText(Helper.dateDiff(context, conversation.last_status.created_at)); @@ -224,6 +225,7 @@ public class ConversationAdapter extends RecyclerView.Adapter StatusViewHolder holder = (StatusViewHolder) viewHolder; SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); if (sharedpreferences.getBoolean(context.getString(R.string.SET_CARDVIEW), false)) { - holder.binding.cardviewContainer.setCardElevation(Helper.convertDpToPixel(5, context)); - holder.binding.dividerCard.setVisibility(View.GONE); + holder.bindingFilteredHide.cardviewContainer.setCardElevation(Helper.convertDpToPixel(5, context)); + holder.bindingFilteredHide.dividerCard.setVisibility(View.GONE); } if (status.isFetchMore && fetchMoreCallBack != null) { holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE); From 1d350f46d697b0b9ea8db43f6b361775c7e5c0dd Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 13 Dec 2022 16:08:44 +0100 Subject: [PATCH 40/42] Fix issue #550 - Quick account switch --- .../app/fedilab/android/BaseMainActivity.java | 51 ++++++++++++++++++ .../android/client/entities/app/Account.java | 17 ++++++ app/src/main/res/layout/nav_header_main.xml | 53 +++++++++++++++---- 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index 9570e82b..7e43d4d0 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -758,6 +758,57 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } }).start(); } + //Fetch recent used accounts + new Thread(() -> { + try { + List accounts = new Account(BaseMainActivity.this).getLastUsedAccounts(); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + if (accounts != null && accounts.size() > 0) { + Helper.loadPP(this, headerMainBinding.otherAccount1, accounts.get(0)); + headerMainBinding.otherAccount1.setVisibility(View.VISIBLE); + headerMainBinding.otherAccount1.setOnClickListener(v -> { + headerMenuOpen = false; + Toasty.info(BaseMainActivity.this, getString(R.string.toast_account_changed, "@" + accounts.get(0).mastodon_account.acct + "@" + accounts.get(0).instance), Toasty.LENGTH_LONG).show(); + BaseMainActivity.currentToken = accounts.get(0).token; + BaseMainActivity.currentUserID = accounts.get(0).user_id; + api = accounts.get(0).api; + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(PREF_USER_TOKEN, accounts.get(0).token); + editor.commit(); + //The user is now aut + //The user is now authenticated, it will be redirected to MainActivity + Intent mainActivity = new Intent(this, MainActivity.class); + startActivity(mainActivity); + finish(); + }); + if (accounts.size() > 1) { + Helper.loadPP(this, headerMainBinding.otherAccount2, accounts.get(1)); + headerMainBinding.otherAccount2.setVisibility(View.VISIBLE); + headerMainBinding.otherAccount2.setOnClickListener(v -> { + headerMenuOpen = false; + Toasty.info(BaseMainActivity.this, getString(R.string.toast_account_changed, "@" + accounts.get(1).mastodon_account.acct + "@" + accounts.get(1).instance), Toasty.LENGTH_LONG).show(); + BaseMainActivity.currentToken = accounts.get(1).token; + BaseMainActivity.currentUserID = accounts.get(1).user_id; + api = accounts.get(1).api; + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(PREF_USER_TOKEN, accounts.get(1).token); + editor.commit(); + //The user is now aut + //The user is now authenticated, it will be redirected to MainActivity + Intent mainActivity = new Intent(this, MainActivity.class); + startActivity(mainActivity); + finish(); + }); + } + } + }; + mainHandler.post(myRunnable); + + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); } protected abstract void rateThisApp(); diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Account.java b/app/src/main/java/app/fedilab/android/client/entities/app/Account.java index 7564cc36..090c1b3d 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Account.java @@ -318,6 +318,23 @@ public class Account extends BaseAccount implements Serializable { } } + /** + * Returns last used account + * + * @return BaseAccount {@link BaseAccount} + */ + public List getLastUsedAccounts() throws DBException { + if (db == null) { + throw new DBException("db is null. Wrong initialization."); + } + try { + Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, null, null, null, null, Sqlite.COL_UPDATED_AT + " DESC", null); + return cursorToListUser(c); + } catch (Exception e) { + return null; + } + } + /** * Remove an account from db * diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml index c9c28f1b..fc0ed464 100644 --- a/app/src/main/res/layout/nav_header_main.xml +++ b/app/src/main/res/layout/nav_header_main.xml @@ -37,15 +37,48 @@ android:paddingRight="@dimen/activity_horizontal_margin" android:paddingBottom="5dp"> - + + + + + + + + + + + Date: Tue, 13 Dec 2022 16:28:26 +0100 Subject: [PATCH 41/42] Fix issue #629 - Remove animations after refresh --- .../ui/fragment/timeline/FragmentMastodonConversation.java | 6 ++++++ .../ui/fragment/timeline/FragmentMastodonNotification.java | 5 +++++ .../ui/fragment/timeline/FragmentMastodonTimeline.java | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java index ded9e0af..2b59c69f 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java @@ -28,6 +28,7 @@ import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; import java.util.ArrayList; import java.util.List; @@ -262,6 +263,11 @@ public class FragmentMastodonConversation extends Fragment implements Conversati if (binding == null || !isAdded() || getActivity() == null) { return; } + + RecyclerView.ItemAnimator animator = binding.recyclerView.getItemAnimator(); + if (animator instanceof SimpleItemAnimator) { + ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); + } binding.loader.setVisibility(View.GONE); binding.noAction.setVisibility(View.GONE); binding.swipeContainer.setRefreshing(false); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java index 50d5ccff..dcedecff 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java @@ -32,6 +32,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; import com.google.gson.annotations.SerializedName; @@ -253,6 +254,10 @@ public class FragmentMastodonNotification extends Fragment implements Notificati if (binding == null || !isAdded() || getActivity() == null) { return; } + RecyclerView.ItemAnimator animator = binding.recyclerView.getItemAnimator(); + if (animator instanceof SimpleItemAnimator) { + ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); + } binding.loader.setVisibility(View.GONE); binding.noAction.setVisibility(View.GONE); binding.swipeContainer.setRefreshing(false); 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 a4b57d8a..1ae41045 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 @@ -39,6 +39,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; import java.util.ArrayList; import java.util.List; @@ -538,6 +539,10 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (statusReport != null) { scrollToTop(); } + RecyclerView.ItemAnimator animator = binding.recyclerView.getItemAnimator(); + if (animator instanceof SimpleItemAnimator) { + ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); + } mLayoutManager = new LinearLayoutManager(requireActivity()); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); binding.recyclerView.setLayoutManager(mLayoutManager); From 0772f47b13f6b144a76a8d0b9b3f54f78feb5bff Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 13 Dec 2022 18:01:14 +0100 Subject: [PATCH 42/42] Release 3.11.0 --- app/build.gradle | 4 +- app/src/main/assets/release_notes/notes.json | 5 ++ .../android/ui/drawer/ComposeAdapter.java | 59 ++++++++++++++--- .../android/ui/drawer/StatusAdapter.java | 66 +++++++++++-------- .../metadata/android/en/changelogs/446.txt | 18 +++++ 5 files changed, 113 insertions(+), 39 deletions(-) create mode 100644 src/fdroid/fastlane/metadata/android/en/changelogs/446.txt diff --git a/app/build.gradle b/app/build.gradle index 7e631fb5..d22d76ee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 32 - versionCode 445 - versionName "3.10.2" + versionCode 446 + versionName "3.11.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 01903334..f3818d4c 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.11.0", + "code": "446", + "note": "Added:\n- Display all messages in threads from remote instances (when possible)\n- Allow to unmute/unfollow/unpin a tag from tag timelines\n- Display most used accounts in header menu for an easy switch\n- Automatically add the tag when composing from a tag timeline\n- Add a translate button at the bottom of messages (default: disabled)\n- Add account role in profiles\n- Translate morse\n\nChanged:\n- Disable animations after a refresh\n\nFixed:\n- Contact not working when composing\n- Status bar for black theme\n- Message duplicated in conversations when edited\n- Color issue on Android 5\n- Several crashes" + }, { "version": "3.10.2", "code": "445", 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 a4dd8a07..9fdeb620 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 @@ -80,8 +80,9 @@ import java.lang.ref.WeakReference; import java.text.Normalizer; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -124,11 +125,52 @@ public class ComposeAdapter extends RecyclerView.Adapter ALPHA_TO_MORSE = new LinkedHashMap<>(); + for (int i = 0; i < ALPHA.length && i < MORSE.length; i++) { + ALPHA_TO_MORSE.put(MORSE[i], ALPHA[i]); + } + List MORSELIST = Arrays.asList(MORSE2); + MORSELIST.sort((s1, s2) -> s2.length() - s1.length()); + LinkedHashMap MORSE_TO_ALPHA = new LinkedHashMap<>(); + for (String s : MORSELIST) { + MORSE_TO_ALPHA.put(s, ALPHA_TO_MORSE.get(s)); + } + for (String morseCode : MORSELIST) { + if (MORSE_TO_ALPHA.containsKey(morseCode)) { + morseContent = morseContent.replaceAll(Pattern.quote(morseCode), MORSE_TO_ALPHA.get(morseCode)); + } + } + return morseContent; + } + private final List statusList; private final int TYPE_NORMAL = 0; private final BaseAccount account; @@ -540,7 +582,7 @@ public class ComposeAdapter extends RecyclerView.Adapter ALPHA_TO_MORSE = new HashMap<>(); + LinkedHashMap ALPHA_TO_MORSE = new LinkedHashMap<>(); for (int i = 0; i < ALPHA.length && i < MORSE.length; i++) { ALPHA_TO_MORSE.put(ALPHA[i], MORSE[i]); } @@ -552,7 +594,6 @@ public class ComposeAdapter extends RecyclerView.Adapter { @@ -592,7 +633,7 @@ public class ComposeAdapter extends RecyclerView.Adapter { if (focused) { - currentCursorPosition = position; + currentCursorPosition = holder.getLayoutPosition(); } }); if (statusDraft.cursorPosition <= holder.binding.content.length()) { 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 6e3e0d9c..41b29f4b 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 @@ -1901,42 +1901,52 @@ public class StatusAdapter extends RecyclerView.Adapter private static void translate(Context context, Status statusToDeal, StatusViewHolder holder, RecyclerView.Adapter adapter) { - MyTransL.translatorEngine et = MyTransL.translatorEngine.LIBRETRANSLATE; - final MyTransL myTransL = MyTransL.getInstance(et); - myTransL.setObfuscation(true); - Params params = new Params(); - params.setSplit_sentences(false); - params.setFormat(Params.fType.TEXT); - params.setSource_lang("auto"); - myTransL.setLibretranslateDomain("translate.fedilab.app"); String statusToTranslate; - SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); - String translate = sharedpreferences.getString(context.getString(R.string.SET_LIVE_TRANSLATE), MyTransL.getLocale()); - if (translate != null && translate.equalsIgnoreCase("default")) { - translate = MyTransL.getLocale(); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) statusToTranslate = Html.fromHtml(statusToDeal.content, Html.FROM_HTML_MODE_LEGACY).toString(); else statusToTranslate = Html.fromHtml(statusToDeal.content).toString(); - myTransL.translate(statusToTranslate, translate, params, new Results() { - @Override - public void onSuccess(Translate translate) { - if (translate.getTranslatedContent() != null) { - statusToDeal.translationShown = true; - statusToDeal.translationContent = translate.getTranslatedContent(); - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - } else { - Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show(); + + int countMorseChar = ComposeAdapter.countMorseChar(statusToTranslate); + if (countMorseChar < 4) { + MyTransL.translatorEngine et = MyTransL.translatorEngine.LIBRETRANSLATE; + final MyTransL myTransL = MyTransL.getInstance(et); + myTransL.setObfuscation(true); + Params params = new Params(); + params.setSplit_sentences(false); + params.setFormat(Params.fType.TEXT); + params.setSource_lang("auto"); + myTransL.setLibretranslateDomain("translate.fedilab.app"); + + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + String translate = sharedpreferences.getString(context.getString(R.string.SET_LIVE_TRANSLATE), MyTransL.getLocale()); + if (translate != null && translate.equalsIgnoreCase("default")) { + translate = MyTransL.getLocale(); + } + + + myTransL.translate(statusToTranslate, translate, params, new Results() { + @Override + public void onSuccess(Translate translate) { + if (translate.getTranslatedContent() != null) { + statusToDeal.translationShown = true; + statusToDeal.translationContent = translate.getTranslatedContent(); + adapter.notifyItemChanged(holder.getBindingAdapterPosition()); + } else { + Toasty.error(context, context.getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show(); + } } - } - @Override - public void onFail(HttpsConnectionException httpsConnectionException) { + @Override + public void onFail(HttpsConnectionException httpsConnectionException) { - } - }); + } + }); + } else { + statusToDeal.translationShown = true; + statusToDeal.translationContent = ComposeAdapter.morseToText(statusToTranslate); + adapter.notifyItemChanged(holder.getBindingAdapterPosition()); + } } private static void loadAndAddAttachment(Context context, LayoutMediaBinding layoutMediaBinding, diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/446.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/446.txt new file mode 100644 index 00000000..c703d706 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/446.txt @@ -0,0 +1,18 @@ +Added: +- Display all messages in threads from remote instances (when possible) +- Allow to unmute/unfollow/unpin a tag from tag timelines +- Display most used accounts in header menu for an easy switch +- Automatically add the tag when composing from a tag timeline +- Add a translate button at the bottom of messages (default: disabled) +- Add account role in profiles +- Translate morse + +Changed: +- Disable animations after a refresh + +Fixed: +- Contact not working when composing +- Status bar for black theme +- Message duplicated in conversations when edited +- Color issue on Android 5 +- Several crashes \ No newline at end of file