From 29a002e4519dc2dfc9c49d5b604ec957c92fc3a9 Mon Sep 17 00:00:00 2001 From: David Kaspar Date: Sat, 15 Jun 2024 09:51:05 +0200 Subject: [PATCH 01/45] Set redirects to false for httpclient used during nip05 --- .../amethyst/service/Nip05NostrAddressVerifier.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt index 674e8fa0f8..559c0bae92 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt @@ -64,8 +64,8 @@ class Nip05NostrAddressVerifier() { .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url(url) .build() - - HttpClientManager.getHttpClient() + // Fetchers MUST ignore any HTTP redirects given by the /.well-known/nostr.json endpoint. + HttpClientManager.getHttpClient().newBuilder().followRedirects(false).build() .newCall(request) .enqueue( object : Callback { From 475e1c6fe009dc39af79462b768a4b6bc6e281df Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Sat, 15 Jun 2024 13:47:01 +0000 Subject: [PATCH 02/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-pl-rPL/strings.xml | 378 +++++++++++++++++++-- 1 file changed, 356 insertions(+), 22 deletions(-) diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 080111c2c4..aac8f92eb8 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -17,21 +17,29 @@ Spam Liczba spamu z tego transmitera Podszywanie się - Nielegalne zachowanie + Antyspołeczne zachowanie + Inne Nieznany Ikona transmitera Autor nieznany Skopiuj tekst Kopiuj identyfikator autora Kopiuj identyfikator notatki + Roześlij + Znacznik czasowy + Znacznik czasowy: Oczekujące potwierdzenia + OTS: Oczekuje + Poproś o usunięcie Zablokuj / Zgłoś Zgłoś spam/oszustwo Zgłoś podszywanie się Zgłoś niedozwoloną zawartość + Zgłoś antyspołeczne działania Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby móc odpowiedzieć Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby zwiększyć liczbę postów Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby polubić posty + Nie ustawiono kwoty zap-a. Naciśnij i przytrzymaj, aby zmienić Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby móc wysyłać zapy Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby móc obserwować Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby móc przestać obserwować @@ -39,13 +47,17 @@ Używasz klucza publicznego, a klucze publiczne są tylko do odczytu. Zaloguj się za pomocą klucza prywatnego, aby móc pokazać słowo lub zdanie Zapy Liczba wyświetleń - Zwiększ - zwiększony + Repost + reposted edytowano edytuj #%1$s oryginalny - Nowa kwota w Satsach + Zacytuj + Sklonuj + Zaproponuj zmianę + Nowa kwota w Satach Dodaj + "odpowiadając do" " i " "na kanale " Baner profilu @@ -57,7 +69,9 @@ Filtry bezpieczeństwa Wyloguj się Pokaż Więcej + Faktura LN Zapłać + Lightning-wskazówki Notatka dla odbiorcy Dziękuję bardzo! Kwota w Satsach @@ -65,43 +79,68 @@ "Błąd analizowania podglądu dla %1$s : %2$s" "Podgląd obrazu karty dla %1$s" Nowy kanał - Nazwa kanału - Moja wspaniała Grupa - Adres URL zdjęcia + Nazwa Grupy + Nazwa Grupy + Adres Url obrazka Opis - "O nas. " + "Informacja o grupie.. " Co masz na myśli? Wyślij Zapisz Utwórz Anuluj + Nie udało się przesłać obrazu Adres transmitera Wpisy + Bajtów Błędy + Liczba błędów połączenia w tej sesji + Główny kanał + Kanał wiadomości prywatnych + Kanał Czatu Publicznego Kanał Ogólny + Przeszukaj kanał Dodaj Transmiter Nazwa użytkownika + Mój nick + G Braun + Witamy serdecznie! Nazwa użytkownika + Mój login O mnie URL awatara URL banera Adres URL strony + LN Adres + Adres URL LN (nieaktualny) Zapisz w galerii Zdjęcie zapisane w galerii Nie udało się zapisać zdjęcia Dodaj zdjęcie Wgrywanie… + Użytkownik nie ma skonfigurowanego adresu LN, aby odbierać saty "odpowiedz tutaj.. " + Kopiuje ID wpisu do schowka w celu udostępnienia w Nostr + Kopiuj ID kanału (wpisu) do schowka + Edytuje metadane kanału Dołącz + Popularne + Nowe Prośby Zablokowani użytkownicy Nowe Wpisy - Konwersacje - Uwagi + Rozmowy + Wpisy Odpowiedzi + "Obserwowani" "Zgłoszenia" Więcej opcji " Transmitery" Strona www + Lightning Adres + Kopiuje Nsec ID (hasło) do schowka w celu wykonania kopii zapasowej + Skopiuj tajny klucz do schowka + Kopiuje klucz publiczny do schowka w celu udostępnienia + Skopiuj klucz publiczny (NPub) do schowka Wyślij bezpośrednią wiadomość Edytowanie metadanych użytkowników Obserwuj @@ -123,6 +162,7 @@ Wymagane jest zaakceptowanie warunków użytkowania Hasło jest wymagane Klucz jest wymagany + Nazwa jest wymagana Zaloguj się Zarejestruj się Utwórz konto @@ -132,19 +172,30 @@ Utwórz nowe konto Wygeneruj nowy klucz Wczytywanie zawartości - Wczytywanie konta + Ładowanie konta "Błąd wczytywania odpowiedzi: " Spróbuj ponownie Brak zawartości. Odśwież + stworzył (a) + z opisem i zdjęcie zmieniono nazwę czatu na + opis dla i zdjęcie do Wyjdź - Przestań obserwować + Porzuć obserwację + Kanał utworzony + "Informacje o kanale zmienione na" Czat Publiczny + odebranych wiadomości Usuń + Automatycznie + przetłumaczono z do + Najpierw pokaż w %1$s + Zawsze tłumacz na %1$s + Nigdy nie tłumacz z %1$s Adres Nostr nigdy teraz @@ -156,22 +207,52 @@ Zgłoś nienawistną mowę Zgłoś Nagość / Pornografię inne + Oznacz wszystkie popularne jako przeczytane + Oznacz wszystkie nowe jako przeczytane Oznacz wszystkie jako przeczytane + Klucze kopii zapasowej + ## Porady dotyczące kopii zapasowej i bezpieczeństwa + \n\nTwoje konto jest zabezpieczone tajnym kluczem. Kluczem jest długa sekwencja znaków, zaczynająca się od **nsec1**. Każdy, kto ma dostęp do tego tajnego klucza może publikować i zmieniać Twoją tożsamość. + \n\n- **nie** umiejszczaj swojego tajnego klucza na żadnej stronie internetowej lub oprogramowaniu, któremu nie ufasz. + \n- Deweloperzy Ametyst **nigdy** nie będą prosić o Twój tajny klucz. + \n- **Zrób ** bezpieczną kopię zapasową swojego tajnego klucza do ewentualnego odzyskania konta. Zalecamy użycie menedżera haseł. + + Dla dodatkowego bezpieczeństwa możesz zaszyfrować swój klucz hasłem. Ten klucz zaczyna się od **ncryptsec1** i nie może być użyty bez hasła. + \n\nJeśli zgubisz hasło, nie będziesz w stanie odzyskać swojego klucza. + + Nie udało się zaszyfrować Twojego klucza prywatnego + Tajny klucz (nsec) skopiowany do schowka + Kopiuj mój tajny klucz + Zaszyfruj i skopiuj mój tajny klucz + Uwierzytelnianie nie udało się + Biometria nie uwierzytelniła właściciela tego telefonu + Biometria nie uwierzytelniła właściciela tego telefonu. Błąd: %1$s Błąd + "Utworzony przez %1$s" + "Wizerunek odznaki dla %1$s" + Otrzymałeś nową odznakę + Nagroda przyznana dla + Skopiowano tekst wpisu do schowka + Skopiowano @npub autora do schowka + Skopiowane ID wpisu (@note1) do schowka Zaznacz tekst + "<Unable to decrypt private message>\n\nZostałeś wspomniany w prywatnej/zaszyfrowanej rozmowie pomiędzy %1$s i %2$s." Dodaj nowe konto Konta Wybierz Konto Dodaj konto + Konto aktywne + Ma klucz prywatny Tylko do odczytu, brak klucza prywatnego Wstecz Wybierz + Udostępnij link przeglądarki Udostępnij ID autora ID notatki Skopiuj tekst Usuń - Przestań obserwować + Porzuć Śledź Poproś o usunięcie Amethyst poprosi o usunięcie Twojej notatki z aktualnie podłączonych transmiterów. Nie ma gwarancji, że Twoja notatka zostanie trwale usunięta z tych lub z innych transmiterów, gdzie może być przechowywana. @@ -180,15 +261,17 @@ Zablokuj Zgłoś Usuń - Nie pokazuj ponownie + Nie pokazuj więcej Spam lub oszustwa - Wulgaryzmy lub nienawistne zachowanie + Wulgaryzmy lub obelgi Złośliwe podszywanie się - Nagość lub zawartość graficzna - Nielegalne zachowanie + Nagość lub obraźliwa grafika + Antyspołeczne zachowanie Zablokowanie użytkownika ukryje jego zawartość w aplikacji. Twoje notatki są nadal widoczne publicznie, w tym dla osób, które blokujesz. Zablokowani użytkownicy są wymienieni na ekranie filtrów bezpieczeństwa. Zgłoś nadużycie + Wszystkie wysłane zgłoszenia będą publicznie dostępne. + Opcjonalnie podaj dodatkowe informacje dotyczące zgłoszenia… Dodatkowe informacje Powód Wybierz powód… @@ -203,25 +286,59 @@ Dodaj do publicznych zakładek Usuń z prywatnych zakładek Usuń z publicznych zakładek + Usługa Wallet Connect Autoryzuje Nostr Secret do płacenia zapów bez opuszczania aplikacji. Strzeż pilnie i użyj prywatnego transmitera, jeśli to możliwe + Klucz publiczny Wallet Connect + Transmiter Wallet Connect + Klucz dostępu do portfela Pokaż tajny klucz + klucz prywatny nsec / hex + Kwota zobowiązania w Satach + Wyślij Ankietę + Wymagane pola: + Odbiorcy zap + Podstawowy opis ankiety… Opcja %s + Opis opcji ankiety + Pola opcjonalne: Minimalny Zap Maksymalny Zap + Konsensus (0–100)% + Zamknij po dni + Nie można głosować + Ankieta jest zamknięta dla nowych głosów + Kwota Zap + Tylko jeden głos na użytkownika jest dozwolony dla tego typu ankiety + "Szukam wydarzenia %1$s" Dodaj wiadomość publiczną Dodaj prywatną wiadomość + Dodaj wiadomość do faktury Dziękujemy za całą twoją pracę! Utwórz i Dodaj + Autorzy ankiet nie mogą głosować we własnych ankietach. + Co to oznacza? + Ta zawartość jest taka sama od początku + Ta zawartość uległa zmianie. Autor mógł nie zobaczyć ani nie zatwierdzić zmiany Dodaj zdjęcie Dodaj wideo Dodaj dokument Dodaj do wiadomości Opis zawartości + Błękitna łódź na białej piaszczystej plaży o zachodzie słońca + Typ Zap-a + Typ Zap-a dla wszystkich opcji + Publiczny Każdy może zobaczyć transakcję i wiadomość + Prywatny Nadawca i odbiorca mogą zobaczyć się nawzajem i przeczytać wiadomość + Anonimowy + Odbiorca i użytkownicy nie wiedzą, kto wysłał płatność + Bez Zapów + Brak śladu w Nostr, tylko w Lightning Serwer Plików + LnAdres lub @Użytkownik Twoje transmitery (NIP-95) Pliki są przechowywane przez Twoje retransmitery. Nowy NIP: sprawdź, czy jest obsługiwany Tor/Orbot - Ustawienia @@ -250,6 +367,10 @@ Powiadamia Cię, gdy nadejdzie prywatna wiadomość Otrzymano Zapy Powiadamia Cię, gdy ktoś prześle ci zapy + %1$s Satów + Od %1$s + dla %1$s + Powiadom: Dołącz do rozmowy ID Użytkownika lub Grupy npub, nevent lub hex @@ -261,27 +382,62 @@ Zawsze ukrywaj wrażliwe treści Zawsze pokazuj wrażliwą zawartość Zawsze pokazuj ostrzeżenia dotyczące zawartości + Zalecenia: Filtruj spam z nieznajomych Ostrzegaj, gdy posty zostały zgłoszone przez osoby które obserwujesz + Nowy Symbol reakcji + Brak wstępnie wybranych typów reakcji dla tego użytkownika. Przytrzymaj przycisk serce, aby zmienić + Zapraiser + Dodaje docelową liczbę satów do podniesienia dla tego wpisu. W zależności od aplikacji może być pokazywany to jako pasek postępu, aby zachęcić do darowizn + Docelowa kwota w Satach + Zapraiser przy: %1$s. %2$s satach do celu Odczytaj z Transmitera Zapisz do Transmitera + Ilość w bajtach, która została wysłana do tego transmitera, w tym filtry i wydarzenia + Ilość w bajtach, która została otrzymana z tego transmitera, w tym filtry i wydarzenia Wystąpił błąd podczas próby uzyskania informacji o transmiterze z %1$s Właściciel Wersja Oprogramowanie Kontakt + Obsługiwane Nipy + Opłaty za wstęp Adres URL płatności Ograniczenia Kraje Języki Tagi Polityka publikowania + Błędy i powiadomienia z tego transmitera Długość wiadomości Subskrybcje Filtry + Długość identyfikatora subskrypcji + Minimalny prefiks + Maksymalna ilość tagów wydarzeń + Długość zawartości + Minimalny poW + Autoryzacja + Płatność Cashu Token + Wykup + Wyślij do Zap Wallet + Otwórz w Portfelu Cashu + Skopiuj token + Nie ustawiono adresu Lightning + Skopiowano token do schowka + LIVE + OFFLINE + Zakończony + ZAPLANOWANE + Transmisja wyłączona + Transmisja na żywo zakończona + Wylogowanie usuwa wszystkie informacje lokalne. Upewnij się, że masz kopię zapasową kluczy prywatnych, aby uniknąć utraty konta. Czy chcesz kontynuować? Obserwowane tagi Transmitery + Przegląd Wpisów + Market + Na żywo Społeczność Czaty Zatwierdzone posty @@ -312,6 +468,7 @@ Spamerzy Wyciszone. Kliknij, aby wyłączyć wyciszenie Dźwięk włączony. Kliknij, aby wyciszyć + Wyszukiwanie lokalne i zdalne Adres Nostr został zweryfikowany Nieudana weryfikacja adresu Nostr Sprawdzanie adresu Nostr @@ -319,77 +476,221 @@ Domyślne Wybierz Transmiter, aby kontynuować Przekaż zapy do: + Wspierający klient podzieli i przekaże zapy na LNAdres lub profil użytkownika poniżej zamiast Ciebie + Wyświetl lokalizację jako + Dodaje Geohash twojej lokalizacji do wpisu. Użytkownicy będą wiedzieli, że jesteś mniej niż 5 km od bieżącej lokalizacji Dodaje ostrzeżenie o wrażliwych treściach przed wyświetleniem treści. Jest to idealne dla dowolnych treści NSFW lub treści, które niektóre osoby mogą uznać za obraźliwe lub przeszkadzające + Nowa Funkcjonalność Aktywacja tego trybu wymaga wysłania wiadomości NIP-17 przez Ametyst. (Prezent, Zapieczętowane wiadomości bezpośrednie i grupowe). NIP-17 jest nowy, a większość klientów jeszcze go nie zaimplementowała. Upewnij się, że odbiorca używa kompatybilnego klienta. + Aktywuj + Publiczna + Nowa Grupa Publiczna lub Prywatna + Prywatna Do Temat Temat dyskusji "\@Użytkownik1, @Użytkownik2, @Użytkownik3" Członkowie tej grupy + Wyjaśnienie dla członków + Zmiana nazwy dla nowych celów. + Wklej ze schowka Dla interfejsu aplikacji Motyw ciemny, jasny lub automatyczny + Automatycznie załaduj obrazki i Gify Automatycznie odtwarzaj filmy i pliki GIF Pokaż podgląd linków + Kiedy załadować obrazki Kopiuj do schowka Kopiuj npub do schowka + Udostępnij lub Zapisz Kopiuj adres URL do schowka - Kopiuj ID notatki do schowka + Kopiuj ID wpisu do schowka + Utworzono + Zasady + Zaloguj się za pomocą Amber Zaktualizuj swój status Błąd podczas analizowania komunikatu o błędzie Głosy są oceniane na podstawie ilości zapperów. Możesz ustawić minimalną kwotę, aby uniknąć spamerów i maksymalną kwotę, aby uniknąć przejęcia ankiety przez dużych zapperów. Użyj tej samej kwoty w obu polach, aby upewnić się, że każdy głos ma taką samą wartość. Pozostaw to pole puste, aby zaakceptować dowolną kwotę. + Nie można wysłać zapa + Wyślij wiadomość użytkownikowi OK + Nieudane połączenie z %1$s: %2$s + Nie udało się skompilować adresu URL NIP-11 dla %1$s: %2$s + Nieudane połączenie z %1$s: %2$s + Nie udało się przeanalizować wyniku z %1$s: %2$s + Transmiter odrzucił żądanie %1$s: %2$s + Nieudane połączenie z %1$s: %2$s + Nie udało się przeanalizować wyniku z %1$s: %2$s + %1$s nie powiódł się z kodem %2$s + Aktywny dla: + Strona główna + DMs + Czaty Wszystkie + Szukaj Podziel i przekaż Zapy - Obsługa klientów podzieli i przekaże zapy do użytkowników dodanych tutaj, zamiast twoich + Wspierający klient podzieli i przekaże zapy do dodanego tutaj użytkownika, a nie do Ciebie Szukaj i dodaj użytkownika + Nick lub Login + Brakująca konfiguracja LN + Użytkownik %1$s nie ma skonfigurowanego adresu LN, aby odbierać saty + Procentowo 25 + Podziel zapsy z + Przesyłanie zapasów do + Nie znaleziono portfeli Lightning + Zapłacone + Portfel %1$s + Błąd podczas otwierania aplikacji podpisującej + Nie można odnaleźć aplikacji podpisującej. Sprawdź, czy aplikacja nie została odinstalowana + Odrzucono aplikację podpisującego + Upewnij się, że aplikacja podpisującego autoryzuje tę transakcję + Nie znaleziono portfeli do zapłacenia faktury z Lightning (Error: %1$s). Proszę zainstalować Lightning wallet, aby używać zapów + Nie znaleziono portfeli do zapłacenia faktury z Lightning. Proszę zainstalować Lightning wallet, aby używać zapów Ukryte słowa + Ukryj nowe słowo lub wyrażenie Zdjęcie profilowe Pokaż zdjęcia profilowe Wybierz opcję + Nie można zapłacić faktury + Nie można wypłacić + Nie można skonfigurować Wallet Connect + Błąd podczas analizowania ciągu połączeń NIP-47. Sprawdź, czy jest to poprawne z Twoim dostawcą portfela: %1$s. Błąd: %2$s + Błąd podczas analizowania ciągu połączeń NIP-47. Sprawdź u dostawcy portfela, czy jest to poprawne: %1$s. + Nie można wykupić Cashu + Mint dostarczył następujący komunikat błędu: %1$s + Tokeny Cashu zostały już wydane. + Cashu odebrano + %1$s saty zostały wysłane do Twojego portfela. (opłata: %2$s satów) + W systemie nie znaleziono kompatybilnego portfela Cashu + Nie można pobrać faktury z serwerów odbiorcy Twój dostawca połączenia z portfelem zwrócił następujący błąd: %1$s Połączenie z serwerem Tor nieudane - Nie można pobrać dokumentu transmitera + Nie można pobrać pliku z transmitera + Nie można stworzyć LNUrl z Adresu \"%1$s\". Sprawdź konfigurację użytkownika + Usługa lightning odbiorcy w %1$s jest niedostępna. Została obliczona na podstawie adresu lightning \"%2$s\". Błąd: %3$s. Sprawdź, czy serwer jest gotowy i czy adres lightning jest poprawny + Nie można rozwiązać %1$s. Sprawdź, czy jesteś połączony, czy serwer jest gotowy i czy lightning adres %2$s jest poprawny + Nie można rozwiązać %1$s. Sprawdź, czy jesteś połączony, czy serwer jest gotowy i czy lightning adres %2$s jest poprawny.\n\nWyjątkiem było: %3$s + Nie można pobrać faktury z %1$s + Błąd przetwarzania JSON z adresu lightning. Sprawdź konfigurację lightning użytkownika + Błąd przetwarzania JSON z %1$s. Sprawdź konfigurację lightning użytkownika + Adres zwrotny nie został znaleziony w konfiguracji serwera adresu lightning użytkownika + Nie znaleziono zwrotnego adresu URL z odpowiedzi %1$s + Wystąpił błąd podczas analizowania JSON z pobierania faktury z Lightning Adresu. Sprawdź konfigurację lightning użytkownika + Błąd przetwarzania pliku JSON z pobierania faktury %1$s. Sprawdź konfigurację lightning użytkownika + Nieprawidłowa kwota faktury (%1$s satów) od %2$s. Powinieno być %3$s + Nie można utworzyć faktury przed wysłaniem zapa. Portfel odbiorcy wysłał następujący błąd: %1$s + Nie można utworzyć faktury. Wiadomość od %1$s: %2$s + Nie można utworzyć faktury przed wysłaniem zapa. Element pr nie został znaleziony w powstałym JSON. + Nie można utworzyć faktury od %1$s: Element pr nie został znaleziony w powstałym JSON. \"Tylko do odczytu\" + Nie ustawiono reakcji + Wybierz aplikację UnifiedPush + Powiadomienia + Z zainstalowanych aplikacji UnifiedPush + Żaden + Wyłącz powiadomienia + Używa aplikacji %1$s + Ustawienia powiadomień + Aby otrzymywać powiadomienia, zainstaluj dowolną aplikację, która obsługuje [Unified Push](https://unifiedpush. rg/), np. [Nfty](https://ntfy.sh/). + Po zainstalowaniu, wybierz w ustawieniach aplikację, którą chcesz użyć. + + Wiadomość od %1$s + Wpis + Wyślij sprzedawcy wiadomość + Witaj %1$s, czy to nadal jest dostępne? + Cześć, czy to jest nadal dostępne? + Sprzedaj przedmiot Tytuł iPhone 13 Stan Kategoria Cena (w Satach) + 1000 Lokalizacja Miasto, Województwo, Kraj + Nowość + To zupełnie nowa jednostka, w oryginalnym pudełku Jak nowy + Jest używany, ale nie ma znaków użycia + Stan dobry + Posiada kilka powierzchownych śladów użytkowania + Średnia + Nadal jest w dobrym stanie i wciąż nadaje się do użytku + Odzież Akcesoria Elektronika Meble + Kolekcjonerstwo Książki Zwierzęta domowe Sporty Fitness Sztuka + Rzemiosło + AGD Biuro Żywność Różne Inne + Nie udało się załadować załącznika + Nie można otworzyć skompresowanego pliku + Błąd podczas kompresji plików: %1$s Błąd wysyłania: %1$s Serwer nie podał adresu URL po załadowaniu + Nie można pobrać przesłanych plików z serwera + Nie można przygotować pliku lokalnego do przesłania: %1$s + Edytuj wersję roboczą + Zaloguj się przy użyciu QR kodu + Ścieżka + Start + Szukaj + Odkryj + Wiadomości + Powiadomienia Wszystkie + Filmiki Filtry bezpieczeństwa Nowy post + Nowy wpis w społeczności + Otwórz wszystkie reakcje na ten post + Zamknij wszystkie reakcje na ten post + Odpowiedz + Zrepostuj lub Zacytuj + Lubię + Zap + Zdjęcie profilowe %1$s Transmiter %1$s Rozwiń listę transmiterów + Opcje wpisu Wybór listy transmiterów + Ankieta + Wyłącz Ankietę + Faktura Bitcoin + Anuluj fakturę Bitcoin + Anuluj sprzedaż przedmiotu + Zapraiser + Anuluj Zapraiser + Lokalizacja + Usuń lokalizację + Podział Zap + Anuluj podział Zap Dodaj ostrzeżenie o treści Usuń ostrzeżenie o treści Pokaż npub jako QR kod Nieprawidłowy adres + Ametyst otrzymał URI do otwarcia, ale ten adres był nieprawidłowy: %1$s Transmitery Skrzynki Odbiorczej + Transmitery %1$s + Korzystanie ze zwykłych transmiterów Skonfiguruj prywatne transmitery odbiorcze + To ustawienie pozwala wszystkim wiedzieć, których transmiterów użyć podczas wysyłania wiadomości do Ciebie. Bez nich możesz przegapić niektóre wiadomości. Dobre opcje to:\n - inbox.nostr.wine (płatny)\n - you.nostr1.com (transmitery osobiste - płatny) Wstaw od 1 do 3 transmiterów, które będą służyć jako Twoja prywatna skrzynka odbiorcza. Transmitery DM powinny akceptować dowolne wiadomości od każdego, ale pozwalać tylko na ich pobieranie. - Skonfiguruj + Konfiguruj Transmitery wyszukujące - Skonfiguruj swoje Transmitery wyszukujące + Skonfiguruj transmitery wyszukujące + Stworzenie listy transmiterów specjalnie przeznaczonych do wyszukiwania i tagowania użytkowników poprawi te wyniki. Wstaw od 1 do 3 transmiterów, które będą używane podczas wyszukiwania treści lub tagowania użytkowników. Upewnij się, że zaimplementowano NIP-50 Ustawienia Transmiterów Publiczne transmitery domowe @@ -406,13 +707,46 @@ Lista transmiterów używanych podczas wyszukiwania treści lub użytkowników. Tagowanie i wyszukiwanie nie będą działać, jeśli nie będą dostępne żadne opcje. Upewnij się, że zaimplementowano NIP-50. Lokalne Transmitery Lista transmiterów działających na tym urządzeniu. + Wspieraj deweloperów! + Twoja darowizna pomaga nam coś zmienić. Każdy sat liczy się! Przekaż darowiznę został Ci dostarczony przez: Ta wersja została Ci dostarczona przez: Wersja %1$s Dziękuję! Maksymalny Limit + Twórcy z ograniczeniami + Sklonowany z + SKLONUJ + Repozytorium Git: %1$s + Strona internetowa: + Klonuj: + OTS: %1$s + Potwierdzenie znacznika czasu + Istnieje dowód na to, że ten post został podpisany przed %1$s. Dowód został opatrzony pieczęcią w łańcuchu bloków Bitcoin w tym dniu i czasie. + Edytuj wpis + Propozycja ulepszenia wpisu + Podsumowanie zmian + Szybkie poprawki… + Zaakceptuj sugestię + Pobierz + Tekst włączony + Tekst wyłączony + Zapieczętowana wiadomość wyłączona. Kliknij, aby włączyć zapieczętowaną wiadomość + Zapieczętowana wiadomość włączona. Kliknij, aby wyłączyć zapieczętowaną wiadomość Wyślij + Odtwórz nazwę użytkownika jako dźwięk Zeskanuj QR kod + Przejdź do Alby zewnętrznego dostawcy portfela + Nie jest możliwa odpowiedź na szkic wpisu + Nie jest możliwe zacytowanie szkicu notatki + Nie jest możliwe reagowanie na szkic wpisu + Nie jest możliwy zap dla szkicu wpisu + Szkic wpisu Z sms-a + Szukanie aplikacji + Wysłano zapytanie, oczekiwanie na odpowiedź + Zapytanie o pracę z DVM + Prośba o płatność została wysłana, oczekiwanie na potwierdzenie z Twojego portfela + Oczekiwanie na potwierdzenie płatności lub wysłanie wyników DVM From c07a0065a1eeec5d990a277f55db3447fc38b9cf Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 15 Jun 2024 11:28:20 -0400 Subject: [PATCH 03/45] Upgrades Compose, Lifecycle and Fragments --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7d9ae527d7..78eae24531 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,11 +11,11 @@ benchmarkJunit4 = "1.2.4" biometricKtx = "1.2.0-alpha05" blurhash = "1.0.0" coil = "2.6.0" -composeBom = "2024.05.00" +composeBom = "2024.06.00" coreKtx = "1.13.1" espressoCore = "3.5.1" firebaseBom = "33.1.0" -fragmentKtx = "1.7.1" +fragmentKtx = "1.8.0" gms = "4.4.1" jacksonModuleKotlin = "2.17.1" jna = "5.14.0" @@ -24,7 +24,7 @@ kotlin = "1.9.24" kotlinxCollectionsImmutable = "0.3.7" languageId = "17.0.5" lazysodiumAndroid = "5.1.0" -lifecycleRuntimeKtx = "2.7.0" +lifecycleRuntimeKtx = "2.8.2" lightcompressor = "1.3.2" markdown = "077a2cde64" media3 = "1.3.1" From 010402ebd5342b8e6de846dfa4c1e6bae21c3460 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Sat, 15 Jun 2024 15:31:05 +0000 Subject: [PATCH 04/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-pl-rPL/strings.xml | 2 ++ app/src/main/res/values-zh-rCN/strings.xml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index aac8f92eb8..f9d3b679a7 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -652,6 +652,7 @@ Filmiki Filtry bezpieczeństwa Nowy post + Nowe Króciaki: zdjęcia lub filmiki Nowy wpis w społeczności Otwórz wszystkie reakcje na ten post Zamknij wszystkie reakcje na ten post @@ -692,6 +693,7 @@ Skonfiguruj transmitery wyszukujące Stworzenie listy transmiterów specjalnie przeznaczonych do wyszukiwania i tagowania użytkowników poprawi te wyniki. Wstaw od 1 do 3 transmiterów, które będą używane podczas wyszukiwania treści lub tagowania użytkowników. Upewnij się, że zaimplementowano NIP-50 + Dobre opcje to:\n - nostr.wine\n - relay.nostr.band\n - relay.noswhere.com Ustawienia Transmiterów Publiczne transmitery domowe Ten typ transmitera przechowuje całą zawartość. Amethyst będzie wysyłać Twoje posty tutaj, a inni będą korzystać z tych transmiterów, aby znaleźć Twoje treści. Wstaw od 1 do 3 transmiterów. Mogą to być transmitery prywatne, płatne lub publiczne. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 983fe5be2f..775ddbecf0 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -515,6 +515,10 @@ 向用户发送消息 无法连接 %1$s: %2$s + 组合 %1$s 的 NIP-11 URL 失败: %2$s + 无法连接 %1$s: %2$s + 无法解析来自 %1$s 的响应: %2$s + 中继拒绝请求 %1$s: %2$s 无法连接 %1$s: %2$s 无法解析来自 %1$s的结果: %2$s %1$s 失败,代码 %2$s From ae0ae413e6ae9c85babf91ad5667039d1b7b2053 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 15 Jun 2024 12:33:06 -0400 Subject: [PATCH 05/45] Fixes Go Button on new user screen --- .../ui/screen/loggedOff/SignUpScreen.kt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt index d157892444..a67ba3a79b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt @@ -161,9 +161,7 @@ fun SignUpPage( } if (acceptedTerms.value && displayName.value.text.isNotBlank()) { - accountStateViewModel.login(displayName.value.text, useProxy.value, proxyPort.value.toInt()) { - errorMessage = context.getString(R.string.invalid_key) - } + accountStateViewModel.newKey(useProxy.value, proxyPort.value.toInt(), displayName.value.text) } }, ), @@ -202,8 +200,7 @@ fun SignUpPage( ClickableText( text = annotatedTermsString, ) { spanOffset -> - annotatedTermsString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { - span -> + annotatedTermsString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { span -> if (span.tag == "openTerms") { runCatching { uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md") @@ -244,12 +241,12 @@ fun SignUpPage( }, onError = { scope.launch { - Toast.makeText( - context, - it, - Toast.LENGTH_LONG, - ) - .show() + Toast + .makeText( + context, + it, + Toast.LENGTH_LONG, + ).show() } }, proxyPort, From 80d506be37007c674098bc086967bcee9ff896e4 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 15 Jun 2024 12:33:43 -0400 Subject: [PATCH 06/45] Allows login with NIP-05 address --- .../service/Nip05NostrAddressVerifier.kt | 60 +++++++------------ .../ui/screen/AccountStateViewModel.kt | 24 ++++---- 2 files changed, 36 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt index 559c0bae92..1846124976 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifier.kt @@ -25,12 +25,9 @@ import com.vitorpamplona.amethyst.BuildConfig import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import okhttp3.Call -import okhttp3.Callback import okhttp3.Request -import okhttp3.Response -class Nip05NostrAddressVerifier() { +class Nip05NostrAddressVerifier { fun assembleUrl(nip05address: String): String? { val parts = nip05address.trim().split("@") @@ -46,7 +43,7 @@ class Nip05NostrAddressVerifier() { suspend fun fetchNip05Json( nip05: String, - onSuccess: (String) -> Unit, + onSuccess: suspend (String) -> Unit, onError: (String) -> Unit, ) = withContext(Dispatchers.IO) { checkNotInMainThread() @@ -60,52 +57,39 @@ class Nip05NostrAddressVerifier() { try { val request = - Request.Builder() + Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url(url) .build() // Fetchers MUST ignore any HTTP redirects given by the /.well-known/nostr.json endpoint. - HttpClientManager.getHttpClient().newBuilder().followRedirects(false).build() + HttpClientManager + .getHttpClient() + .newBuilder() + .followRedirects(false) + .build() .newCall(request) - .enqueue( - object : Callback { - override fun onResponse( - call: Call, - response: Response, - ) { - checkNotInMainThread() + .execute() + .use { + checkNotInMainThread() - response.use { - if (it.isSuccessful) { - onSuccess(it.body.string()) - } else { - onError( - "Could not resolve $nip05. Error: ${it.code}. Check if the server is up and if the address $nip05 is correct", - ) - } - } - } - - override fun onFailure( - call: Call, - e: java.io.IOException, - ) { - onError( - "Could not resolve $url. Check if the server is up and if the address $nip05 is correct", - ) - e.printStackTrace() - } - }, - ) + if (it.isSuccessful) { + onSuccess(it.body.string()) + } else { + onError( + "Could not resolve $nip05. Error: ${it.code}. Check if the server is up and if the address $nip05 is correct", + ) + } + } } catch (e: Exception) { if (e is CancellationException) throw e - onError("Could not resolve '$url': ${e.message}") + onError("Could not resolve NIP-05 $nip05 as URL $url: ${e.message}") } } suspend fun verifyNip05( nip05: String, - onSuccess: (String) -> Unit, + onSuccess: suspend (String) -> Unit, onError: (String) -> Unit, ) { // check fails on tests diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index 03c5f8d3d2..18e4803c28 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -29,6 +29,7 @@ import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.HttpClientManager +import com.vitorpamplona.amethyst.service.Nip05NostrAddressVerifier import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.crypto.KeyPair @@ -57,7 +58,7 @@ import java.util.regex.Pattern val EMAIL_PATTERN = Pattern.compile(".+@.+\\.[a-z]+") @Stable -class AccountStateViewModel() : ViewModel() { +class AccountStateViewModel : ViewModel() { var serviceManager: ServiceManager? = null private val _accountContent = MutableStateFlow(AccountState.Loading) @@ -144,15 +145,6 @@ class AccountStateViewModel() : ViewModel() { proxyPort = proxyPort, signer = NostrSignerInternal(keyPair), ) - } else if (EMAIL_PATTERN.matcher(key).matches()) { - val keyPair = KeyPair() - // TODO: Evaluate NIP-5 - Account( - keyPair, - proxy = proxy, - proxyPort = proxyPort, - signer = NostrSignerInternal(keyPair), - ) } else { val keyPair = KeyPair(Hex.decode(key)) Account( @@ -243,6 +235,18 @@ class AccountStateViewModel() : ViewModel() { onError(null) } } + } else if (EMAIL_PATTERN.matcher(key).matches()) { + Nip05NostrAddressVerifier().verifyNip05( + key, + onSuccess = { publicKey -> + loginSync(Hex.decode(publicKey).toNpub(), useProxy, proxyPort, loginWithExternalSigner, packageName) { + onError(null) + } + }, + onError = { + onError(it) + }, + ) } else { loginSync(key, useProxy, proxyPort, loginWithExternalSigner, packageName) { onError(null) From 545df8317729c39e3891634b3101f33dd3002492 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 15 Jun 2024 12:34:03 -0400 Subject: [PATCH 07/45] Simple refactoring --- .../amethyst/ui/note/NoteCompose.kt | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index e2a26e1106..51107e4869 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -461,7 +461,14 @@ fun InnerNoteWithReactions( horizontalArrangement = RowColSpacing10dp, ) { if (notBoostedNorQuote) { - AuthorAndRelayInformation(baseNote, accountViewModel, nav) + Column(WidthAuthorPictureModifier, verticalArrangement = RowColSpacing5dp) { + // Draws the boosted picture outside the boosted card. + Box(modifier = Size55Modifier, contentAlignment = Alignment.BottomEnd) { + RenderAuthorImages(baseNote, nav, accountViewModel) + } + + BadgeBox(baseNote, accountViewModel, nav) + } } Column(Modifier.fillMaxWidth()) { @@ -1051,22 +1058,6 @@ fun observeEdits( return editState } -@Composable -private fun AuthorAndRelayInformation( - baseNote: Note, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - Column(WidthAuthorPictureModifier, verticalArrangement = RowColSpacing5dp) { - // Draws the boosted picture outside the boosted card. - Box(modifier = Size55Modifier, contentAlignment = Alignment.BottomEnd) { - RenderAuthorImages(baseNote, nav, accountViewModel) - } - - BadgeBox(baseNote, accountViewModel, nav) - } -} - @Composable private fun BadgeBox( baseNote: Note, @@ -1088,9 +1079,7 @@ private fun RenderAuthorImages( nav: (String) -> Unit, accountViewModel: AccountViewModel, ) { - val isRepost = baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent - - if (isRepost) { + if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) { val baseRepost = baseNote.replyTo?.lastOrNull() if (baseRepost != null) { RepostNoteAuthorPicture(baseNote, baseRepost, accountViewModel, nav) From 719be8469fda40599f6edd3f8137ba83ff9e927c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sun, 16 Jun 2024 19:36:41 -0400 Subject: [PATCH 08/45] Fix test cases --- .../amethyst/service/Nip05NostrAddressVerifierTest.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt b/app/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt index a8ee63a463..6a1c6af29f 100644 --- a/app/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt +++ b/app/src/test/java/com/vitorpamplona/amethyst/service/Nip05NostrAddressVerifierTest.kt @@ -64,7 +64,9 @@ class Nip05NostrAddressVerifierTest { coEvery { nip05Verifier.fetchNip05Json(any(), any(), any()) } answers { - secondArg<(String) -> Unit>().invoke(nostrJson) + runBlocking { + secondArg Unit>().invoke(nostrJson) + } } val nip05 = "$userNameToTest@domain.com" @@ -95,7 +97,9 @@ class Nip05NostrAddressVerifierTest { "}" coEvery { nip05Verifier.fetchNip05Json(any(), any(), any()) } answers { - secondArg<(String) -> Unit>().invoke(nostrJson) + runBlocking { + secondArg Unit>().invoke(nostrJson) + } } val nip05 = "$ALL_LOWER_CASE_USER_NAME@domain.com" From a8b6118e2daae292883da6f5ab9c74f7605b93f6 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Sun, 16 Jun 2024 23:37:55 +0000 Subject: [PATCH 09/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-hi-rIN/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 10cf3587b2..c1fc16b02b 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -515,6 +515,10 @@ उपयोगकर्ता को संदेश भेजें ठीक है %1$s तक जा नहीं पाए : %2$s + %1$s के लिए निप॰-११ जालपता बनाने में असफल : %2$s + %1$s तक जाने में असफल : %2$s + %1$s से प्रतिवचन परखने में असफल : %2$s + पुनःप्रसारक ने %1$s अनुरोध को इनकार किया : %2$s %1$s तक जा नहीं पाए : %2$s %1$s से परिणाम परख नहीं पाए : %2$s %1$s असफल हुआ इस संकेतक के साथ : %2$s From aad95595eb188ccd95e437f40f9854f2987d4945 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 17 Jun 2024 14:37:31 -0400 Subject: [PATCH 10/45] Quick Refactoring of the Author UI components. --- .../ui/note/ChatroomMessageCompose.kt | 8 +++- .../vitorpamplona/amethyst/ui/note/Icons.kt | 21 +++++++-- .../amethyst/ui/note/UserProfilePicture.kt | 45 ++++--------------- .../amethyst/ui/screen/FeedView.kt | 15 ------- .../ui/screen/loggedIn/ProfileScreen.kt | 37 +++++++-------- .../vitorpamplona/amethyst/ui/theme/Shape.kt | 3 +- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 20 ++++++++- 7 files changed, 67 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index 9f0ffe7e9d..4144b4b005 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -78,7 +78,7 @@ import com.vitorpamplona.amethyst.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.ui.theme.RowColSpacing5dp import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.Size20dp -import com.vitorpamplona.amethyst.ui.theme.Size5dp +import com.vitorpamplona.amethyst.ui.theme.Size5Modifier import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdTopPadding import com.vitorpamplona.amethyst.ui.theme.chatAuthorBox @@ -769,7 +769,11 @@ private fun WatchAndDisplayUser( accountViewModel = accountViewModel, ) - ObserveAndDisplayFollowingMark(author.pubkeyHex, Size5dp, accountViewModel) + WatchUserFollows(author.pubkeyHex, accountViewModel) { newFollowingState -> + if (newFollowingState) { + FollowingIcon(Size5Modifier) + } + } }, name = { if (userState != null) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 7796c6ad59..b193661e03 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -87,10 +87,15 @@ fun AmethystIcon(iconSize: Dp) { @Composable fun FollowingIcon(iconSize: Dp) { + FollowingIcon(Modifier.size(iconSize)) +} + +@Composable +fun FollowingIcon(modifier: Modifier) { Icon( imageVector = Following, contentDescription = stringResource(id = R.string.following), - modifier = Modifier.size(iconSize), + modifier = modifier, tint = Color.Unspecified, ) } @@ -549,18 +554,26 @@ fun ZapSplitIcon( fun ZapSplitPreview() { Column(horizontalAlignment = Alignment.CenterHorizontally) { Box( - Modifier.height(20.dp).width(25.dp), + Modifier + .height(20.dp) + .width(25.dp), ) { Icon( imageVector = Icons.Outlined.Bolt, contentDescription = stringResource(id = R.string.zaps), - modifier = Modifier.size(20.dp).align(Alignment.CenterStart), + modifier = + Modifier + .size(20.dp) + .align(Alignment.CenterStart), tint = BitcoinOrange, ) Icon( imageVector = Icons.Outlined.ArrowForwardIos, contentDescription = stringResource(id = R.string.zaps), - modifier = Modifier.size(13.dp).align(Alignment.CenterEnd), + modifier = + Modifier + .size(13.dp) + .align(Alignment.CenterEnd), tint = BitcoinOrange, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt index 75749a6078..75c763c317 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt @@ -20,9 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable @@ -30,7 +27,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.remember @@ -40,7 +36,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.Dp import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map @@ -161,23 +156,19 @@ fun ClickableUserPicture( .combinedClickable( onClick = { onClick(baseUser) }, onLongClick = { onLongClick(baseUser) }, - role = Role.Button, ) } else if (onClick != null) { Modifier .size(size) .clickable( onClick = { onClick(baseUser) }, - role = Role.Button, ) } else { Modifier.size(size) } } - Box(modifier = myModifier, contentAlignment = Alignment.TopEnd) { - BaseUserPicture(baseUser, size, accountViewModel, modifier) - } + BaseUserPicture(baseUser, size, accountViewModel, modifier, myModifier) } @Composable @@ -301,10 +292,8 @@ fun BaseUserPicture( size: Dp, accountViewModel: AccountViewModel, innerModifier: Modifier = Modifier, - outerModifier: Modifier = remember { Modifier.size(size) }, + outerModifier: Modifier = Modifier.size(size), ) { - val myIconSize by remember(size) { derivedStateOf { size.div(3.5f) } } - Box(outerModifier, contentAlignment = Alignment.TopEnd) { LoadUserProfilePicture(baseUser) { userProfilePicture, userName -> InnerUserPicture( @@ -317,7 +306,11 @@ fun BaseUserPicture( ) } - ObserveAndDisplayFollowingMark(baseUser.pubkeyHex, myIconSize, accountViewModel) + WatchUserFollows(baseUser.pubkeyHex, accountViewModel) { newFollowingState -> + if (newFollowingState) { + FollowingIcon(Modifier.size(size.div(3.5f))) + } + } } } @@ -345,11 +338,6 @@ fun InnerUserPicture( modifier.size(size).clip(shape = CircleShape) } - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - RobohashFallbackAsyncImage( robot = userHex, model = userPicture, @@ -361,27 +349,10 @@ fun InnerUserPicture( }, modifier = myImageModifier, contentScale = ContentScale.Crop, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, ) } -@Composable -fun ObserveAndDisplayFollowingMark( - userHex: String, - iconSize: Dp, - accountViewModel: AccountViewModel, -) { - WatchUserFollows(userHex, accountViewModel) { newFollowingState -> - AnimatedVisibility( - visible = newFollowingState, - enter = remember { fadeIn() }, - exit = remember { fadeOut() }, - ) { - FollowingIcon(iconSize) - } - } -} - @Composable fun WatchUserFollows( userHex: String, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt index 9c1299b904..8dd64290ff 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt @@ -77,21 +77,6 @@ fun RefresheableFeedView( } } -@Composable -fun DVMStatusView( - viewModel: FeedViewModel, - routeForLastRead: String?, - enablePullRefresh: Boolean = true, - scrollStateKey: String? = null, - accountViewModel: AccountViewModel, - nav: (String) -> Unit, -) { - viewModel.invalidateData() - SaveableFeedState(viewModel, scrollStateKey) { listState -> - RenderFeedState(viewModel, accountViewModel, listState, nav, routeForLastRead) - } -} - @Composable fun RefresheableBox( viewModel: InvalidatableViewModel, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 62bfe7fda6..5168253b5a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -25,7 +25,6 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.scrollBy @@ -159,6 +158,7 @@ import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.DividerThickness +import com.vitorpamplona.amethyst.ui.theme.Size100dp import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.ui.theme.Size25Modifier @@ -166,6 +166,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.ZeroPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.amethyst.ui.theme.userProfileBorderModifier import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.BadgeDefinitionEvent import com.vitorpamplona.quartz.events.BadgeProfilesEvent @@ -429,8 +430,7 @@ private fun RenderSurface( } } }, - ) - .fillMaxHeight() + ).fillMaxHeight() }, ) { RenderScreen( @@ -550,8 +550,7 @@ fun UpdateThreadsAndRepliesWhenBlockUnblock( accountViewModel.account.liveHiddenUsers .map { it.hiddenUsers.contains(baseUser.pubkeyHex) || it.spammers.contains(baseUser.pubkeyHex) - } - .observeAsState(accountViewModel.account.isHidden(baseUser)) + }.observeAsState(accountViewModel.account.isHidden(baseUser)) LaunchedEffect(key1 = isHidden) { threadsViewModel.invalidateData() @@ -597,7 +596,11 @@ private fun RelaysTabHeader(baseUser: User) { val userStateRelayInfo by baseUser.live().relayInfo.observeAsState() val userRelays = remember(userStateRelayInfo) { - userStateRelayInfo?.user?.latestContactList?.relays()?.size ?: "--" + userStateRelayInfo + ?.user + ?.latestContactList + ?.relays() + ?.size ?: "--" } Text(text = "$userRelaysBeingUsed / $userRelays ${stringResource(R.string.relays)}") @@ -780,13 +783,8 @@ private fun ProfileHeader( ClickableUserPicture( baseUser = baseUser, accountViewModel = accountViewModel, - size = 100.dp, - modifier = - Modifier.border( - 3.dp, - MaterialTheme.colorScheme.background, - CircleShape, - ), + size = Size100dp, + modifier = MaterialTheme.colorScheme.userProfileBorderModifier, onClick = { if (baseUser.profilePicture() != null) { zoomImageDialogOpen = true @@ -922,31 +920,28 @@ fun WatchIsHiddenUser( accountViewModel.account.liveHiddenUsers .map { it.hiddenUsers.contains(baseUser.pubkeyHex) || it.spammers.contains(baseUser.pubkeyHex) - } - .observeAsState(accountViewModel.account.isHidden(baseUser)) + }.observeAsState(accountViewModel.account.isHidden(baseUser)) content(isHidden) } -fun getIdentityClaimIcon(identity: IdentityClaim): Int { - return when (identity) { +fun getIdentityClaimIcon(identity: IdentityClaim): Int = + when (identity) { is TwitterIdentity -> R.drawable.twitter is TelegramIdentity -> R.drawable.telegram is MastodonIdentity -> R.drawable.mastodon is GitHubIdentity -> R.drawable.github else -> R.drawable.github } -} -fun getIdentityClaimDescription(identity: IdentityClaim): Int { - return when (identity) { +fun getIdentityClaimDescription(identity: IdentityClaim): Int = + when (identity) { is TwitterIdentity -> R.string.twitter is TelegramIdentity -> R.string.telegram is MastodonIdentity -> R.string.mastodon is GitHubIdentity -> R.string.github else -> R.drawable.github } -} @Composable private fun DrawAdditionalInfo( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt index 4a5ddcc9f0..5f3bce586b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt @@ -97,6 +97,7 @@ val Size35dp = 35.dp val Size40dp = 40.dp val Size55dp = 55.dp val Size75dp = 75.dp +val Size100dp = 100.dp val Size110dp = 110.dp val Size165dp = 165.dp @@ -122,7 +123,7 @@ val VertPadding = Modifier.padding(vertical = 10.dp) val MaxWidthWithHorzPadding = Modifier.fillMaxWidth().padding(horizontal = 10.dp) -val Size6Modifier = Modifier.size(6.dp) +val Size5Modifier = Modifier.size(5.dp) val Size10Modifier = Modifier.size(10.dp) val Size15Modifier = Modifier.size(15.dp) val Size16Modifier = Modifier.size(16.dp) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index d96062a030..440a16c1e2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -191,6 +191,20 @@ val LightChannelNotePictureModifier = .clip(shape = CircleShape) .border(2.dp, LightColorPalette.background, CircleShape) +val LightProfilePictureBorder = + Modifier.border( + 3.dp, + DarkColorPalette.background, + CircleShape, + ) + +val DarkProfilePictureBorder = + Modifier.border( + 3.dp, + LightColorPalette.background, + CircleShape, + ) + val LightRelayIconModifier = Modifier .size(Size13dp) @@ -379,6 +393,9 @@ val ColorScheme.innerPostModifier: Modifier val ColorScheme.channelNotePictureModifier: Modifier get() = if (isLight) LightChannelNotePictureModifier else DarkChannelNotePictureModifier +val ColorScheme.userProfileBorderModifier: Modifier + get() = if (isLight) LightProfilePictureBorder else DarkProfilePictureBorder + val ColorScheme.relayIconModifier: Modifier get() = if (isLight) LightRelayIconModifier else DarkRelayIconModifier @@ -400,8 +417,7 @@ val ColorScheme.chartStyle: ChartStyle defaultColors.entity1Color, defaultColors.entity2Color, defaultColors.entity3Color, - ) - .map(::Color), + ).map(::Color), elevationOverlayColor = Color(defaultColors.elevationOverlayColor), ) } From 0fa6dce42c546420cb734697068a557f9ef5f626 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 17 Jun 2024 16:20:40 -0400 Subject: [PATCH 11/45] Fixes giftwrap date mismatch --- .../com/vitorpamplona/quartz/events/GiftWrapEvent.kt | 6 ++---- .../vitorpamplona/quartz/events/SealedGossipEvent.kt | 10 +++------- .../java/com/vitorpamplona/quartz/utils/TimeUtils.kt | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/GiftWrapEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/GiftWrapEvent.kt index 9d4e8950ca..7e98dcd4b8 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/GiftWrapEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/GiftWrapEvent.kt @@ -56,9 +56,7 @@ class GiftWrapEvent( override fun isContentEncoded() = true - fun preCachedGift(signer: NostrSigner): Event? { - return cachedInnerEvent[signer.pubKey] - } + fun preCachedGift(signer: NostrSigner): Event? = cachedInnerEvent[signer.pubKey] fun addToCache( pubKey: HexKey, @@ -114,7 +112,7 @@ class GiftWrapEvent( fun create( event: Event, recipientPubKey: HexKey, - createdAt: Long = TimeUtils.randomWithinAWeek(), + createdAt: Long = TimeUtils.randomWithTwoDays(), onReady: (GiftWrapEvent) -> Unit, ) { val signer = NostrSignerInternal(KeyPair()) // GiftWrap is always a random key diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/SealedGossipEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/SealedGossipEvent.kt index b6411f1625..1ca4af9c6d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/SealedGossipEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/SealedGossipEvent.kt @@ -58,9 +58,7 @@ class SealedGossipEvent( override fun isContentEncoded() = true - fun preCachedGossip(signer: NostrSigner): Event? { - return cachedInnerEvent[signer.pubKey] - } + fun preCachedGossip(signer: NostrSigner): Event? = cachedInnerEvent[signer.pubKey] fun addToCache( pubKey: HexKey, @@ -133,7 +131,7 @@ class SealedGossipEvent( gossip: Gossip, encryptTo: HexKey, signer: NostrSigner, - createdAt: Long = TimeUtils.randomWithinAWeek(), + createdAt: Long = TimeUtils.randomWithTwoDays(), onReady: (SealedGossipEvent) -> Unit, ) { val msg = Gossip.toJson(gossip) @@ -172,8 +170,6 @@ class Gossip( fun toJson(event: Gossip): String = Event.mapper.writeValueAsString(event) - fun create(event: Event): Gossip { - return Gossip(event.id, event.pubKey, event.createdAt, event.kind, event.tags, event.content) - } + fun create(event: Event): Gossip = Gossip(event.id, event.pubKey, event.createdAt, event.kind, event.tags, event.content) } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt b/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt index 023fc9fb65..bb13e4f998 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt @@ -55,5 +55,5 @@ object TimeUtils { fun oneWeekAgo() = now() - ONE_WEEK - fun randomWithinAWeek() = System.currentTimeMillis() / 1000 - CryptoUtils.randomInt(ONE_WEEK) + fun randomWithTwoDays() = System.currentTimeMillis() / 1000 - CryptoUtils.randomInt(twoDays()) } From 5d5c3ae3e3a6ce4ce36c80fad6d3b4fe0c92585c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 17 Jun 2024 17:22:39 -0400 Subject: [PATCH 12/45] Faster calculation of uncited hashtags. --- .../amethyst/service/CachedRichTextParser.kt | 7 +- .../note/elements/DisplayUncitedHashtags.kt | 67 ++++++++++++++++--- .../amethyst/ui/note/types/AudioTrack.kt | 3 +- .../amethyst/ui/note/types/CommunityHeader.kt | 15 ++--- .../amethyst/ui/note/types/Git.kt | 18 ++--- .../types/NIP90ContentDiscoveryResponse.kt | 53 ++------------- .../amethyst/ui/note/types/Poll.kt | 4 +- .../amethyst/ui/note/types/PrivateMessage.kt | 8 +-- .../amethyst/ui/note/types/Text.kt | 16 ++--- .../amethyst/ui/note/types/Video.kt | 17 ++--- .../ui/screen/loggedIn/ChannelScreen.kt | 25 ++++--- .../com/vitorpamplona/quartz/events/Event.kt | 2 + .../quartz/events/EventInterface.kt | 2 + .../vitorpamplona/quartz/utils/StringUtils.kt | 9 +-- 14 files changed, 115 insertions(+), 131 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt index cd11404445..8a7027a667 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt @@ -28,13 +28,16 @@ import com.vitorpamplona.quartz.events.ImmutableListOfLists object CachedRichTextParser { val richTextCache = LruCache(50) + fun getCached(content: String): RichTextViewerState? = richTextCache[content] + fun parseText( content: String, tags: ImmutableListOfLists, callbackUri: String? = null, ): RichTextViewerState { - return if (richTextCache[content] != null) { - richTextCache[content] + val cached = richTextCache[content] + return if (cached != null) { + cached } else { val newUrls = RichTextParser().parseText(content, tags, callbackUri) richTextCache.put(content, newUrls) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt index 551f606898..97c48e96f5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt @@ -26,23 +26,75 @@ import androidx.compose.foundation.text.ClickableText import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.ui.text.AnnotatedString +import com.vitorpamplona.amethyst.commons.richtext.HashTagSegment +import com.vitorpamplona.amethyst.service.CachedRichTextParser import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.ui.theme.lessImportantLink -import kotlinx.collections.immutable.ImmutableList +import com.vitorpamplona.quartz.events.Event +import com.vitorpamplona.quartz.events.toImmutableListOfLists +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@Composable +fun DisplayUncitedHashtags( + event: Event, + nav: (String) -> Unit, +) { + DisplayUncitedHashtags(event, event.content, nav) +} @OptIn(ExperimentalLayoutApi::class) @Composable fun DisplayUncitedHashtags( - hashtags: ImmutableList, - eventContent: String, + event: Event, + content: String, nav: (String) -> Unit, ) { - val unusedHashtags = - remember(eventContent) { hashtags.filter { !eventContent.contains(it, true) } } + val unusedHashtags by + produceState(initialValue = emptyList()) { + withContext(Dispatchers.Default) { + val state = CachedRichTextParser.parseText(content, event.tags.toImmutableListOfLists()) + + val tagsInEvent = event.hashtags() + + if (tagsInEvent.isEmpty()) return@withContext + + val tagsInContent = + state + .paragraphs + .map { + it.words.mapNotNull { + if (it is HashTagSegment) { + it.hashtag + } else { + null + } + } + }.flatten() + + val unusedHashtags = + tagsInEvent.filterNot { eventTag -> + tagsInContent.any { contentTag -> + eventTag.equals(contentTag, true) + } + } + + if (unusedHashtags.isNotEmpty()) { + value = unusedHashtags + } + } + } if (unusedHashtags.isNotEmpty()) { + val style = + LocalTextStyle.current.copy( + color = MaterialTheme.colorScheme.lessImportantLink, + ) + FlowRow( modifier = HalfTopPadding, ) { @@ -50,10 +102,7 @@ fun DisplayUncitedHashtags( ClickableText( text = remember { AnnotatedString("#$hashtag ") }, onClick = { nav("Hashtag/$hashtag") }, - style = - LocalTextStyle.current.copy( - color = MaterialTheme.colorScheme.lessImportantLink, - ), + style = style, ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt index 1c59001dcb..7b3215b965 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt @@ -240,8 +240,7 @@ fun AudioHeader( if (noteEvent.hasHashtags()) { Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { - val hashtags = remember(noteEvent) { noteEvent.hashtags().toImmutableList() } - DisplayUncitedHashtags(hashtags, content ?: "", nav) + DisplayUncitedHashtags(noteEvent, nav) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index 5386e101de..3477c8af24 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -79,7 +79,6 @@ import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.Participant import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList import java.util.Locale @Composable @@ -90,9 +89,10 @@ fun RenderCommunity( ) { if (baseNote is AddressableNote) { Row( - MaterialTheme.colorScheme.innerPostModifier.clickable { - routeFor(baseNote, accountViewModel.userProfile())?.let { nav(it) } - }.padding(Size10dp), + MaterialTheme.colorScheme.innerPostModifier + .clickable { + routeFor(baseNote, accountViewModel.userProfile())?.let { nav(it) } + }.padding(Size10dp), ) { ShortCommunityHeader( baseNote = baseNote, @@ -160,8 +160,8 @@ fun LongCommunityHeader( if (summary != null && noteEvent.hasHashtags()) { DisplayUncitedHashtags( - hashtags = remember(key1 = noteEvent) { noteEvent.hashtags().toImmutableList() }, - eventContent = summary, + event = noteEvent, + content = summary, nav = nav, ) } @@ -361,8 +361,7 @@ fun WatchAddressableNoteFollows( accountViewModel.userFollows .map { it.user.latestContactList?.isTaggedAddressableNote(note.idHex) ?: false } .distinctUntilChanged() - } - .observeAsState(false) + }.observeAsState(false) onFollowChanges(showFollowingMark) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt index 27b8f7681f..e4a0a6b62b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt @@ -66,8 +66,6 @@ import com.vitorpamplona.quartz.events.GitPatchEvent import com.vitorpamplona.quartz.events.GitRepositoryEvent import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList @Composable fun RenderGitPatchEvent( @@ -195,11 +193,11 @@ private fun RenderGitPatchEvent( } if (note.event?.hasHashtags() == true) { - val hashtags = - remember(note.event) { - note.event?.hashtags()?.toImmutableList() ?: persistentListOf() - } - DisplayUncitedHashtags(hashtags, eventContent, nav) + DisplayUncitedHashtags( + event = noteEvent, + content = eventContent, + nav = nav, + ) } } } @@ -299,11 +297,7 @@ private fun RenderGitIssueEvent( } if (note.event?.hasHashtags() == true) { - val hashtags = - remember(note.event) { - note.event?.hashtags()?.toImmutableList() ?: persistentListOf() - } - DisplayUncitedHashtags(hashtags, eventContent, nav) + DisplayUncitedHashtags(noteEvent, eventContent, nav) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt index a4d6f68125..02a060d57e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note.types -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -35,17 +34,12 @@ import com.vitorpamplona.amethyst.ui.components.GenericLoadable import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent -import com.vitorpamplona.amethyst.ui.note.ReplyNoteComposition import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer -import com.vitorpamplona.quartz.events.BaseTextNoteEvent -import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.EmptyTagList +import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList @Composable fun RenderNIP90ContentDiscoveryResponse( @@ -59,39 +53,7 @@ fun RenderNIP90ContentDiscoveryResponse( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val noteEvent = note.event - - val showReply by - remember(note) { - derivedStateOf { - noteEvent is BaseTextNoteEvent && !makeItShort && unPackReply && (note.replyTo != null || noteEvent.hasAnyTaggedUser()) - } - } - - if (showReply) { - val replyingDirectlyTo = - remember(note) { - if (noteEvent is BaseTextNoteEvent) { - val replyingTo = noteEvent.replyingToAddressOrEvent() - if (replyingTo != null) { - val newNote = accountViewModel.getNoteIfExists(replyingTo) - if (newNote != null && newNote.channelHex() == null && newNote.event?.kind() != CommunityDefinitionEvent.KIND) { - newNote - } else { - note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND } - } - } else { - note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND } - } - } else { - note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND } - } - } - if (replyingDirectlyTo != null && unPackReply) { - ReplyNoteComposition(replyingDirectlyTo, backgroundColor, accountViewModel, nav) - Spacer(modifier = StdVertSpacer) - } - } + val noteEvent = note.event as? Event ?: return LoadDecryptedContent( note, @@ -118,9 +80,6 @@ fun RenderNIP90ContentDiscoveryResponse( } } - val isAuthorTheLoggedUser = - remember(note.event) { accountViewModel.isLoggedUser(note.author) } - SensitivityWarning( note = note, accountViewModel = accountViewModel, @@ -143,12 +102,8 @@ fun RenderNIP90ContentDiscoveryResponse( ) } - if (note.event?.hasHashtags() == true) { - val hashtags = - remember(note.event) { - note.event?.hashtags()?.toImmutableList() ?: persistentListOf() - } - DisplayUncitedHashtags(hashtags, eventContent, nav) + if (noteEvent.hasHashtags()) { + DisplayUncitedHashtags(noteEvent, eventContent, nav) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt index 27db72f57c..eedd9003fd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt @@ -45,7 +45,6 @@ import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.PollNoteEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.toImmutableList @Composable fun RenderPoll( @@ -126,8 +125,7 @@ fun RenderPoll( } if (noteEvent.hasHashtags()) { - val hashtags = remember { noteEvent.hashtags().toImmutableList() } - DisplayUncitedHashtags(hashtags, eventContent, nav) + DisplayUncitedHashtags(noteEvent, eventContent, nav) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt index ba026b5ca7..69cf512f77 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt @@ -52,8 +52,6 @@ import com.vitorpamplona.quartz.events.ChatroomKeyable import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList @Composable fun RenderPrivateMessage( @@ -122,11 +120,7 @@ fun RenderPrivateMessage( } if (noteEvent.hasHashtags()) { - val hashtags = - remember(note.event?.id()) { - note.event?.hashtags()?.toImmutableList() ?: persistentListOf() - } - DisplayUncitedHashtags(hashtags, eventContent, nav) + DisplayUncitedHashtags(noteEvent, eventContent, nav) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt index 775b1f7abe..e98dcec4c5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt @@ -46,10 +46,9 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.BaseTextNoteEvent import com.vitorpamplona.quartz.events.CommunityDefinitionEvent import com.vitorpamplona.quartz.events.EmptyTagList +import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList @Composable fun RenderTextEvent( @@ -63,7 +62,7 @@ fun RenderTextEvent( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val noteEvent = note.event + val noteEvent = note.event as? Event ?: return val showReply by remember(note) { @@ -137,7 +136,6 @@ fun RenderTextEvent( note = note, accountViewModel = accountViewModel, ) { - val modifier = remember(note) { Modifier.fillMaxWidth() } val tags = remember(note) { note.event?.tags()?.toImmutableListOfLists() ?: EmptyTagList } @@ -145,7 +143,7 @@ fun RenderTextEvent( content = eventContent, canPreview = canPreview && !makeItShort, quotesLeft = quotesLeft, - modifier = modifier, + modifier = Modifier.fillMaxWidth(), tags = tags, backgroundColor = backgroundColor, id = note.idHex, @@ -155,12 +153,8 @@ fun RenderTextEvent( ) } - if (note.event?.hasHashtags() == true) { - val hashtags = - remember(note.event) { - note.event?.hashtags()?.toImmutableList() ?: persistentListOf() - } - DisplayUncitedHashtags(hashtags, eventContent, nav) + if (noteEvent.hasHashtags()) { + DisplayUncitedHashtags(noteEvent, eventContent, nav) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt index 18636729a0..79f1ef6963 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt @@ -58,7 +58,6 @@ import com.vitorpamplona.amethyst.ui.theme.imageModifier import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.VideoEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.toImmutableList @Composable fun VideoDisplay( @@ -178,17 +177,13 @@ fun VideoDisplay( accountViewModel = accountViewModel, nav = nav, ) - } - if (event.hasHashtags()) { - Row( - Modifier.fillMaxWidth(), - ) { - DisplayUncitedHashtags( - remember(event) { event.hashtags().toImmutableList() }, - summary ?: "", - nav, - ) + if (event.hasHashtags()) { + Row( + Modifier.fillMaxWidth(), + ) { + DisplayUncitedHashtags(event, summary, nav) + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 7648f7244a..1f886feb86 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -710,8 +710,7 @@ fun ShowVideoStreaming( .map { val activity = it.channel as? LiveActivitiesChannel activity?.info - } - .distinctUntilChanged() + }.distinctUntilChanged() .observeAsState(baseChannel.info) streamingInfo?.let { event -> @@ -869,12 +868,12 @@ fun LongChannelHeader( ) } - if (baseChannel is LiveActivitiesChannel && baseChannel.info?.hasHashtags() == true) { - val hashtags = - remember(baseChannel.info) { - baseChannel.info?.hashtags()?.toImmutableList() ?: persistentListOf() + if (baseChannel is LiveActivitiesChannel && summary != null) { + baseChannel.info?.let { + if (it.hasHashtags()) { + DisplayUncitedHashtags(it, summary, nav) } - DisplayUncitedHashtags(hashtags, summary ?: "", nav) + } } } @@ -938,8 +937,7 @@ fun LongChannelHeader( ?.participants() ?.mapNotNull { part -> LocalCache.checkGetOrCreateUser(part.key)?.let { Pair(part, it) } - } - ?.toImmutableList() + }?.toImmutableList() if ( newParticipantUsers != null && !equalImmutableLists(newParticipantUsers, participantUsers) @@ -1155,10 +1153,11 @@ fun OfflineFlag() { fun ScheduledFlag(starts: Long?) { val startsIn = starts?.let { - SimpleDateFormat.getDateTimeInstance( - DateFormat.SHORT, - DateFormat.SHORT, - ).format(Date(starts * 1000)) + SimpleDateFormat + .getDateTimeInstance( + DateFormat.SHORT, + DateFormat.SHORT, + ).format(Date(starts * 1000)) } Text( diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt index 5051d93863..6228b74616 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt @@ -89,6 +89,8 @@ open class Event( override fun forEachTaggedEvent(onEach: (eventId: HexKey) -> Unit) = forEachTagged("e", onEach) + override fun forEachHashTag(onEach: (eventId: HexKey) -> Unit) = forEachTagged("t", onEach) + private fun forEachTagged( tagName: String, onEach: (eventId: HexKey) -> Unit, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt index 957ff7a997..5465a50f3d 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/EventInterface.kt @@ -119,6 +119,8 @@ interface EventInterface { fun forEachTaggedEvent(onEach: (eventId: HexKey) -> Unit) + fun forEachHashTag(onEach: (eventId: HexKey) -> Unit) + fun mapTaggedEvent(map: (eventId: HexKey) -> R): List fun mapTaggedAddress(map: (address: String) -> R): List diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/utils/StringUtils.kt b/quartz/src/main/java/com/vitorpamplona/quartz/utils/StringUtils.kt index 0682eccfb5..305d487be4 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/utils/StringUtils.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/utils/StringUtils.kt @@ -22,9 +22,7 @@ package com.vitorpamplona.quartz.utils import kotlin.math.min -fun String.bytesUsedInMemory(): Int { - return (8 * ((((this.length) * 2) + 45) / 8)) -} +fun String.bytesUsedInMemory(): Int = (8 * ((((this.length) * 2) + 45) / 8)) fun String.containsIgnoreCase(term: String): Boolean { if (term.isEmpty()) return true // Empty string is contained @@ -72,4 +70,7 @@ fun String.containsAny(terms: List): Boolean { return terms.any { containsIgnoreCase(it.lowercase, it.uppercase) } } -class DualCase(val lowercase: String, val uppercase: String) +class DualCase( + val lowercase: String, + val uppercase: String, +) From 08869ac350ba20fadad47da6e30147e524287b43 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 09:11:32 -0400 Subject: [PATCH 13/45] removes derived states and some remember functions for performance. --- .../amethyst/service/NostrSingleUserDataSource.kt | 8 +++----- .../amethyst/ui/navigation/AppBottomBar.kt | 13 ++++++++----- .../amethyst/ui/screen/ThreadFeedView.kt | 7 ++----- .../java/com/vitorpamplona/quartz/events/Event.kt | 2 +- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt index 6f5ac49465..e1a768992c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleUserDataSource.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.quartz.events.ReportEvent import com.vitorpamplona.quartz.events.StatusEvent object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") { - var usersToWatch = setOf() + private var usersToWatch = setOf() fun createUserMetadataFilter(): List? { if (usersToWatch.isEmpty()) return null @@ -83,8 +83,7 @@ object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") { ), ), ) - } - .flatten() + }.flatten() } val userChannel = @@ -110,8 +109,7 @@ object NostrSingleUserDataSource : NostrDataSource("SingleUserFeed") { listOfNotNull( createUserMetadataFilter(), createUserMetadataStatusReportFilter(), - ) - .flatten() + ).flatten() .ifEmpty { null } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt index e3dd7225fd..4478dd9a66 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt @@ -35,7 +35,6 @@ import androidx.compose.material3.NavigationBarItem import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.State -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -146,12 +145,16 @@ private fun RowScope.HasNewItemsIcon( navEntryState: State, nav: (Route, Boolean) -> Unit, ) { - val selected by - remember(navEntryState.value) { - derivedStateOf { navEntryState.value?.destination?.route?.substringBefore("?") == route.base } - } + val selected = + ( + navEntryState.value + ?.destination + ?.route + ?.indexOf(route.base) ?: -1 + ) > -1 NavigationBarItem( + alwaysShowLabel = false, icon = { NotifiableIcon( selected, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index 8542945a71..6980f89ed3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -47,7 +47,6 @@ import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -405,11 +404,9 @@ private fun FullBleedNoteCompose( Row(verticalAlignment = Alignment.CenterVertically) { NoteUsernameDisplay(baseNote, Modifier.weight(1f)) - val isCommunityPost by + val isCommunityPost = remember(baseNote) { - derivedStateOf { - baseNote.event?.isTaggedAddressableKind(CommunityDefinitionEvent.KIND) == true - } + baseNote.event?.isTaggedAddressableKind(CommunityDefinitionEvent.KIND) == true } if (isCommunityPost) { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt index 6228b74616..5dcd4710a3 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt @@ -143,7 +143,7 @@ open class Event( override fun isSensitive() = tags.any { - (it.size > 0 && it[0].equals("content-warning")) || + (it.size > 0 && it[0] == "content-warning") || (it.size > 1 && it[0] == "t" && (it[1].equals("nsfw", true) || it[1].equals("nude", true))) } From e18945b3787db99744bce908a1eef663bafcd994 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 09:13:48 -0400 Subject: [PATCH 14/45] Adds performance mode for older devices. --- .../vitorpamplona/amethyst/model/Settings.kt | 56 +-- .../amethyst/ui/actions/CrossfadeIfEnabled.kt | 45 +++ .../ui/actions/JoinUserOrChannelView.kt | 33 +- .../amethyst/ui/actions/NewPostView.kt | 8 +- .../relays/BasicRelaySetupInfoClickableRow.kt | 2 + .../relays/BasicRelaySetupInfoDialog.kt | 9 +- .../ui/actions/relays/Kind3RelayListView.kt | 132 +++---- .../actions/relays/RelayInformationDialog.kt | 27 +- .../amethyst/ui/components/CashuRedeem.kt | 4 +- .../ui/components/ClickableWithdrawal.kt | 10 +- .../ui/components/ForwardingPainter.kt | 79 +++++ .../amethyst/ui/components/InvoicePreview.kt | 10 +- .../amethyst/ui/components/LoadUrlPreview.kt | 7 +- .../amethyst/ui/components/RichTextViewer.kt | 28 +- .../ui/components/RobohashAsyncImage.kt | 78 +++-- .../ui/components/SensitivityWarning.kt | 4 +- .../ui/navigation/AccountSwitchBottomSheet.kt | 14 +- .../amethyst/ui/navigation/AppTopBar.kt | 52 ++- .../amethyst/ui/navigation/DrawerContent.kt | 12 +- .../amethyst/ui/note/ChannelCardCompose.kt | 4 +- .../amethyst/ui/note/ChatroomHeaderCompose.kt | 26 +- .../ui/note/ChatroomMessageCompose.kt | 16 +- .../amethyst/ui/note/MultiSetCompose.kt | 10 +- .../ui/note/NIP05VerificationDisplay.kt | 23 +- .../amethyst/ui/note/NoteCompose.kt | 11 +- .../amethyst/ui/note/ReactionsRow.kt | 70 ++-- .../amethyst/ui/note/RelayListBox.kt | 6 +- .../amethyst/ui/note/RelayListRow.kt | 4 + .../amethyst/ui/note/UserCompose.kt | 2 +- .../amethyst/ui/note/UserProfilePicture.kt | 9 +- .../amethyst/ui/note/UsernameDisplay.kt | 15 +- .../amethyst/ui/note/WatchNoteEvent.kt | 6 +- .../amethyst/ui/note/ZapCustomDialog.kt | 12 +- .../amethyst/ui/note/ZapNoteCompose.kt | 13 +- .../amethyst/ui/note/ZapUserSetCompose.kt | 2 +- .../ui/note/elements/ZapTheDevsCard.kt | 4 +- .../amethyst/ui/note/types/AudioTrack.kt | 2 +- .../amethyst/ui/note/types/CommunityHeader.kt | 13 +- .../amethyst/ui/note/types/Emoji.kt | 7 +- .../amethyst/ui/note/types/FileStorage.kt | 4 +- .../amethyst/ui/note/types/LiveActivity.kt | 6 +- .../amethyst/ui/qrcode/ShowQRDialog.kt | 6 +- .../amethyst/ui/screen/CardFeedView.kt | 5 +- .../amethyst/ui/screen/ChatroomFeedView.kt | 4 +- .../ui/screen/ChatroomListFeedView.kt | 5 +- .../amethyst/ui/screen/FeedView.kt | 17 +- .../amethyst/ui/screen/LnZapFeedView.kt | 4 +- .../ui/screen/SharedPreferencesViewModel.kt | 4 +- .../amethyst/ui/screen/StringFeedView.kt | 6 +- .../amethyst/ui/screen/ThreadFeedView.kt | 2 +- .../amethyst/ui/screen/UserFeedView.kt | 4 +- .../ui/screen/loggedIn/ChannelScreen.kt | 13 +- .../ui/screen/loggedIn/ChatroomScreen.kt | 15 +- .../ui/screen/loggedIn/DiscoverScreen.kt | 17 +- .../ui/screen/loggedIn/HiddenUsersScreen.kt | 1 + .../amethyst/ui/screen/loggedIn/HomeScreen.kt | 5 +- .../amethyst/ui/screen/loggedIn/MainScreen.kt | 322 +++++++++++------- .../loggedIn/NIP90ContentDiscoveryScreen.kt | 11 +- .../ui/screen/loggedIn/ProfileScreen.kt | 50 +-- .../ui/screen/loggedIn/SearchScreen.kt | 29 +- .../ui/screen/loggedIn/SettingsScreen.kt | 4 +- .../ui/screen/loggedIn/VideoScreen.kt | 9 +- app/src/main/res/values/strings.xml | 1 + .../components/TranslatableRichTextViewer.kt | 19 +- 64 files changed, 860 insertions(+), 568 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt index 3d5993718f..f1c4332645 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -34,17 +34,20 @@ data class Settings( val automaticallyShowProfilePictures: ConnectivityType = ConnectivityType.ALWAYS, val dontShowPushNotificationSelector: Boolean = false, val dontAskForNotificationPermissions: Boolean = false, - val featureSet: FeatureSetType = FeatureSetType.COMPLETE, + val featureSet: FeatureSetType = FeatureSetType.SIMPLIFIED, ) -enum class ThemeType(val screenCode: Int, val resourceId: Int) { +enum class ThemeType( + val screenCode: Int, + val resourceId: Int, +) { SYSTEM(0, R.string.system), LIGHT(1, R.string.light), DARK(2, R.string.dark), } -fun parseThemeType(code: Int?): ThemeType { - return when (code) { +fun parseThemeType(code: Int?): ThemeType = + when (code) { ThemeType.SYSTEM.screenCode -> ThemeType.SYSTEM ThemeType.LIGHT.screenCode -> ThemeType.LIGHT ThemeType.DARK.screenCode -> ThemeType.DARK @@ -52,21 +55,28 @@ fun parseThemeType(code: Int?): ThemeType { ThemeType.SYSTEM } } -} -enum class ConnectivityType(val prefCode: Boolean?, val screenCode: Int, val resourceId: Int) { +enum class ConnectivityType( + val prefCode: Boolean?, + val screenCode: Int, + val resourceId: Int, +) { ALWAYS(null, 0, R.string.connectivity_type_always), WIFI_ONLY(true, 1, R.string.connectivity_type_wifi_only), NEVER(false, 2, R.string.connectivity_type_never), } -enum class FeatureSetType(val screenCode: Int, val resourceId: Int) { +enum class FeatureSetType( + val screenCode: Int, + val resourceId: Int, +) { COMPLETE(0, R.string.ui_feature_set_type_complete), SIMPLIFIED(1, R.string.ui_feature_set_type_simplified), + PERFORMANCE(2, R.string.ui_feature_set_type_performance), } -fun parseConnectivityType(code: Boolean?): ConnectivityType { - return when (code) { +fun parseConnectivityType(code: Boolean?): ConnectivityType = + when (code) { ConnectivityType.ALWAYS.prefCode -> ConnectivityType.ALWAYS ConnectivityType.WIFI_ONLY.prefCode -> ConnectivityType.WIFI_ONLY ConnectivityType.NEVER.prefCode -> ConnectivityType.NEVER @@ -74,10 +84,9 @@ fun parseConnectivityType(code: Boolean?): ConnectivityType { ConnectivityType.ALWAYS } } -} -fun parseConnectivityType(screenCode: Int): ConnectivityType { - return when (screenCode) { +fun parseConnectivityType(screenCode: Int): ConnectivityType = + when (screenCode) { ConnectivityType.ALWAYS.screenCode -> ConnectivityType.ALWAYS ConnectivityType.WIFI_ONLY.screenCode -> ConnectivityType.WIFI_ONLY ConnectivityType.NEVER.screenCode -> ConnectivityType.NEVER @@ -85,39 +94,40 @@ fun parseConnectivityType(screenCode: Int): ConnectivityType { ConnectivityType.ALWAYS } } -} -fun parseFeatureSetType(screenCode: Int): FeatureSetType { - return when (screenCode) { +fun parseFeatureSetType(screenCode: Int): FeatureSetType = + when (screenCode) { FeatureSetType.COMPLETE.screenCode -> FeatureSetType.COMPLETE FeatureSetType.SIMPLIFIED.screenCode -> FeatureSetType.SIMPLIFIED + FeatureSetType.PERFORMANCE.screenCode -> FeatureSetType.PERFORMANCE else -> { FeatureSetType.COMPLETE } } -} -enum class BooleanType(val prefCode: Boolean?, val screenCode: Int, val reourceId: Int) { +enum class BooleanType( + val prefCode: Boolean?, + val screenCode: Int, + val reourceId: Int, +) { ALWAYS(null, 0, R.string.connectivity_type_always), NEVER(false, 1, R.string.connectivity_type_never), } -fun parseBooleanType(code: Boolean?): BooleanType { - return when (code) { +fun parseBooleanType(code: Boolean?): BooleanType = + when (code) { BooleanType.ALWAYS.prefCode -> BooleanType.ALWAYS BooleanType.NEVER.prefCode -> BooleanType.NEVER else -> { BooleanType.ALWAYS } } -} -fun parseBooleanType(screenCode: Int): BooleanType { - return when (screenCode) { +fun parseBooleanType(screenCode: Int): BooleanType = + when (screenCode) { BooleanType.ALWAYS.screenCode -> BooleanType.ALWAYS BooleanType.NEVER.screenCode -> BooleanType.NEVER else -> { BooleanType.ALWAYS } } -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt new file mode 100644 index 0000000000..145dcd44f4 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.actions + +import androidx.compose.animation.Crossfade +import androidx.compose.animation.core.FiniteAnimationSpec +import androidx.compose.animation.core.tween +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.vitorpamplona.amethyst.model.FeatureSetType +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel + +@Composable +fun CrossfadeIfEnabled( + targetState: T, + modifier: Modifier = Modifier, + animationSpec: FiniteAnimationSpec = tween(), + label: String = "Crossfade", + accountViewModel: AccountViewModel, + content: @Composable (T) -> Unit, +) { + if (accountViewModel.settings.featureSet == FeatureSetType.PERFORMANCE) { + content(targetState) + } else { + Crossfade(targetState, modifier, animationSpec, label, content) + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt index 4cda055f4b..373b28c438 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt @@ -73,6 +73,7 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource @@ -331,11 +332,6 @@ private fun RenderSearchResults( val users by searchBarViewModel.searchResultsUsers.collectAsStateWithLifecycle() val channels by searchBarViewModel.searchResultsChannels.collectAsStateWithLifecycle() - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - Row( modifier = Modifier @@ -367,7 +363,11 @@ private fun RenderSearchResults( channels, key = { _, item -> "c" + item.idHex }, ) { _, item -> - RenderChannel(item, automaticallyShowProfilePicture) { + RenderChannel( + item, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, + ) { nav("Channel/${item.idHex}") searchBarViewModel.clear() } @@ -385,6 +385,7 @@ private fun RenderSearchResults( private fun RenderChannel( item: com.vitorpamplona.amethyst.model.Channel, loadProfilePicture: Boolean, + loadRobohash: Boolean, onClick: () -> Unit, ) { val hasNewMessages = remember { mutableStateOf(false) } @@ -403,6 +404,7 @@ private fun RenderChannel( hasNewMessages, onClick = onClick, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) } @@ -414,14 +416,15 @@ fun UserComposeForChat( ) { Row( modifier = - Modifier.clickable( - onClick = onClick, - ).padding( - start = 12.dp, - end = 12.dp, - top = 10.dp, - bottom = 10.dp, - ), + Modifier + .clickable( + onClick = onClick, + ).padding( + start = 12.dp, + end = 12.dp, + top = 10.dp, + bottom = 10.dp, + ), verticalAlignment = Alignment.CenterVertically, ) { ClickableUserPicture(baseUser, Size55dp, accountViewModel) @@ -432,7 +435,7 @@ fun UserComposeForChat( .padding(start = 10.dp) .weight(1f), ) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser, accountViewModel = accountViewModel) } DisplayUserAboutInfo(baseUser) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 0cfe1e6e3d..225f63b40c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -324,8 +324,7 @@ fun NewPostView( top = pad.calculateTopPadding(), end = Size10dp, bottom = pad.calculateBottomPadding(), - ) - .fillMaxSize(), + ).fillMaxSize(), ) { Column( modifier = @@ -676,8 +675,7 @@ private fun MessageField(postViewModel: NewPostViewModel) { width = 1.dp, color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(8.dp), - ) - .focusRequester(focusRequester) + ).focusRequester(focusRequester) .onFocusChanged { if (it.isFocused) { keyboardController?.show() @@ -1130,7 +1128,7 @@ fun FowardZapTo( Spacer(modifier = DoubleHorzSpacer) Column(modifier = Modifier.weight(1f)) { - UsernameDisplay(splitItem.key) + UsernameDisplay(splitItem.key, accountViewModel = accountViewModel) Text( text = String.format("%.0f%%", splitItem.percentage * 100), maxLines = 1, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt index 045421fd63..89f40a14c0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoClickableRow.kt @@ -46,6 +46,7 @@ import com.vitorpamplona.amethyst.ui.theme.largeRelayIconModifier fun BasicRelaySetupInfoClickableRow( item: BasicRelaySetupInfo, loadProfilePicture: Boolean, + loadRobohash: Boolean, onDelete: (BasicRelaySetupInfo) -> Unit, onClick: () -> Unit, accountViewModel: AccountViewModel, @@ -65,6 +66,7 @@ fun BasicRelaySetupInfoClickableRow( item.briefInfo.displayUrl, iconUrlFromRelayInfoDoc ?: item.briefInfo.favIcon, loadProfilePicture, + loadRobohash, MaterialTheme.colorScheme.largeRelayIconModifier, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt index 5a4c8069ea..3bd774fb7b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt @@ -27,6 +27,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog @@ -52,14 +53,10 @@ fun BasicRelaySetupInfoDialog( ) } - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - BasicRelaySetupInfoClickableRow( item = item, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, onDelete = onDelete, accountViewModel = accountViewModel, onClick = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt index 6eeae17168..f6199fc5be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt @@ -67,6 +67,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11Retriever @@ -146,6 +147,7 @@ fun LazyListScope.renderKind3Items( fun ServerConfigPreview() { ClickableRelayItem( loadProfilePicture = true, + loadRobohash = false, item = Kind3BasicRelaySetupInfo( url = "nostr.mom", @@ -200,14 +202,10 @@ fun LoadRelayInfo( ) } - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - ClickableRelayItem( item = item, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, onToggleDownload = onToggleDownload, onToggleUpload = onToggleUpload, onToggleFollows = onToggleFollows, @@ -268,6 +266,7 @@ fun LoadRelayInfo( fun ClickableRelayItem( item: Kind3BasicRelaySetupInfo, loadProfilePicture: Boolean, + loadRobohash: Boolean, onToggleDownload: (Kind3BasicRelaySetupInfo) -> Unit, onToggleUpload: (Kind3BasicRelaySetupInfo) -> Unit, onToggleFollows: (Kind3BasicRelaySetupInfo) -> Unit, @@ -293,6 +292,7 @@ fun ClickableRelayItem( item.briefInfo.displayUrl, iconUrlFromRelayInfoDoc ?: item.briefInfo.favIcon, loadProfilePicture, + loadRobohash, MaterialTheme.colorScheme.largeRelayIconModifier, ) } @@ -348,17 +348,18 @@ private fun StatusRow( imageVector = Icons.Default.Download, contentDescription = stringResource(R.string.read_from_relay), modifier = - Modifier.size(15.dp) + Modifier + .size(15.dp) .combinedClickable( onClick = { onToggleDownload(item) }, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.read_from_relay), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.read_from_relay), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -384,17 +385,18 @@ private fun StatusRow( imageVector = Icons.Default.Upload, stringResource(R.string.write_to_relay), modifier = - Modifier.size(15.dp) + Modifier + .size(15.dp) .combinedClickable( onClick = { onToggleUpload(item) }, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.write_to_relay), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.write_to_relay), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -420,17 +422,18 @@ private fun StatusRow( imageVector = Icons.Default.SyncProblem, stringResource(R.string.errors), modifier = - Modifier.size(15.dp) + Modifier + .size(15.dp) .combinedClickable( onClick = {}, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.errors), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.errors), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -454,17 +457,18 @@ private fun StatusRow( imageVector = Icons.Default.DeleteSweep, stringResource(R.string.spam), modifier = - Modifier.size(15.dp) + Modifier + .size(15.dp) .combinedClickable( onClick = {}, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.spam), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.spam), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -514,18 +518,19 @@ private fun ActiveToggles( painterResource(R.drawable.ic_home), stringResource(R.string.home_feed), modifier = - Modifier.padding(horizontal = 5.dp) + Modifier + .padding(horizontal = 5.dp) .size(15.dp) .combinedClickable( onClick = { onToggleFollows(item) }, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.home_feed), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.home_feed), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -547,18 +552,19 @@ private fun ActiveToggles( painterResource(R.drawable.ic_dm), stringResource(R.string.private_message_feed), modifier = - Modifier.padding(horizontal = 5.dp) + Modifier + .padding(horizontal = 5.dp) .size(15.dp) .combinedClickable( onClick = { onTogglePrivateDMs(item) }, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.private_message_feed), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.private_message_feed), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -580,18 +586,19 @@ private fun ActiveToggles( imageVector = Icons.Default.Groups, contentDescription = stringResource(R.string.public_chat_feed), modifier = - Modifier.padding(horizontal = 5.dp) + Modifier + .padding(horizontal = 5.dp) .size(15.dp) .combinedClickable( onClick = { onTogglePublicChats(item) }, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.public_chat_feed), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.public_chat_feed), + Toast.LENGTH_SHORT, + ).show() } }, ), @@ -613,18 +620,19 @@ private fun ActiveToggles( imageVector = Icons.Default.Public, stringResource(R.string.global_feed), modifier = - Modifier.padding(horizontal = 5.dp) + Modifier + .padding(horizontal = 5.dp) .size(15.dp) .combinedClickable( onClick = { onToggleGlobal(item) }, onLongClick = { scope.launch { - Toast.makeText( - context, - context.getString(R.string.global_feed), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + context.getString(R.string.global_feed), + Toast.LENGTH_SHORT, + ).show() } }, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt index 7ccc0cc448..695e477478 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.actions.relays -import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -50,9 +49,11 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.relays.RelayStats import com.vitorpamplona.amethyst.ui.actions.CloseButton +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.ClickableEmail import com.vitorpamplona.amethyst.ui.components.ClickableUrl import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer @@ -81,12 +82,13 @@ fun RelayInformationDialog( ) { val messages = remember(relayBriefInfo) { - RelayStats.get(url = relayBriefInfo.url).messages.snapshot().values.sortedByDescending { it.time }.toImmutableList() - } - - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value + RelayStats + .get(url = relayBriefInfo.url) + .messages + .snapshot() + .values + .sortedByDescending { it.time } + .toImmutableList() } Dialog( @@ -124,10 +126,11 @@ fun RelayInformationDialog( ) { Column { RenderRelayIcon( - relayBriefInfo.displayUrl, - relayInfo.icon ?: relayBriefInfo.favIcon, - automaticallyShowProfilePicture, - MaterialTheme.colorScheme.largeRelayIconModifier, + displayUrl = relayBriefInfo.displayUrl, + iconUrl = relayInfo.icon ?: relayBriefInfo.favIcon, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, + iconModifier = MaterialTheme.colorScheme.largeRelayIconModifier, ) } @@ -346,7 +349,7 @@ private fun DisplayOwnerInformation( nav: (String) -> Unit, ) { LoadUser(baseUserHex = userHex, accountViewModel) { - Crossfade(it) { + CrossfadeIfEnabled(it, accountViewModel = accountViewModel) { if (it != null) { UserCompose( baseUser = it, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt index 8a8daec0da..2ef53e03a0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.components import android.content.Context import android.content.Intent import android.net.Uri -import androidx.compose.animation.Crossfade import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -69,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.model.ThemeType import com.vitorpamplona.amethyst.service.CachedCashuProcessor import com.vitorpamplona.amethyst.service.CashuToken +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation import com.vitorpamplona.amethyst.ui.note.CashuIcon import com.vitorpamplona.amethyst.ui.note.CopyIcon @@ -106,7 +106,7 @@ fun CashuPreview( } } - Crossfade(targetState = cashuData, label = "CashuPreview") { + CrossfadeIfEnabled(targetState = cashuData, label = "CashuPreview", accountViewModel = accountViewModel) { when (it) { is GenericLoadable.Loaded -> CashuPreview(it.loaded, accountViewModel) is GenericLoadable.Error -> diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt index a46bddec4d..67258d71fc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import androidx.compose.animation.Crossfade import androidx.compose.foundation.text.ClickableText import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme @@ -35,21 +34,26 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextDirection import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.ui.note.payViaIntent +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.encoders.LnWithdrawalUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Composable -fun MayBeWithdrawal(lnurlWord: String) { +fun MayBeWithdrawal( + lnurlWord: String, + accountViewModel: AccountViewModel, +) { var lnWithdrawal by remember { mutableStateOf(null) } LaunchedEffect(key1 = lnurlWord) { launch(Dispatchers.IO) { lnWithdrawal = LnWithdrawalUtil.findWithdrawal(lnurlWord) } } - Crossfade(targetState = lnWithdrawal) { + CrossfadeIfEnabled(targetState = lnWithdrawal, accountViewModel = accountViewModel) { if (it != null) { ClickableWithdrawal(withdrawalString = it) } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt new file mode 100644 index 0000000000..ab6cabd43b --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ForwardingPainter.kt @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.components + +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.DefaultAlpha +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.painter.Painter + +/** + * Create and return a new [Painter] that wraps [painter] with its [alpha], [colorFilter], or [onDraw] overwritten. + */ +fun forwardingPainter( + painter: Painter, + alpha: Float = DefaultAlpha, + colorFilter: ColorFilter? = null, + onDraw: DrawScope.(ForwardingDrawInfo) -> Unit = DefaultOnDraw, +): Painter = ForwardingPainter(painter, alpha, colorFilter, onDraw) + +data class ForwardingDrawInfo( + val painter: Painter, + val alpha: Float, + val colorFilter: ColorFilter?, +) + +private class ForwardingPainter( + private val painter: Painter, + private var alpha: Float, + private var colorFilter: ColorFilter?, + private val onDraw: DrawScope.(ForwardingDrawInfo) -> Unit, +) : Painter() { + private var info = newInfo() + + override val intrinsicSize get() = painter.intrinsicSize + + override fun applyAlpha(alpha: Float): Boolean { + if (alpha != DefaultAlpha) { + this.alpha = alpha + this.info = newInfo() + } + return true + } + + override fun applyColorFilter(colorFilter: ColorFilter?): Boolean { + if (colorFilter == null) { + this.colorFilter = colorFilter + this.info = newInfo() + } + return true + } + + override fun DrawScope.onDraw() = onDraw(info) + + private fun newInfo() = ForwardingDrawInfo(painter, alpha, colorFilter) +} + +private val DefaultOnDraw: DrawScope.(ForwardingDrawInfo) -> Unit = { info -> + with(info.painter) { + draw(size, info.alpha, info.colorFilter) + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt index f7cc281c5b..623c66991a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import androidx.compose.animation.Crossfade import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -54,8 +53,10 @@ import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.hashtags.Lightning import com.vitorpamplona.amethyst.service.lnurl.CachedLnInvoiceParser import com.vitorpamplona.amethyst.service.lnurl.InvoiceAmount +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.ui.note.payViaIntent +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -82,9 +83,12 @@ fun LoadValueFromInvoice( } @Composable -fun MayBeInvoicePreview(lnbcWord: String) { +fun MayBeInvoicePreview( + lnbcWord: String, + accountViewModel: AccountViewModel, +) { LoadValueFromInvoice(lnbcWord = lnbcWord) { invoiceAmount -> - Crossfade(targetState = invoiceAmount, label = "MayBeInvoicePreview") { + CrossfadeIfEnabled(targetState = invoiceAmount, label = "MayBeInvoicePreview", accountViewModel = accountViewModel) { if (it != null) { InvoicePreview(it.invoice, it.amount) } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt index 2d91cab5c5..70a6f97e1f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt @@ -20,8 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import androidx.compose.animation.Crossfade -import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -30,6 +28,7 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.model.UrlCachedPreviewer +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding @@ -55,10 +54,10 @@ fun LoadUrlPreview( } } - Crossfade( + CrossfadeIfEnabled( targetState = urlPreviewState, - animationSpec = tween(durationMillis = 100), label = "UrlPreview", + accountViewModel = accountViewModel, ) { state -> when (state) { is UrlPreviewState.Loaded -> { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 7bcb049923..bfad6b30b1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import androidx.compose.animation.Crossfade import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -86,6 +85,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.checkForHashtagWithIcon import com.vitorpamplona.amethyst.service.CachedRichTextParser +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown import com.vitorpamplona.amethyst.ui.note.LoadUser import com.vitorpamplona.amethyst.ui.note.NoteCompose @@ -103,15 +103,14 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob -fun isMarkdown(content: String): Boolean { - return content.startsWith("> ") || +fun isMarkdown(content: String): Boolean = + content.startsWith("> ") || content.startsWith("# ") || content.contains("##") || content.contains("__") || content.contains("**") || content.contains("```") || content.contains("](") -} @Composable fun RichTextViewer( @@ -172,8 +171,8 @@ fun RenderRegularPreview() { // is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel) // is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, accountViewModel) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) - is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) - is WithdrawSegment -> MayBeWithdrawal(word.segmentText) + // is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) + // is WithdrawSegment -> MayBeWithdrawal(word.segmentText) // is CashuSegment -> CashuPreview(word.segmentText, accountViewModel) is EmailSegment -> ClickableEmail(word.segmentText) is PhoneSegment -> ClickablePhone(word.segmentText) @@ -209,8 +208,8 @@ fun RenderRegularPreview2() { // is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel) // is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, accountViewModel) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) - is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) - is WithdrawSegment -> MayBeWithdrawal(word.segmentText) + // is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) + // is WithdrawSegment -> MayBeWithdrawal(word.segmentText) // is CashuSegment -> CashuPreview(word.segmentText, accountViewModel) is EmailSegment -> ClickableEmail(word.segmentText) is PhoneSegment -> ClickablePhone(word.segmentText) @@ -270,8 +269,8 @@ fun RenderRegularPreview3() { // is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel) is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, null, accountViewModel) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) - is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) - is WithdrawSegment -> MayBeWithdrawal(word.segmentText) + // is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) + // is WithdrawSegment -> MayBeWithdrawal(word.segmentText) // is CashuSegment -> CashuPreview(word.segmentText, accountViewModel) is EmailSegment -> ClickableEmail(word.segmentText) is PhoneSegment -> ClickablePhone(word.segmentText) @@ -424,8 +423,8 @@ private fun RenderWordWithPreview( is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel) is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, callbackUri, accountViewModel) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) - is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) - is WithdrawSegment -> MayBeWithdrawal(word.segmentText) + is InvoiceSegment -> MayBeInvoicePreview(word.segmentText, accountViewModel) + is WithdrawSegment -> MayBeWithdrawal(word.segmentText, accountViewModel) is CashuSegment -> CashuPreview(word.segmentText, accountViewModel) is EmailSegment -> ClickableEmail(word.segmentText) is PhoneSegment -> ClickablePhone(word.segmentText) @@ -598,7 +597,7 @@ fun TagLink( Text(text = word.segmentText) } else { Row { - DisplayUserFromTag(it, nav) + DisplayUserFromTag(it, accountViewModel, nav) word.extras?.let { Text(text = it) } @@ -683,11 +682,12 @@ private fun DisplayNoteFromTag( @Composable private fun DisplayUserFromTag( baseUser: User, + accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { val meta by baseUser.live().userMetadataInfo.observeAsState(baseUser.info) - Crossfade(targetState = meta, label = "DisplayUserFromTag") { + CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag", accountViewModel = accountViewModel) { Row { CreateClickableTextWithEmoji( clickablePart = remember(meta) { it?.bestName() ?: baseUser.pubkeyDisplayHex() }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt index b0cd257661..35aa692d3a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt @@ -24,11 +24,12 @@ import android.content.Context import android.graphics.BitmapFactory import android.net.Uri import androidx.compose.foundation.Image +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Face import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter @@ -51,6 +52,7 @@ import coil.request.Options import com.vitorpamplona.amethyst.commons.robohash.CachedRobohash import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.theme.isLight +import com.vitorpamplona.amethyst.ui.theme.onBackgroundColorFilter import java.util.Base64 @Composable @@ -58,19 +60,22 @@ fun RobohashAsyncImage( robot: String, modifier: Modifier = Modifier, contentDescription: String? = null, + loadRobohash: Boolean, ) { - val isLightTheme = MaterialTheme.colorScheme.isLight - - val robotPainter = - remember(robot) { - CachedRobohash.get(robot, isLightTheme) - } - - Image( - imageVector = robotPainter, - contentDescription = contentDescription, - modifier = modifier, - ) + if (loadRobohash) { + Image( + imageVector = CachedRobohash.get(robot, MaterialTheme.colorScheme.isLight), + contentDescription = contentDescription, + modifier = modifier, + ) + } else { + Image( + imageVector = Icons.Default.Face, + contentDescription = contentDescription, + colorFilter = MaterialTheme.colorScheme.onBackgroundColorFilter, + modifier = modifier, + ) + } } @Composable @@ -85,6 +90,7 @@ fun RobohashFallbackAsyncImage( colorFilter: ColorFilter? = null, filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, loadProfilePicture: Boolean, + loadRobohash: Boolean, ) { if (model != null && loadProfilePicture) { val isBase64 = model.startsWith("data:image/jpeg;base64,") @@ -106,9 +112,20 @@ fun RobohashFallbackAsyncImage( ) } else { val painter = - rememberVectorPainter( - image = CachedRobohash.get(robot, MaterialTheme.colorScheme.isLight), - ) + if (loadRobohash) { + rememberVectorPainter( + image = CachedRobohash.get(robot, MaterialTheme.colorScheme.isLight), + ) + } else { + forwardingPainter( + painter = + rememberVectorPainter( + image = Icons.Default.Face, + ), + colorFilter = MaterialTheme.colorScheme.onBackgroundColorFilter, + alpha = 0.5f, + ) + } AsyncImage( model = model, @@ -125,16 +142,25 @@ fun RobohashFallbackAsyncImage( ) } } else { - val robotPainter = CachedRobohash.get(robot, MaterialTheme.colorScheme.isLight) - - Image( - imageVector = robotPainter, - contentDescription = contentDescription, - modifier = modifier, - alignment = alignment, - contentScale = contentScale, - colorFilter = colorFilter, - ) + if (loadRobohash) { + Image( + imageVector = CachedRobohash.get(robot, MaterialTheme.colorScheme.isLight), + contentDescription = contentDescription, + modifier = modifier, + alignment = alignment, + contentScale = contentScale, + colorFilter = colorFilter, + ) + } else { + Image( + imageVector = Icons.Default.Face, + contentDescription = contentDescription, + colorFilter = MaterialTheme.colorScheme.onBackgroundColorFilter, + modifier = modifier, + alignment = alignment, + contentScale = contentScale, + ) + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt index fd19d837dd..5d8dedc8dd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -54,6 +53,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding @@ -102,7 +102,7 @@ fun SensitivityWarning( var showContentWarningNote by remember(accountState) { mutableStateOf(accountState?.account?.showSensitiveContent != true) } - Crossfade(targetState = showContentWarningNote) { + CrossfadeIfEnabled(targetState = showContentWarningNote, accountViewModel = accountViewModel) { if (it) { ContentWarningNote { showContentWarningNote = false } } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt index 4114a82091..b8d251b462 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt @@ -64,6 +64,7 @@ import androidx.compose.ui.window.DialogProperties import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji @@ -191,12 +192,11 @@ fun DisplayAccount( .width(55.dp) .padding(0.dp), ) { - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - - AccountPicture(it, automaticallyShowProfilePicture) + AccountPicture( + it, + accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, + ) } Spacer(modifier = Modifier.width(16.dp)) Column(modifier = Modifier.weight(1f)) { AccountName(acc, it) } @@ -232,6 +232,7 @@ private fun ActiveMarker( private fun AccountPicture( user: User, loadProfilePicture: Boolean, + loadRobohash: Boolean, ) { val profilePicture by user.live().profilePictureChanges.observeAsState() @@ -241,6 +242,7 @@ private fun AccountPicture( contentDescription = stringResource(R.string.profile_image), modifier = AccountPictureModifier, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index 9fca1d6ff0..7406e60e94 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -41,7 +41,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandMore -import androidx.compose.material3.DrawerState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -58,7 +57,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -81,6 +79,7 @@ import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.AddressableNote +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS import com.vitorpamplona.amethyst.model.KIND3_FOLLOWS import com.vitorpamplona.amethyst.model.LocalCache @@ -154,13 +153,12 @@ import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest -import kotlinx.coroutines.launch @Composable fun AppTopBar( followLists: FollowListViewModel, navEntryState: State, - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, navPopBack: () -> Unit, @@ -180,7 +178,7 @@ fun AppTopBar( derivedStateOf { navEntryState.value?.arguments?.getString("id") } } - RenderTopRouteBar(currentRoute, id, followLists, drawerState, accountViewModel, nav, navPopBack) + RenderTopRouteBar(currentRoute, id, followLists, openDrawer, accountViewModel, nav, navPopBack) } @Composable @@ -188,16 +186,16 @@ private fun RenderTopRouteBar( currentRoute: String?, id: String?, followLists: FollowListViewModel, - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, navPopBack: () -> Unit, ) { when (currentRoute) { - Route.Home.base -> HomeTopBar(followLists, drawerState, accountViewModel, nav) - Route.Video.base -> StoriesTopBar(followLists, drawerState, accountViewModel, nav) - Route.Discover.base -> DiscoveryTopBar(followLists, drawerState, accountViewModel, nav) - Route.Notification.base -> NotificationTopBar(followLists, drawerState, accountViewModel, nav) + Route.Home.base -> HomeTopBar(followLists, openDrawer, accountViewModel, nav) + Route.Video.base -> StoriesTopBar(followLists, openDrawer, accountViewModel, nav) + Route.Discover.base -> DiscoveryTopBar(followLists, openDrawer, accountViewModel, nav) + Route.Notification.base -> NotificationTopBar(followLists, openDrawer, accountViewModel, nav) Route.Settings.base -> TopBarWithBackButton(stringResource(id = R.string.application_preferences), navPopBack) Route.Bookmarks.base -> TopBarWithBackButton(stringResource(id = R.string.bookmarks), navPopBack) Route.Drafts.base -> TopBarWithBackButton(stringResource(id = R.string.drafts), navPopBack) @@ -213,10 +211,10 @@ private fun RenderTopRouteBar( Route.Geohash.base -> GeoHashTopBar(id, accountViewModel, navPopBack) Route.Note.base -> ThreadTopBar(id, accountViewModel, navPopBack) Route.ContentDiscovery.base -> DvmTopBar(id, accountViewModel, nav, navPopBack) - else -> MainTopBar(drawerState, accountViewModel, nav) + else -> MainTopBar(openDrawer, accountViewModel, nav) } } else { - MainTopBar(drawerState, accountViewModel, nav) + MainTopBar(openDrawer, accountViewModel, nav) } } } @@ -381,7 +379,7 @@ private fun RenderRoomTopBar( Spacer(modifier = DoubleHorzSpacer) - UsernameDisplay(baseUser, Modifier.weight(1f), fontWeight = FontWeight.Normal) + UsernameDisplay(baseUser, Modifier.weight(1f), fontWeight = FontWeight.Normal, accountViewModel = accountViewModel) } } }, @@ -413,7 +411,7 @@ private fun RenderRoomTopBar( .padding(start = 10.dp) .weight(1f), fontWeight = FontWeight.Normal, - accountViewModel.userProfile(), + accountViewModel, ) }, extendableRow = { @@ -452,11 +450,11 @@ private fun ChannelTopBar( @Composable fun StoriesTopBar( followLists: FollowListViewModel, - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - GenericMainTopBar(drawerState, accountViewModel, nav) { + GenericMainTopBar(openDrawer, accountViewModel, nav) { val list by accountViewModel.account.defaultStoriesFollowList.collectAsStateWithLifecycle() FollowListWithRoutes( @@ -471,11 +469,11 @@ fun StoriesTopBar( @Composable fun HomeTopBar( followLists: FollowListViewModel, - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - GenericMainTopBar(drawerState, accountViewModel, nav) { + GenericMainTopBar(openDrawer, accountViewModel, nav) { val list by accountViewModel.account.defaultHomeFollowList.collectAsStateWithLifecycle() FollowListWithRoutes( @@ -494,11 +492,11 @@ fun HomeTopBar( @Composable fun NotificationTopBar( followLists: FollowListViewModel, - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - GenericMainTopBar(drawerState, accountViewModel, nav) { + GenericMainTopBar(openDrawer, accountViewModel, nav) { val list by accountViewModel.account.defaultNotificationFollowList.collectAsStateWithLifecycle() FollowListWithoutRoutes( @@ -513,11 +511,11 @@ fun NotificationTopBar( @Composable fun DiscoveryTopBar( followLists: FollowListViewModel, - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - GenericMainTopBar(drawerState, accountViewModel, nav) { + GenericMainTopBar(openDrawer, accountViewModel, nav) { val list by accountViewModel.account.defaultDiscoveryFollowList.collectAsStateWithLifecycle() FollowListWithoutRoutes( @@ -531,17 +529,17 @@ fun DiscoveryTopBar( @Composable fun MainTopBar( - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - GenericMainTopBar(drawerState, accountViewModel, nav) { AmethystClickableIcon() } + GenericMainTopBar(openDrawer, accountViewModel, nav) { AmethystClickableIcon() } } @OptIn(ExperimentalMaterial3Api::class) @Composable fun GenericMainTopBar( - drawerState: DrawerState, + openDrawer: () -> Unit, accountViewModel: AccountViewModel, nav: (String) -> Unit, content: @Composable () -> Unit, @@ -558,8 +556,7 @@ fun GenericMainTopBar( } }, navigationIcon = { - val coroutineScope = rememberCoroutineScope() - LoggedInUserPictureDrawer(accountViewModel) { coroutineScope.launch { drawerState.open() } } + LoggedInUserPictureDrawer(accountViewModel, openDrawer) }, actions = { SearchButton { nav(Route.Search.route) } }, ) @@ -596,6 +593,7 @@ private fun LoggedInUserPictureDrawer( modifier = HeaderPictureModifier, contentScale = ContentScale.Crop, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 8eb7f42ef2..17a6c102be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -86,6 +86,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.relays.RelayPool import com.vitorpamplona.amethyst.service.relays.RelayPoolStatus @@ -131,11 +132,6 @@ fun DrawerContent( Unit } - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - ModalDrawerSheet( drawerContainerColor = MaterialTheme.colorScheme.background, drawerTonalElevation = 0.dp, @@ -174,7 +170,8 @@ fun DrawerContent( BottomContent( accountViewModel.account.userProfile(), drawerState, - automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, nav, ) } @@ -243,6 +240,7 @@ fun ProfileContentTemplate( .border(3.dp, MaterialTheme.colorScheme.background, CircleShape) .clickable(onClick = onClick), loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) if (bestDisplayName != null) { @@ -746,6 +744,7 @@ fun BottomContent( user: User, drawerState: DrawerState, loadProfilePicture: Boolean, + loadRobohash: Boolean, nav: (String) -> Unit, ) { val coroutineScope = rememberCoroutineScope() @@ -804,6 +803,7 @@ fun BottomContent( ShowQRDialog( user, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, onScan = { dialogOpen = false coroutineScope.launch { drawerState.close() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index bf2a687782..986f2fd6ca 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note -import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -68,6 +67,7 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ParticipantListBuilder import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.ui.note.elements.BannerImage @@ -472,7 +472,7 @@ fun RenderLiveActivityThumb( } ?: run { DisplayAuthorBanner(baseNote) } Box(Modifier.padding(10.dp)) { - Crossfade(targetState = card.status, label = "RenderLiveActivityThumb") { + CrossfadeIfEnabled(targetState = card.status, label = "RenderLiveActivityThumb", accountViewModel = accountViewModel) { when (it) { STATUS_LIVE -> { val url = card.media diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt index 61501fbd6b..5c0b685d54 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note -import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -61,8 +60,10 @@ import androidx.lifecycle.map import com.patrykandpatrick.vico.core.extension.forEachIndexedExtended import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Channel +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.layouts.ChatHeaderLayout @@ -136,7 +137,7 @@ private fun ChatroomPrivateMessages( } } - Crossfade(userRoom, label = "ChatroomPrivateMessages") { room -> + CrossfadeIfEnabled(userRoom, label = "ChatroomPrivateMessages", accountViewModel = accountViewModel) { room -> if (room != null) { UserRoomCompose(baseNote, room, accountViewModel, nav) } else { @@ -191,11 +192,6 @@ private fun ChannelRoomCompose( val hasNewMessages = remember { mutableStateOf(false) } - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - WatchNotificationChanges(note, route, accountViewModel) { newHasNewMessages -> if (hasNewMessages.value != newHasNewMessages) { hasNewMessages.value = newHasNewMessages @@ -209,7 +205,8 @@ private fun ChannelRoomCompose( channelLastTime = remember(note) { note.createdAt() }, channelLastContent = remember(note, authorState) { "$authorName: $description" }, hasNewMessages = hasNewMessages, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, onClick = { nav(route) }, ) } @@ -305,7 +302,7 @@ fun RoomNameDisplay( .distinctUntilChanged() .observeAsState(accountViewModel.userProfile().privateChatrooms[room]?.subject) - Crossfade(targetState = roomSubject, modifier, label = "RoomNameDisplay") { + CrossfadeIfEnabled(targetState = roomSubject, modifier, label = "RoomNameDisplay", accountViewModel = accountViewModel) { if (!it.isNullOrBlank()) { if (room.users.size > 1) { DisplayRoomSubject(it) @@ -337,7 +334,7 @@ private fun DisplayUserAndSubject( maxLines = 1, ) LoadUser(baseUserHex = user, accountViewModel = accountViewModel) { - it?.let { UsernameDisplay(it, Modifier.weight(1f)) } + it?.let { UsernameDisplay(it, Modifier.weight(1f), accountViewModel = accountViewModel) } } } } @@ -354,14 +351,14 @@ fun DisplayUserSetAsSubject( // Regular Design Row { LoadUser(baseUserHex = userList[0], accountViewModel) { - it?.let { UsernameDisplay(it, Modifier.weight(1f), fontWeight = fontWeight) } + it?.let { UsernameDisplay(it, Modifier.weight(1f), fontWeight = fontWeight, accountViewModel = accountViewModel) } } } } else { Row { userList.take(4).forEachIndexedExtended { index, isFirst, isLast, value -> LoadUser(baseUserHex = value, accountViewModel) { - it?.let { ShortUsernameDisplay(baseUser = it, fontWeight = fontWeight) } + it?.let { ShortUsernameDisplay(baseUser = it, fontWeight = fontWeight, accountViewModel = accountViewModel) } } if (!isLast) { @@ -395,6 +392,7 @@ fun ShortUsernameDisplay( baseUser: User, weight: Modifier = Modifier, fontWeight: FontWeight = FontWeight.Bold, + accountViewModel: AccountViewModel, ) { val userName by baseUser @@ -404,7 +402,7 @@ fun ShortUsernameDisplay( .distinctUntilChanged() .observeAsState(baseUser.toBestShortFirstName()) - Crossfade(targetState = userName, modifier = weight) { + CrossfadeIfEnabled(targetState = userName, modifier = weight, accountViewModel = accountViewModel) { CreateTextWithEmoji( text = it, tags = baseUser.info?.tags, @@ -459,6 +457,7 @@ fun ChannelName( channelLastContent: String?, hasNewMessages: MutableState, loadProfilePicture: Boolean, + loadRobohash: Boolean, onClick: () -> Unit, ) { ChannelName( @@ -469,6 +468,7 @@ fun ChannelName( contentDescription = stringResource(R.string.channel_image), modifier = AccountPictureModifier, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) }, channelTitle, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index 4144b4b005..d508327e8d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -173,7 +173,7 @@ fun NormalChatNote( ChatBubbleLayout( isLoggedInUser = isLoggedInUser, innerQuote = innerQuote, - isSimplified = accountViewModel.settings.featureSet == FeatureSetType.SIMPLIFIED, + isComplete = accountViewModel.settings.featureSet == FeatureSetType.COMPLETE, hasDetailsToShow = note.zaps.isNotEmpty() || note.zapPayments.isNotEmpty() || note.reactions.isNotEmpty(), drawAuthorInfo = drawAuthorInfo, parentBackgroundColor = parentBackgroundColor, @@ -249,7 +249,7 @@ fun NormalChatNote( fun ChatBubbleLayout( isLoggedInUser: Boolean, innerQuote: Boolean, - isSimplified: Boolean, + isComplete: Boolean, hasDetailsToShow: Boolean, drawAuthorInfo: Boolean, parentBackgroundColor: MutableState? = null, @@ -300,10 +300,10 @@ fun ChatBubbleLayout( val showDetails = remember { mutableStateOf( - if (isSimplified) { - hasDetailsToShow - } else { + if (isComplete) { true + } else { + hasDetailsToShow }, ) } @@ -313,7 +313,7 @@ fun ChatBubbleLayout( Modifier.combinedClickable( onClick = { if (!onClick()) { - if (isSimplified) { + if (!isComplete) { showDetails.value = !showDetails.value } } @@ -376,7 +376,7 @@ private fun BubblePreview() { ChatBubbleLayout( isLoggedInUser = false, innerQuote = false, - isSimplified = false, + isComplete = true, hasDetailsToShow = true, drawAuthorInfo = true, parentBackgroundColor = backgroundBubbleColor, @@ -406,7 +406,7 @@ private fun BubblePreview() { ChatBubbleLayout( isLoggedInUser = true, innerQuote = false, - isSimplified = false, + isComplete = true, hasDetailsToShow = true, drawAuthorInfo = true, parentBackgroundColor = backgroundBubbleColor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index 0ade7e95a7..958c5e525f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -59,6 +59,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.amethyst.model.User @@ -493,7 +494,7 @@ private fun BoxedAuthor( accountViewModel: AccountViewModel, ) { Box(modifier = Size35Modifier.clickable(onClick = { nav(authorRouteFor(note)) })) { - WatchAuthorWithBlank(note, Size35Modifier) { author -> + WatchAuthorWithBlank(note, Size35Modifier, accountViewModel) { author -> WatchUserMetadataAndFollowsAndRenderUserProfilePictureOrDefaultAuthor( author, accountViewModel, @@ -510,7 +511,7 @@ fun WatchUserMetadataAndFollowsAndRenderUserProfilePictureOrDefaultAuthor( if (author != null) { WatchUserMetadataAndFollowsAndRenderUserProfilePicture(author, accountViewModel) } else { - DisplayBlankAuthor(Size35dp) + DisplayBlankAuthor(Size35dp, accountViewModel = accountViewModel) } } @@ -520,7 +521,6 @@ fun WatchUserMetadataAndFollowsAndRenderUserProfilePicture( accountViewModel: AccountViewModel, ) { WatchUserMetadata(author) { baseUserPicture -> - // Crossfade(targetState = baseUserPicture) { userPicture -> RobohashFallbackAsyncImage( robot = author.pubkeyHex, model = baseUserPicture, @@ -528,18 +528,16 @@ fun WatchUserMetadataAndFollowsAndRenderUserProfilePicture( modifier = MaterialTheme.colorScheme.profile35dpModifier, contentScale = ContentScale.Crop, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) - // } } WatchUserFollows(author.pubkeyHex, accountViewModel) { isFollowing -> - // Crossfade(targetState = isFollowing) { if (isFollowing) { Box(modifier = Size35Modifier, contentAlignment = Alignment.TopEnd) { FollowingIcon(Size10dp) } } - // } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index 3f34d409b8..5435d2f7dc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.hashtags.Tunestr import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.LoadStatuses @@ -132,10 +132,11 @@ fun ObserveDisplayNip05Status( val nip05 by baseUser.live().nip05Changes.observeAsState(baseUser.nip05()) LoadStatuses(baseUser, accountViewModel) { statuses -> - Crossfade( + CrossfadeIfEnabled( targetState = nip05, modifier = columnModifier, label = "ObserveDisplayNip05StatusCrossfade", + accountViewModel = accountViewModel, ) { VerifyAndDisplayNIP05OrStatusLine( it, @@ -165,11 +166,11 @@ private fun VerifyAndDisplayNIP05OrStatusLine( nip05VerificationAsAState(baseUser.info!!, baseUser.pubkeyHex, accountViewModel) if (nip05Verified.value != true) { - DisplayNIP05(nip05, nip05Verified) + DisplayNIP05(nip05, nip05Verified, accountViewModel) } else if (!statuses.isEmpty()) { RotateStatuses(statuses, accountViewModel, nav) } else { - DisplayNIP05(nip05, nip05Verified) + DisplayNIP05(nip05, nip05Verified, accountViewModel) } } else { if (!statuses.isEmpty()) { @@ -271,8 +272,7 @@ fun DisplayStatus( routeFor( note, accountViewModel.userProfile(), - ) - ?.let { nav(it) } + )?.let { nav(it) } }, ) { Icon( @@ -294,8 +294,7 @@ fun DisplayStatus( routeFor( it, accountViewModel.userProfile(), - ) - ?.let { nav(it) } + )?.let { nav(it) } }, ) { Icon( @@ -314,6 +313,7 @@ fun DisplayStatus( private fun DisplayNIP05( nip05: String, nip05Verified: MutableState, + accountViewModel: AccountViewModel, ) { val uri = LocalUriHandler.current val (user, domain) = @@ -336,7 +336,7 @@ private fun DisplayNIP05( ) } - NIP05VerifiedSymbol(nip05Verified, NIP05IconSize) + NIP05VerifiedSymbol(nip05Verified, NIP05IconSize, accountViewModel) ClickableText( text = remember(nip05) { AnnotatedString(domain) }, @@ -352,8 +352,9 @@ private fun DisplayNIP05( private fun NIP05VerifiedSymbol( nip05Verified: MutableState, modifier: Modifier, + accountViewModel: AccountViewModel, ) { - Crossfade(targetState = nip05Verified.value) { + CrossfadeIfEnabled(targetState = nip05Verified.value, accountViewModel = accountViewModel) { when (it) { null -> NIP05CheckingIcon(modifier = modifier) true -> NIP05VerifiedIcon(modifier = modifier) @@ -373,7 +374,7 @@ fun DisplayNip05ProfileStatus( if (nip05.split("@").size <= 2) { val nip05Verified = nip05VerificationAsAState(user.info!!, user.pubkeyHex, accountViewModel) Row(verticalAlignment = Alignment.CenterVertically) { - NIP05VerifiedSymbol(nip05Verified, Size16Modifier) + NIP05VerifiedSymbol(nip05Verified, Size16Modifier, accountViewModel) var domainPadStart = 5.dp val (user, domain) = diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 51107e4869..6a483e2e74 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -477,7 +477,7 @@ fun InnerNoteWithReactions( baseNote.event !is GenericRepostEvent && !isBoostedNote && !isQuotedNote && - accountViewModel.settings.featureSet != FeatureSetType.SIMPLIFIED + accountViewModel.settings.featureSet == FeatureSetType.COMPLETE NoteBody( baseNote = baseNote, showAuthorPicture = isQuotedNote, @@ -975,9 +975,9 @@ fun FirstUserInfoRow( if (showAuthorPicture) { NoteAuthorPicture(baseNote, nav, accountViewModel, Size25dp) Spacer(HalfPadding) - NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor) + NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor, accountViewModel = accountViewModel) } else { - NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor) + NoteUsernameDisplay(baseNote, Modifier.weight(1f), textColor = textColor, accountViewModel = accountViewModel) } if (isCommunityPost) { @@ -1064,7 +1064,7 @@ private fun BadgeBox( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - if (accountViewModel.settings.featureSet != FeatureSetType.SIMPLIFIED) { + if (accountViewModel.settings.featureSet == FeatureSetType.COMPLETE) { if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) { baseNote.replyTo?.lastOrNull()?.let { RelayBadges(it, accountViewModel, nav) } } else { @@ -1097,6 +1097,7 @@ private fun RenderAuthorImages( ChannelNotePicture( channel, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } } @@ -1107,6 +1108,7 @@ private fun RenderAuthorImages( private fun ChannelNotePicture( baseChannel: Channel, loadProfilePicture: Boolean, + loadRobohash: Boolean, ) { val model by baseChannel.live @@ -1121,6 +1123,7 @@ private fun ChannelNotePicture( contentDescription = stringResource(R.string.group_picture), modifier = MaterialTheme.colorScheme.channelNotePictureModifier, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 0d48b980ab..46f899148c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -24,7 +24,6 @@ import android.content.Context import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform -import androidx.compose.animation.Crossfade import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -98,8 +97,10 @@ import coil.compose.AsyncImage import coil.request.CachePolicy import coil.request.ImageRequest import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.ZapPaymentHandler +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.components.GenericLoadable import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer @@ -177,7 +178,7 @@ private fun InnerReactionRow( addPadding = addPadding, one = { WatchReactionsZapsBoostsAndDisplayIfExists(baseNote) { - RenderShowIndividualReactionsButton(wantsToSeeReactions) + RenderShowIndividualReactionsButton(wantsToSeeReactions, accountViewModel) } }, two = { @@ -377,14 +378,18 @@ fun LiveData.combineWith( } @Composable -private fun RenderShowIndividualReactionsButton(wantsToSeeReactions: MutableState) { +private fun RenderShowIndividualReactionsButton( + wantsToSeeReactions: MutableState, + accountViewModel: AccountViewModel, +) { IconButton( onClick = { wantsToSeeReactions.value = !wantsToSeeReactions.value }, modifier = Size20Modifier, ) { - Crossfade( + CrossfadeIfEnabled( targetState = wantsToSeeReactions.value, label = "RenderShowIndividualReactionsButton", + accountViewModel = accountViewModel, ) { if (it) { ExpandLessIcon(modifier = Size22Modifier, R.string.close_all_reactions_to_this_post) @@ -607,7 +612,7 @@ fun ReplyReaction( } if (showCounter) { - ReplyCounter(baseNote, grayTint) + ReplyCounter(baseNote, grayTint, accountViewModel) } } @@ -615,23 +620,29 @@ fun ReplyReaction( fun ReplyCounter( baseNote: Note, textColor: Color, + accountViewModel: AccountViewModel, ) { val repliesState by baseNote.live().replyCount.observeAsState(baseNote.replies.size) - SlidingAnimationCount(repliesState, textColor) + SlidingAnimationCount(repliesState, textColor, accountViewModel) } @Composable private fun SlidingAnimationCount( baseCount: Int, textColor: Color, + accountViewModel: AccountViewModel, ) { - AnimatedContent( - targetState = baseCount, - transitionSpec = AnimatedContentTransitionScope::transitionSpec, - label = "SlidingAnimationCount", - ) { count -> - TextCount(count, textColor) + if (accountViewModel.settings.featureSet == FeatureSetType.PERFORMANCE) { + TextCount(baseCount, textColor) + } else { + AnimatedContent( + targetState = baseCount, + transitionSpec = AnimatedContentTransitionScope::transitionSpec, + label = "SlidingAnimationCount", + ) { count -> + TextCount(count, textColor) + } } } @@ -669,18 +680,28 @@ fun TextCount( fun SlidingAnimationAmount( amount: String, textColor: Color, + accountViewModel: AccountViewModel, ) { - AnimatedContent( - targetState = amount, - transitionSpec = AnimatedContentTransitionScope::transitionSpec, - label = "SlidingAnimationAmount", - ) { count -> + if (accountViewModel.settings.featureSet == FeatureSetType.PERFORMANCE) { Text( - text = count, + text = amount, fontSize = Font14SP, color = textColor, maxLines = 1, ) + } else { + AnimatedContent( + targetState = amount, + transitionSpec = AnimatedContentTransitionScope::transitionSpec, + label = "SlidingAnimationAmount", + ) { count -> + Text( + text = count, + fontSize = Font14SP, + color = textColor, + maxLines = 1, + ) + } } } @@ -725,7 +746,7 @@ fun BoostReaction( } } - BoostText(baseNote, grayTint) + BoostText(baseNote, grayTint, accountViewModel) } @Composable @@ -752,10 +773,11 @@ fun ObserveBoostIcon( fun BoostText( baseNote: Note, grayTint: Color, + accountViewModel: AccountViewModel, ) { val boostState by baseNote.live().boostCount.observeAsState(baseNote.boosts.size) - SlidingAnimationCount(boostState, grayTint) + SlidingAnimationCount(boostState, grayTint, accountViewModel) } @OptIn(ExperimentalFoundationApi::class) @@ -792,7 +814,7 @@ fun LikeReaction( ), ) { ObserveLikeIcon(baseNote, accountViewModel) { reactionType -> - Crossfade(targetState = reactionType, label = "LikeIcon") { + CrossfadeIfEnabled(targetState = reactionType, label = "LikeIcon", accountViewModel = accountViewModel) { if (it != null) { RenderReactionType(it, heartSizeModifier, iconFontSize) } else { @@ -823,7 +845,7 @@ fun LikeReaction( } } - ObserveLikeText(baseNote) { reactionCount -> SlidingAnimationCount(reactionCount, grayTint) } + ObserveLikeText(baseNote) { reactionCount -> SlidingAnimationCount(reactionCount, grayTint, accountViewModel) } } @Composable @@ -1071,7 +1093,7 @@ fun ZapReaction( baseNote, accountViewModel, ) { wasZappedByLoggedInUser -> - Crossfade(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon") { + CrossfadeIfEnabled(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon", accountViewModel = accountViewModel) { if (it) { ZappedIcon(iconSizeModifier) } else { @@ -1083,7 +1105,7 @@ fun ZapReaction( } ObserveZapAmountText(baseNote, accountViewModel) { zapAmountTxt -> - SlidingAnimationAmount(zapAmountTxt, grayTint) + SlidingAnimationAmount(zapAmountTxt, grayTint, accountViewModel) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt index 893c142c6e..7f182de168 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note -import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -53,6 +52,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonBoxModifer import com.vitorpamplona.amethyst.ui.theme.Size17Modifier @@ -69,7 +69,7 @@ fun RelayBadges( ) { val expanded = remember { mutableStateOf(false) } - Crossfade(expanded.value, modifier = noteComposeRelayBox, label = "RelayBadges") { + CrossfadeIfEnabled(expanded.value, modifier = noteComposeRelayBox, label = "RelayBadges", accountViewModel = accountViewModel) { if (it) { RenderAllRelayList(baseNote, Modifier.fillMaxWidth(), accountViewModel = accountViewModel, nav = nav) } else { @@ -131,7 +131,7 @@ fun WatchAndRenderRelay( baseNote.relays.getOrNull(relayIndex), ) - Crossfade(targetState = noteRelays, label = "RenderRelay", modifier = Size17Modifier) { + CrossfadeIfEnabled(targetState = noteRelays, label = "RenderRelay", modifier = Size17Modifier, accountViewModel = accountViewModel) { if (it != null) { RenderRelay(it, accountViewModel, nav) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt index 7486e908e9..4dd5231a95 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11CachedRetriever @@ -178,6 +179,7 @@ fun RenderRelay( displayUrl = relay.displayUrl, iconUrl = relayInfo?.icon ?: relay.favIcon, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } } @@ -187,6 +189,7 @@ fun RenderRelayIcon( displayUrl: String, iconUrl: String?, loadProfilePicture: Boolean, + loadRobohash: Boolean, iconModifier: Modifier = MaterialTheme.colorScheme.relayIconModifier, ) { RobohashFallbackAsyncImage( @@ -196,5 +199,6 @@ fun RenderRelayIcon( colorFilter = RelayIconFilter, modifier = iconModifier, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt index 89ef9551f7..b6914a028d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt @@ -51,7 +51,7 @@ fun UserCompose( UserPicture(baseUser, Size55dp, accountViewModel = accountViewModel, nav = nav) Column(modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser, accountViewModel = accountViewModel) } AboutDisplay(baseUser) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt index 75c763c317..5b20bf188a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.unit.Dp import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage @@ -68,9 +69,9 @@ fun NoteAuthorPicture( modifier: Modifier = Modifier, onClick: ((User) -> Unit)? = null, ) { - WatchAuthorWithBlank(baseNote) { + WatchAuthorWithBlank(baseNote, accountViewModel = accountViewModel) { if (it == null) { - DisplayBlankAuthor(size, modifier) + DisplayBlankAuthor(size, modifier, accountViewModel) } else { ClickableUserPicture(it, size, accountViewModel, modifier, onClick) } @@ -81,6 +82,7 @@ fun NoteAuthorPicture( fun DisplayBlankAuthor( size: Dp, modifier: Modifier = Modifier, + accountViewModel: AccountViewModel, ) { val nullModifier = remember { @@ -91,6 +93,7 @@ fun DisplayBlankAuthor( robot = "authornotfound", contentDescription = stringResource(R.string.unknown_author), modifier = nullModifier, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } @@ -115,6 +118,7 @@ fun UserPicture( DisplayBlankAuthor( size, pictureModifier, + accountViewModel, ) } } @@ -350,6 +354,7 @@ fun InnerUserPicture( modifier = myImageModifier, contentScale = ContentScale.Crop, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt index 7f3db2f47b..b2c2084ce6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.note import android.content.Context import android.util.Log -import androidx.compose.animation.Crossfade import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -40,7 +39,9 @@ import androidx.lifecycle.LifecycleOwner import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.tts.TextToSpeechHelper +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.StdButtonSizeModifier import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.ImmutableListOfLists @@ -50,9 +51,10 @@ fun NoteUsernameDisplay( baseNote: Note, weight: Modifier = Modifier, textColor: Color = Color.Unspecified, + accountViewModel: AccountViewModel, ) { WatchAuthor(baseNote) { - UsernameDisplay(it, weight, textColor = textColor) + UsernameDisplay(it, weight, textColor = textColor, accountViewModel = accountViewModel) } } @@ -77,6 +79,7 @@ fun WatchAuthor( fun WatchAuthorWithBlank( baseNote: Note, modifier: Modifier = Modifier, + accountViewModel: AccountViewModel, inner: @Composable (User?) -> Unit, ) { val noteAuthor = baseNote.author @@ -85,7 +88,7 @@ fun WatchAuthorWithBlank( } else { val authorState by baseNote.live().metadata.observeAsState() - Crossfade(targetState = authorState?.note?.author, modifier = modifier, label = "WatchAuthorWithBlank") { newAuthor -> + CrossfadeIfEnabled(targetState = authorState?.note?.author, modifier = modifier, label = "WatchAuthorWithBlank", accountViewModel = accountViewModel) { newAuthor -> inner(newAuthor) } } @@ -97,10 +100,11 @@ fun UsernameDisplay( weight: Modifier = Modifier, fontWeight: FontWeight = FontWeight.Bold, textColor: Color = Color.Unspecified, + accountViewModel: AccountViewModel, ) { val userMetadata by baseUser.live().userMetadataInfo.observeAsState(baseUser.info) - Crossfade(targetState = userMetadata, modifier = weight, label = "UsernameDisplay") { + CrossfadeIfEnabled(targetState = userMetadata, modifier = weight, label = "UsernameDisplay", accountViewModel = accountViewModel) { val name = it?.bestName() if (name != null) { UserDisplay(name, it.tags, weight, fontWeight, textColor) @@ -164,7 +168,8 @@ private fun speak( context: Context, owner: LifecycleOwner, ) { - TextToSpeechHelper.getInstance(context) + TextToSpeechHelper + .getInstance(context) .registerLifecycle(owner) .speak(message) .highlight() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt index 06dc89eb7e..33db44e8b1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note -import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable import androidx.compose.runtime.Composable @@ -29,6 +28,7 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @OptIn(ExperimentalFoundationApi::class) @@ -57,6 +57,7 @@ fun WatchNoteEvent( ) } }, + accountViewModel = accountViewModel, ) } @@ -65,6 +66,7 @@ fun WatchNoteEvent( baseNote: Note, onNoteEventFound: @Composable () -> Unit, onBlank: @Composable () -> Unit, + accountViewModel: AccountViewModel, ) { if (baseNote.event != null) { onNoteEventFound() @@ -72,7 +74,7 @@ fun WatchNoteEvent( // avoid observing costs if already has an event. val hasEvent by baseNote.live().hasEvent.observeAsState(baseNote.event != null) - Crossfade(targetState = hasEvent, label = "Event presence") { + CrossfadeIfEnabled(targetState = hasEvent, label = "Event presence", accountViewModel = accountViewModel) { if (it) { onNoteEventFound() } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt index 84e592d7ad..cca7e1b874 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt @@ -102,13 +102,9 @@ class ZapOptionstViewModel : ViewModel() { this.account = account } - fun canSend(): Boolean { - return value() != null - } + fun canSend(): Boolean = value() != null - fun value(): Long? { - return customAmount.text.trim().toLongOrNull() - } + fun value(): Long? = customAmount.text.trim().toLongOrNull() fun cancel() {} } @@ -383,14 +379,14 @@ fun PayViaIntentDialog( if (it.user != null) { BaseUserPicture(it.user, Size55dp, accountViewModel = accountViewModel) } else { - DisplayBlankAuthor(size = Size55dp) + DisplayBlankAuthor(size = Size55dp, accountViewModel = accountViewModel) } Spacer(modifier = DoubleHorzSpacer) Column(modifier = Modifier.weight(1f)) { if (it.user != null) { - UsernameDisplay(it.user) + UsernameDisplay(it.user, accountViewModel = accountViewModel) } else { Text( text = stringResource(id = R.string.wallet_number, index + 1), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt index 1ede76f829..f085925ede 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt @@ -65,7 +65,10 @@ fun ZapNoteCompose( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val baseNoteRequest by baseReqResponse.zapRequest.live().metadata.observeAsState() + val baseNoteRequest by baseReqResponse.zapRequest + .live() + .metadata + .observeAsState() var baseAuthor by remember { mutableStateOf(null) } @@ -115,7 +118,7 @@ private fun RenderZapNote( Column( modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }, ) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseAuthor) } + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseAuthor, accountViewModel = accountViewModel) } Row(verticalAlignment = Alignment.CenterVertically) { AboutDisplay(baseAuthor) } } @@ -179,7 +182,11 @@ fun ShowFollowingOrUnfollowingButton( accountViewModel: AccountViewModel, ) { var isFollowing by remember { mutableStateOf(false) } - val accountFollowsState by accountViewModel.account.userProfile().live().follows.observeAsState() + val accountFollowsState by accountViewModel.account + .userProfile() + .live() + .follows + .observeAsState() LaunchedEffect(key1 = accountFollowsState) { launch(Dispatchers.Default) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt index 3a440f4d18..edb150193a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt @@ -102,7 +102,7 @@ fun ZapUserSetCompose( ) Column(modifier = remember { Modifier.padding(start = 10.dp).weight(1f) }) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(zapSetCard.user) } + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(zapSetCard.user, accountViewModel = accountViewModel) } AboutDisplay(zapSetCard.user) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt index 41ff8fe337..59e1b88038 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.note.elements import android.content.Context -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -68,6 +67,7 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ThemeType import com.vitorpamplona.amethyst.service.ZapPaymentHandler +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.navigation.routeFor @@ -443,7 +443,7 @@ fun ZapDonationButton( } } - Crossfade(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon") { + CrossfadeIfEnabled(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon", accountViewModel = accountViewModel) { if (it) { ZappedIcon(iconSizeModifier) } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt index 7b3215b965..d7875628e0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt @@ -123,7 +123,7 @@ fun AudioTrackHeader( ) { ClickableUserPicture(it.second, 25.dp, accountViewModel) Spacer(Modifier.width(5.dp)) - UsernameDisplay(it.second, Modifier.weight(1f)) + UsernameDisplay(it.second, Modifier.weight(1f), accountViewModel = accountViewModel) Spacer(Modifier.width(5.dp)) it.first.role?.let { Text( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index 3477c8af24..5b1cf183c7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -47,6 +47,7 @@ import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.AddressableNote +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage @@ -188,7 +189,7 @@ fun LongCommunityHeader( Spacer(DoubleHorzSpacer) NoteAuthorPicture(baseNote, nav, accountViewModel, Size25dp) Spacer(DoubleHorzSpacer) - NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) }) + NoteUsernameDisplay(baseNote, Modifier.weight(1f), accountViewModel = accountViewModel) } var participantUsers by @@ -228,7 +229,7 @@ fun LongCommunityHeader( Spacer(DoubleHorzSpacer) ClickableUserPicture(it.second, Size25dp, accountViewModel) Spacer(DoubleHorzSpacer) - UsernameDisplay(it.second, remember { Modifier.weight(1f) }) + UsernameDisplay(it.second, Modifier.weight(1f), accountViewModel = accountViewModel) } } @@ -258,11 +259,6 @@ fun ShortCommunityHeader( val noteEvent = remember(noteState) { noteState?.note?.event as? CommunityDefinitionEvent } ?: return - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - Row(verticalAlignment = Alignment.CenterVertically) { noteEvent.image()?.let { RobohashFallbackAsyncImage( @@ -271,7 +267,8 @@ fun ShortCommunityHeader( contentDescription = stringResource(R.string.profile_image), contentScale = ContentScale.Crop, modifier = HeaderPictureModifier, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt index 6c5a29d040..1f0c006060 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note.types -import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -49,6 +48,7 @@ import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import coil.compose.AsyncImage import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.elements.AddButton @@ -195,10 +195,9 @@ private fun EmojiListOptions( .metadata .map { usersEmojiList.event?.isTaggedAddressableNote(emojiPackNote.idHex) } .distinctUntilChanged() - } - .observeAsState() + }.observeAsState() - Crossfade(targetState = hasAddedThis, label = "EmojiListOptions") { + CrossfadeIfEnabled(targetState = hasAddedThis, label = "EmojiListOptions", accountViewModel = accountViewModel) { if (it != true) { AddButton { accountViewModel.addEmojiPack(usersEmojiList, emojiPackNote) } } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt index 26eab2f870..70321e2ee8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note.types -import androidx.compose.animation.Crossfade import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -31,6 +30,7 @@ import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent import com.vitorpamplona.amethyst.commons.richtext.MediaLocalImage import com.vitorpamplona.amethyst.commons.richtext.MediaLocalVideo import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.ZoomableContentView @@ -106,7 +106,7 @@ private fun ObserverAndRenderNIP95( mutableStateOf(newContent) } - Crossfade(targetState = content) { + CrossfadeIfEnabled(targetState = content, accountViewModel = accountViewModel) { if (it != null) { SensitivityWarning(note = header, accountViewModel = accountViewModel) { ZoomableContentView( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt index cd5ed6250b..eb379995cf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.note.types -import androidx.compose.animation.Crossfade import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -46,6 +45,7 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.VideoView import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.note.UsernameDisplay @@ -116,7 +116,7 @@ fun RenderLiveActivityEventInner( Spacer(modifier = StdHorzSpacer) - Crossfade(targetState = status, label = "RenderLiveActivityEventInner") { + CrossfadeIfEnabled(targetState = status, label = "RenderLiveActivityEventInner", accountViewModel = accountViewModel) { when (it) { LiveActivitiesEvent.STATUS_LIVE -> { media?.let { CrossfadeCheckIfUrlIsOnline(it, accountViewModel) { LiveFlag() } } @@ -205,7 +205,7 @@ fun RenderLiveActivityEventInner( ) { ClickableUserPicture(it.second, 25.dp, accountViewModel) Spacer(StdHorzSpacer) - UsernameDisplay(it.second, Modifier.weight(1f)) + UsernameDisplay(it.second, Modifier.weight(1f), accountViewModel = accountViewModel) Spacer(StdHorzSpacer) it.first.role?.let { Text( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt index 0cb474347f..3b02eadde0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt @@ -77,6 +77,7 @@ fun ShowQRDialogPreview() { ShowQRDialog( user = user, loadProfilePicture = false, + loadRobohash = false, onScan = {}, onClose = {}, ) @@ -86,6 +87,7 @@ fun ShowQRDialogPreview() { fun ShowQRDialog( user: User, loadProfilePicture: Boolean, + loadRobohash: Boolean, onScan: (String) -> Unit, onClose: () -> Unit, ) { @@ -120,11 +122,13 @@ fun ShowQRDialog( model = user.profilePicture(), contentDescription = stringResource(R.string.profile_image), modifier = - Modifier.width(100.dp) + Modifier + .width(100.dp) .height(100.dp) .clip(shape = CircleShape) .border(3.dp, MaterialTheme.colorScheme.background, CircleShape), loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) } Row( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt index 8d0a140b83..ead1f9cd9a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Row @@ -41,6 +40,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.BadgeCompose import com.vitorpamplona.amethyst.ui.note.MessageSetCompose @@ -111,10 +111,11 @@ fun RenderCardFeed( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade( + CrossfadeIfEnabled( modifier = Modifier.fillMaxSize(), targetState = feedState, animationSpec = tween(durationMillis = 100), + accountViewModel = accountViewModel, ) { state -> when (state) { is CardFeedState.Empty -> { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt index a4afc4aadf..b0dd65c34b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomFeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -38,6 +37,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ChatroomMessageCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.FeedPadding @@ -86,7 +86,7 @@ fun RenderChatroomFeedView( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade(targetState = feedState, animationSpec = tween(durationMillis = 100)) { state -> + CrossfadeIfEnabled(targetState = feedState, animationSpec = tween(durationMillis = 100), accountViewModel = accountViewModel) { state -> when (state) { is FeedState.Empty -> { FeedEmpty { viewModel.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt index 1d88fe089b..56d30493f0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -34,6 +33,7 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ChatroomHeaderCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -58,9 +58,10 @@ private fun CrossFadeState( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade( + CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), + accountViewModel = accountViewModel, ) { state -> when (state) { is FeedState.Empty -> { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt index 8dd64290ff..200ba6a4fd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement @@ -55,6 +54,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -105,12 +105,10 @@ fun RefresheableBox( val pullRefreshState = rememberPullRefreshState(refreshing, onRefresh = refresh) val modifier = - remember { - if (enablePullRefresh) { - Modifier.fillMaxSize().pullRefresh(pullRefreshState) - } else { - Modifier.fillMaxSize() - } + if (enablePullRefresh) { + Modifier.fillMaxSize().pullRefresh(pullRefreshState) + } else { + Modifier.fillMaxSize() } Box(modifier) { @@ -120,7 +118,7 @@ fun RefresheableBox( PullRefreshIndicator( refreshing = refreshing, state = pullRefreshState, - modifier = remember { Modifier.align(Alignment.TopCenter) }, + modifier = Modifier.align(Alignment.TopCenter), ) } } @@ -176,9 +174,10 @@ fun RenderFeedState( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade( + CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), + accountViewModel = accountViewModel, ) { state -> when (state) { is FeedState.Empty -> onEmpty() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt index 4d531ac3b7..0a2c8d2b25 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -32,6 +31,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ZapNoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -45,7 +45,7 @@ fun LnZapFeedView( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade(targetState = feedState, animationSpec = tween(durationMillis = 100)) { state -> + CrossfadeIfEnabled(targetState = feedState, animationSpec = tween(durationMillis = 100), accountViewModel = accountViewModel) { state -> when (state) { is LnZapFeedState.Empty -> { FeedEmpty { viewModel.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt index 83f506cfd3..129ad0ebb9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt @@ -42,7 +42,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Stable -class SettingsState() { +class SettingsState { var theme by mutableStateOf(ThemeType.SYSTEM) var language by mutableStateOf(null) @@ -53,7 +53,7 @@ class SettingsState() { var automaticallyShowProfilePictures by mutableStateOf(ConnectivityType.ALWAYS) var dontShowPushNotificationSelector by mutableStateOf(false) var dontAskForNotificationPermissions by mutableStateOf(false) - var featureSet by mutableStateOf(FeatureSetType.COMPLETE) + var featureSet by mutableStateOf(FeatureSetType.SIMPLIFIED) var isOnMobileData: State = mutableStateOf(false) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt index c3561e544c..931352ac67 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -38,19 +37,22 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding @Composable fun StringFeedView( viewModel: StringFeedViewModel, + accountViewModel: AccountViewModel, pre: (@Composable () -> Unit)? = null, post: (@Composable () -> Unit)? = null, inner: @Composable (String) -> Unit, ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade(targetState = feedState, animationSpec = tween(durationMillis = 100)) { state -> + CrossfadeIfEnabled(targetState = feedState, animationSpec = tween(durationMillis = 100), accountViewModel = accountViewModel) { state -> when (state) { is StringFeedState.Empty -> { StringFeedEmpty(pre, post) { viewModel.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index 6980f89ed3..c0e5fe1cf8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -402,7 +402,7 @@ private fun FullBleedNoteCompose( Column(modifier = Modifier.padding(start = 10.dp)) { Row(verticalAlignment = Alignment.CenterVertically) { - NoteUsernameDisplay(baseNote, Modifier.weight(1f)) + NoteUsernameDisplay(baseNote, Modifier.weight(1f), accountViewModel = accountViewModel) val isCommunityPost = remember(baseNote) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt index bc1ee84fed..bc9812d174 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed @@ -29,6 +28,7 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -52,7 +52,7 @@ fun UserFeedView( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade(targetState = feedState, animationSpec = tween(durationMillis = 100)) { state -> + CrossfadeIfEnabled(targetState = feedState, animationSpec = tween(durationMillis = 100), accountViewModel = accountViewModel) { state -> when (state) { is UserFeedState.Empty -> { FeedEmpty { viewModel.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 1f886feb86..4fc7151aa0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -104,6 +104,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Channel +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.LiveActivitiesChannel import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -763,11 +764,6 @@ fun ShortChannelHeader( val channelState by baseChannel.live.observeAsState() val channel = channelState?.channel ?: return - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - Row(verticalAlignment = Alignment.CenterVertically) { if (channel is LiveActivitiesChannel) { channel.creator?.let { @@ -786,7 +782,8 @@ fun ShortChannelHeader( contentDescription = stringResource(R.string.profile_image), contentScale = ContentScale.Crop, modifier = HeaderPictureModifier, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) } } @@ -902,7 +899,7 @@ fun LongChannelHeader( Spacer(DoubleHorzSpacer) NoteAuthorPicture(note, nav, accountViewModel, Size25dp) Spacer(DoubleHorzSpacer) - NoteUsernameDisplay(note, remember { Modifier.weight(1f) }) + NoteUsernameDisplay(note, Modifier.weight(1f), accountViewModel = accountViewModel) } Row( @@ -963,7 +960,7 @@ fun LongChannelHeader( Spacer(DoubleHorzSpacer) ClickableUserPicture(it.second, Size25dp, accountViewModel) Spacer(DoubleHorzSpacer) - UsernameDisplay(it.second, remember { Modifier.weight(1f) }) + UsernameDisplay(it.second, Modifier.weight(1f), accountViewModel = accountViewModel) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index aedacc4ed8..c8df0f6525 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.widget.Toast -import androidx.compose.animation.Crossfade import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -89,6 +88,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrChatroomDataSource import com.vitorpamplona.amethyst.ui.actions.CloseButton +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel import com.vitorpamplona.amethyst.ui.actions.PostButton import com.vitorpamplona.amethyst.ui.actions.ServerOption @@ -646,7 +646,7 @@ fun ChatroomHeader( ) Column(modifier = Modifier.padding(start = 10.dp)) { - UsernameDisplay(baseUser) + UsernameDisplay(baseUser, accountViewModel = accountViewModel) } } } @@ -678,7 +678,7 @@ fun GroupChatroomHeader( ) Column(modifier = Modifier.padding(start = 10.dp)) { - RoomNameOnlyDisplay(room, Modifier, FontWeight.Bold, accountViewModel.userProfile()) + RoomNameOnlyDisplay(room, Modifier, FontWeight.Bold, accountViewModel) DisplayUserSetAsSubject(room, accountViewModel, FontWeight.Normal) } } @@ -892,17 +892,18 @@ fun RoomNameOnlyDisplay( room: ChatroomKey, modifier: Modifier, fontWeight: FontWeight = FontWeight.Bold, - loggedInUser: User, + accountViewModel: AccountViewModel, ) { val roomSubject by - loggedInUser + accountViewModel + .userProfile() .live() .messages .map { it.user.privateChatrooms[room]?.subject } .distinctUntilChanged() - .observeAsState(loggedInUser.privateChatrooms[room]?.subject) + .observeAsState(accountViewModel.userProfile().privateChatrooms[room]?.subject) - Crossfade(targetState = roomSubject, modifier) { + CrossfadeIfEnabled(targetState = roomSubject, modifier, accountViewModel = accountViewModel) { if (it != null && it.isNotBlank()) { DisplayRoomSubject(it, fontWeight) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt index 3120345fe0..cbe5c710da 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Column @@ -59,6 +58,7 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.NostrDiscoveryDataSource +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.note.ChannelCardCompose import com.vitorpamplona.amethyst.ui.screen.FeedEmpty @@ -146,8 +146,7 @@ fun DiscoverScreen( ScrollStateKeys.DISCOVER_CHATS, ChannelCreateEvent.KIND, ), - ) - .toImmutableList(), + ).toImmutableList(), ) } @@ -213,8 +212,7 @@ private fun DiscoverPages( HorizontalPager(state = pagerState) { page -> RefresheableBox(tabs[page].viewModel, true) { if (tabs[page].viewModel is NostrDiscoverMarketplaceFeedViewModel) { - SaveableGridFeedState(tabs[page].viewModel, scrollStateKey = tabs[page].scrollStateKey) { - listState -> + SaveableGridFeedState(tabs[page].viewModel, scrollStateKey = tabs[page].scrollStateKey) { listState -> RenderDiscoverFeed( viewModel = tabs[page].viewModel, routeForLastRead = tabs[page].routeForLastRead, @@ -225,8 +223,7 @@ private fun DiscoverPages( ) } } else { - SaveableFeedState(tabs[page].viewModel, scrollStateKey = tabs[page].scrollStateKey) { - listState -> + SaveableFeedState(tabs[page].viewModel, scrollStateKey = tabs[page].scrollStateKey) { listState -> RenderDiscoverFeed( viewModel = tabs[page].viewModel, routeForLastRead = tabs[page].routeForLastRead, @@ -252,10 +249,11 @@ private fun RenderDiscoverFeed( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade( + CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), label = "RenderDiscoverFeed", + accountViewModel = accountViewModel, ) { state -> when (state) { is FeedState.Empty -> { @@ -292,10 +290,11 @@ private fun RenderDiscoverFeed( ) { val feedState by viewModel.feedContent.collectAsStateWithLifecycle() - Crossfade( + CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), label = "RenderDiscoverFeed", + accountViewModel = accountViewModel, ) { state -> when (state) { is FeedState.Empty -> { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt index 1c30be2594..929ddbbd5e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt @@ -219,6 +219,7 @@ private fun HiddenWordsFeed( RefresheableBox(hiddenWordsViewModel, false) { StringFeedView( hiddenWordsViewModel, + accountViewModel, post = { AddMuteWordTextField(accountViewModel) }, ) { MutedWordHeader(tag = it, account = accountViewModel) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt index d422a0f971..4578a27fd0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -55,6 +54,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.NostrHomeDataSource import com.vitorpamplona.amethyst.service.OnlineChecker +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog import com.vitorpamplona.amethyst.ui.screen.FeedViewModel @@ -289,9 +289,10 @@ fun CrossfadeCheckIfUrlIsOnline( } } - Crossfade( + CrossfadeIfEnabled( targetState = online, label = "CheckIfUrlIsOnline", + accountViewModel = accountViewModel, ) { if (it) { whenOnline() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt index 83b3a2c929..3b4b2ae6a5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt @@ -74,6 +74,7 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.vitorpamplona.amethyst.R @@ -141,7 +142,6 @@ fun MainScreen( } val navController = rememberNavController() - val navState = navController.currentBackStackEntryAsState() val orientation = LocalConfiguration.current.orientation val currentDrawerState = drawerState.currentValue @@ -165,9 +165,6 @@ fun MainScreen( } } - DisplayErrorMessages(accountViewModel) - DisplayNotifyMessages(accountViewModel, nav) - val navPopBack = remember(navController) { { @@ -176,7 +173,10 @@ fun MainScreen( } } - val followLists: FollowListViewModel = + DisplayErrorMessages(accountViewModel) + DisplayNotifyMessages(accountViewModel, nav) + + val followListsViewModel: FollowListViewModel = viewModel( key = "FollowListViewModel", factory = FollowListViewModel.Factory(accountViewModel.account), @@ -297,52 +297,6 @@ fun MainScreen( } } - val bottomBarHeightPx = with(LocalDensity.current) { 50.dp.roundToPx().toFloat() } - val bottomBarOffsetHeightPx = remember { mutableFloatStateOf(0f) } - val shouldShow = remember { mutableStateOf(true) } - - val nestedScrollConnection = - remember { - object : NestedScrollConnection { - override fun onPreScroll( - available: Offset, - source: NestedScrollSource, - ): Offset { - val newOffset = bottomBarOffsetHeightPx.floatValue + available.y - - if (accountViewModel.settings.automaticallyHideNavigationBars == BooleanType.ALWAYS) { - val newBottomBarOffset = - if (navState.value?.destination?.route !in InvertedLayouts) { - newOffset.coerceIn(-bottomBarHeightPx, 0f) - } else { - newOffset.coerceIn(0f, bottomBarHeightPx) - } - - if (newBottomBarOffset != bottomBarOffsetHeightPx.floatValue) { - bottomBarOffsetHeightPx.floatValue = newBottomBarOffset - } - } else { - if (abs(bottomBarOffsetHeightPx.floatValue) > 0.1) { - bottomBarOffsetHeightPx.floatValue = 0f - } - } - - val newShouldShow = abs(bottomBarOffsetHeightPx.floatValue) < bottomBarHeightPx / 2.0f - - if (shouldShow.value != newShouldShow) { - shouldShow.value = newShouldShow - } - - return Offset.Zero - } - } - } - - WatchNavStateToUpdateBarVisibility(navState) { - bottomBarOffsetHeightPx.floatValue = 0f - shouldShow.value = true - } - ModalNavigationDrawer( drawerState = drawerState, drawerContent = { @@ -350,87 +304,29 @@ fun MainScreen( BackHandler(enabled = drawerState.isOpen) { scope.launch { drawerState.close() } } }, content = { - Scaffold( - // containerColor = Color.Unspecified, - modifier = - Modifier - .statusBarsPadding() - .nestedScroll(nestedScrollConnection), - bottomBar = { - AnimatedContent( - targetState = shouldShow.value, - transitionSpec = AnimatedContentTransitionScope::bottomBarTransitionSpec, - label = "BottomBarAnimatedContent", - ) { isVisible -> - if (isVisible) { - AppBottomBar(accountViewModel, navState, navBottomRow) - } - } - }, - topBar = { - AnimatedContent( - targetState = shouldShow.value, - transitionSpec = AnimatedContentTransitionScope::topBarTransitionSpec, - label = "TopBarAnimatedContent", - ) { isVisible -> - if (isVisible) { - AppTopBar( - followLists, - navState, - drawerState, - accountViewModel, - nav = nav, - navPopBack, - ) - } - } - }, - floatingActionButton = { - AnimatedVisibility( - visible = shouldShow.value, - enter = remember { scaleIn() }, - exit = remember { scaleOut() }, - ) { - Box( - modifier = Modifier.defaultMinSize(minWidth = 55.dp, minHeight = 55.dp), - ) { - FloatingButtons( - navState, - accountViewModel, - accountStateViewModel, - nav, - navBottomRow, - ) - } - } - }, - ) { - Column( - modifier = - Modifier.padding( - top = it.calculateTopPadding(), - bottom = it.calculateBottomPadding(), - ), - ) { - AppNavigation( - homeFeedViewModel = homeFeedViewModel, - repliesFeedViewModel = repliesFeedViewModel, - knownFeedViewModel = knownFeedViewModel, - newFeedViewModel = newFeedViewModel, - videoFeedViewModel = videoFeedViewModel, - discoverNip89FeedViewModel = discoverNIP89FeedViewModel, - discoverMarketplaceFeedViewModel = discoverMarketplaceFeedViewModel, - discoveryLiveFeedViewModel = discoveryLiveFeedViewModel, - discoveryCommunityFeedViewModel = discoveryCommunityFeedViewModel, - discoveryChatFeedViewModel = discoveryChatFeedViewModel, - notifFeedViewModel = notifFeedViewModel, - userReactionsStatsModel = userReactionsStatsModel, - navController = navController, - accountViewModel = accountViewModel, - sharedPreferencesViewModel = sharedPreferencesViewModel, - ) - } - } + MainScaffold( + navController = navController, + navBottomRow = navBottomRow, + navPopBack = navPopBack, + openDrawer = { scope.launch { drawerState.open() } }, + accountStateViewModel = accountStateViewModel, + userReactionsStatsModel = userReactionsStatsModel, + followListsViewModel = followListsViewModel, + homeFeedViewModel = homeFeedViewModel, + repliesFeedViewModel = repliesFeedViewModel, + knownFeedViewModel = knownFeedViewModel, + newFeedViewModel = newFeedViewModel, + videoFeedViewModel = videoFeedViewModel, + discoverNIP89FeedViewModel = discoverNIP89FeedViewModel, + discoverMarketplaceFeedViewModel = discoverMarketplaceFeedViewModel, + discoveryLiveFeedViewModel = discoveryLiveFeedViewModel, + discoveryCommunityFeedViewModel = discoveryCommunityFeedViewModel, + discoveryChatFeedViewModel = discoveryChatFeedViewModel, + notifFeedViewModel = notifFeedViewModel, + sharedPreferencesViewModel = sharedPreferencesViewModel, + accountViewModel = accountViewModel, + nav = nav, + ) }, ) @@ -456,6 +352,168 @@ fun MainScreen( } } +@Composable +private fun MainScaffold( + navController: NavHostController, + navBottomRow: (Route, Boolean) -> Unit, + navPopBack: () -> Unit, + openDrawer: () -> Unit, + accountStateViewModel: AccountStateViewModel, + userReactionsStatsModel: UserReactionsViewModel, + followListsViewModel: FollowListViewModel, + homeFeedViewModel: NostrHomeFeedViewModel, + repliesFeedViewModel: NostrHomeRepliesFeedViewModel, + knownFeedViewModel: NostrChatroomListKnownFeedViewModel, + newFeedViewModel: NostrChatroomListNewFeedViewModel, + videoFeedViewModel: NostrVideoFeedViewModel, + discoverNIP89FeedViewModel: NostrDiscoverNIP89FeedViewModel, + discoverMarketplaceFeedViewModel: NostrDiscoverMarketplaceFeedViewModel, + discoveryLiveFeedViewModel: NostrDiscoverLiveFeedViewModel, + discoveryCommunityFeedViewModel: NostrDiscoverCommunityFeedViewModel, + discoveryChatFeedViewModel: NostrDiscoverChatFeedViewModel, + notifFeedViewModel: NotificationViewModel, + sharedPreferencesViewModel: SharedPreferencesViewModel, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val navState = navController.currentBackStackEntryAsState() + + val shouldShow = remember { mutableStateOf(true) } + + val modifier = + if (accountViewModel.settings.automaticallyHideNavigationBars == BooleanType.ALWAYS) { + val bottomBarHeightPx = with(LocalDensity.current) { 50.dp.roundToPx().toFloat() } + val bottomBarOffsetHeightPx = remember { mutableFloatStateOf(0f) } + + val nestedScrollConnection = + remember { + object : NestedScrollConnection { + override fun onPreScroll( + available: Offset, + source: NestedScrollSource, + ): Offset { + val newOffset = bottomBarOffsetHeightPx.floatValue + available.y + + if (accountViewModel.settings.automaticallyHideNavigationBars == BooleanType.ALWAYS) { + val newBottomBarOffset = + if (navState.value?.destination?.route !in InvertedLayouts) { + newOffset.coerceIn(-bottomBarHeightPx, 0f) + } else { + newOffset.coerceIn(0f, bottomBarHeightPx) + } + + if (newBottomBarOffset != bottomBarOffsetHeightPx.floatValue) { + bottomBarOffsetHeightPx.floatValue = newBottomBarOffset + } + } else { + if (abs(bottomBarOffsetHeightPx.floatValue) > 0.1) { + bottomBarOffsetHeightPx.floatValue = 0f + } + } + + val newShouldShow = abs(bottomBarOffsetHeightPx.floatValue) < bottomBarHeightPx / 2.0f + + if (shouldShow.value != newShouldShow) { + shouldShow.value = newShouldShow + } + + return Offset.Zero + } + } + } + + WatchNavStateToUpdateBarVisibility(navState) { + bottomBarOffsetHeightPx.floatValue = 0f + shouldShow.value = true + } + + Modifier + .statusBarsPadding() + .nestedScroll(nestedScrollConnection) + } else { + Modifier + .statusBarsPadding() + } + + Scaffold( + modifier = modifier, + bottomBar = { + AnimatedContent( + targetState = shouldShow.value, + transitionSpec = AnimatedContentTransitionScope::bottomBarTransitionSpec, + label = "BottomBarAnimatedContent", + ) { isVisible -> + if (isVisible) { + AppBottomBar(accountViewModel, navState, navBottomRow) + } + } + }, + topBar = { + AnimatedContent( + targetState = shouldShow.value, + transitionSpec = AnimatedContentTransitionScope::topBarTransitionSpec, + label = "TopBarAnimatedContent", + ) { isVisible -> + if (isVisible) { + AppTopBar( + followListsViewModel, + navState, + openDrawer, + accountViewModel, + nav = nav, + navPopBack, + ) + } + } + }, + floatingActionButton = { + AnimatedVisibility( + visible = shouldShow.value, + enter = remember { scaleIn() }, + exit = remember { scaleOut() }, + ) { + Box( + modifier = Modifier.defaultMinSize(minWidth = 55.dp, minHeight = 55.dp), + ) { + FloatingButtons( + navState, + accountViewModel, + accountStateViewModel, + nav, + navBottomRow, + ) + } + } + }, + ) { + Column( + modifier = + Modifier.padding( + top = it.calculateTopPadding(), + bottom = it.calculateBottomPadding(), + ), + ) { + AppNavigation( + homeFeedViewModel = homeFeedViewModel, + repliesFeedViewModel = repliesFeedViewModel, + knownFeedViewModel = knownFeedViewModel, + newFeedViewModel = newFeedViewModel, + videoFeedViewModel = videoFeedViewModel, + discoverNip89FeedViewModel = discoverNIP89FeedViewModel, + discoverMarketplaceFeedViewModel = discoverMarketplaceFeedViewModel, + discoveryLiveFeedViewModel = discoveryLiveFeedViewModel, + discoveryCommunityFeedViewModel = discoveryCommunityFeedViewModel, + discoveryChatFeedViewModel = discoveryChatFeedViewModel, + notifFeedViewModel = notifFeedViewModel, + userReactionsStatsModel = userReactionsStatsModel, + navController = navController, + accountViewModel = accountViewModel, + sharedPreferencesViewModel = sharedPreferencesViewModel, + ) + } + } +} + @OptIn(ExperimentalAnimationApi::class) private fun AnimatedContentTransitionScope.topBarTransitionSpec(): ContentTransform = topBarAnimation diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt index 3ec2a88da4..e4927c220e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -66,6 +65,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.ZapPaymentHandler +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.navigation.routeToMessage import com.vitorpamplona.amethyst.ui.note.DVMCard @@ -117,6 +117,7 @@ fun NIP90ContentDiscoveryScreen( onBlank = { FeedEmptyWithStatus(baseNote, stringResource(R.string.dvm_looking_for_app), accountViewModel, nav) }, + accountViewModel, ) } } @@ -530,8 +531,7 @@ fun ZapDVMButton( targetValue = zappingProgress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, label = "ZapIconIndicator", - ) - .value, + ).value, modifier = remember { Modifier.size(animationSize) }, strokeWidth = 2.dp, color = grayTint, @@ -549,7 +549,7 @@ fun ZapDVMButton( } } - Crossfade(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon") { + CrossfadeIfEnabled(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon", accountViewModel = accountViewModel) { if (it) { ZappedIcon(iconSizeModifier) } else { @@ -632,8 +632,7 @@ fun observeAppDefinition(appDefinitionNote: Note): DVMCard { description = noteEvent?.appMetaData()?.about ?: "", cover = noteEvent?.appMetaData()?.image?.ifBlank { null }, ) - } - .distinctUntilChanged() + }.distinctUntilChanged() .observeAsState( DVMCard( name = noteEvent.appMetaData()?.name ?: "", diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 5168253b5a..9e42c3332d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image @@ -117,10 +116,12 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.AddressableNote +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.InformationDialog import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataView import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji @@ -957,11 +958,6 @@ private fun DrawAdditionalInfo( val uri = LocalUriHandler.current val clipboardManager = LocalClipboardManager.current - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - user.toBestDisplayName().let { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 7.dp)) { CreateTextWithEmoji( @@ -1002,7 +998,8 @@ private fun DrawAdditionalInfo( if (dialogOpen) { ShowQRDialog( user, - automaticallyShowProfilePicture, + accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, onScan = { dialogOpen = false nav(it) @@ -1105,7 +1102,7 @@ private fun DrawAdditionalInfo( } } - DisplayAppRecommendations(appRecommendations, nav) + DisplayAppRecommendations(appRecommendations, accountViewModel, nav) } @Composable @@ -1199,15 +1196,17 @@ fun DisplayLNAddress( @OptIn(ExperimentalLayoutApi::class) private fun DisplayAppRecommendations( appRecommendations: NostrUserAppRecommendationsFeedViewModel, + accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { val feedState by appRecommendations.feedContent.collectAsStateWithLifecycle() LaunchedEffect(key1 = Unit) { appRecommendations.invalidateData() } - Crossfade( + CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), + accountViewModel = accountViewModel, ) { state -> when (state) { is FeedState.Loaded -> { @@ -1274,17 +1273,17 @@ private fun DisplayBadges( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - LoadAddressableNote( aTag = BadgeProfilesEvent.createAddressTag(baseUser.pubkeyHex), accountViewModel = accountViewModel, ) { note -> if (note != null) { - WatchAndRenderBadgeList(note, automaticallyShowProfilePicture, nav) + WatchAndRenderBadgeList( + note = note, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, + nav = nav, + ) } } } @@ -1293,6 +1292,7 @@ private fun DisplayBadges( private fun WatchAndRenderBadgeList( note: AddressableNote, loadProfilePicture: Boolean, + loadRobohash: Boolean, nav: (String) -> Unit, ) { val badgeList by @@ -1303,7 +1303,7 @@ private fun WatchAndRenderBadgeList( .distinctUntilChanged() .observeAsState() - badgeList?.let { list -> RenderBadgeList(list, loadProfilePicture, nav) } + badgeList?.let { list -> RenderBadgeList(list, loadProfilePicture, loadRobohash, nav) } } @Composable @@ -1311,13 +1311,14 @@ private fun WatchAndRenderBadgeList( private fun RenderBadgeList( list: ImmutableList, loadProfilePicture: Boolean, + loadRobohash: Boolean, nav: (String) -> Unit, ) { FlowRow( verticalArrangement = Arrangement.Center, modifier = Modifier.padding(vertical = 5.dp), ) { - list.forEach { badgeAwardEvent -> LoadAndRenderBadge(badgeAwardEvent, loadProfilePicture, nav) } + list.forEach { badgeAwardEvent -> LoadAndRenderBadge(badgeAwardEvent, loadProfilePicture, loadRobohash, nav) } } } @@ -1325,6 +1326,7 @@ private fun RenderBadgeList( private fun LoadAndRenderBadge( badgeAwardEventHex: String, loadProfilePicture: Boolean, + loadRobohash: Boolean, nav: (String) -> Unit, ) { var baseNote by remember(badgeAwardEventHex) { mutableStateOf(LocalCache.getNoteIfExists(badgeAwardEventHex)) } @@ -1337,37 +1339,40 @@ private fun LoadAndRenderBadge( } } - baseNote?.let { ObserveAndRenderBadge(it, loadProfilePicture, nav) } + baseNote?.let { ObserveAndRenderBadge(it, loadProfilePicture, loadRobohash, nav) } } @Composable private fun ObserveAndRenderBadge( it: Note, loadProfilePicture: Boolean, + loadRobohash: Boolean, nav: (String) -> Unit, ) { val badgeAwardState by it.live().metadata.observeAsState() val baseBadgeDefinition by remember(badgeAwardState) { derivedStateOf { badgeAwardState?.note?.replyTo?.firstOrNull() } } - baseBadgeDefinition?.let { BadgeThumb(it, loadProfilePicture, nav, Size35dp) } + baseBadgeDefinition?.let { BadgeThumb(it, loadProfilePicture, loadRobohash, nav, Size35dp) } } @Composable fun BadgeThumb( note: Note, loadProfilePicture: Boolean, + loadRobohash: Boolean, nav: (String) -> Unit, size: Dp, pictureModifier: Modifier = Modifier, ) { - BadgeThumb(note, loadProfilePicture, size, pictureModifier) { nav("Note/${note.idHex}") } + BadgeThumb(note, loadProfilePicture, loadRobohash, size, pictureModifier) { nav("Note/${note.idHex}") } } @Composable fun BadgeThumb( baseNote: Note, loadProfilePicture: Boolean, + loadRobohash: Boolean, size: Dp, pictureModifier: Modifier = Modifier, onClick: ((String) -> Unit)? = null, @@ -1379,7 +1384,7 @@ fun BadgeThumb( .height(size) }, ) { - WatchAndRenderBadgeImage(baseNote, loadProfilePicture, size, pictureModifier, onClick) + WatchAndRenderBadgeImage(baseNote, loadProfilePicture, loadRobohash, size, pictureModifier, onClick) } } @@ -1387,6 +1392,7 @@ fun BadgeThumb( private fun WatchAndRenderBadgeImage( baseNote: Note, loadProfilePicture: Boolean, + loadRobohash: Boolean, size: Dp, pictureModifier: Modifier, onClick: ((String) -> Unit)?, @@ -1411,6 +1417,7 @@ private fun WatchAndRenderBadgeImage( .width(size) .height(size) }, + loadRobohash = loadRobohash, ) } else { RobohashFallbackAsyncImage( @@ -1432,6 +1439,7 @@ private fun WatchAndRenderBadgeImage( } }, loadProfilePicture = loadProfilePicture, + loadRobohash = loadRobohash, ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt index 03a81f620f..27e6bb35f9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt @@ -71,6 +71,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Channel +import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -168,7 +169,9 @@ fun WatchAccountForSearchScreen(accountViewModel: AccountViewModel) { } @Stable -class SearchBarViewModel(val account: Account) : ViewModel() { +class SearchBarViewModel( + val account: Account, +) : ViewModel() { var searchValue by mutableStateOf("") private var _searchResultsUsers = MutableStateFlow>(emptyList()) @@ -198,12 +201,14 @@ class SearchBarViewModel(val account: Account) : ViewModel() { _hashtagResults.emit(findHashtags(searchValue)) _searchResultsUsers.emit( - LocalCache.findUsersStartingWith(searchValue) + LocalCache + .findUsersStartingWith(searchValue) .sortedWith(compareBy({ account.isFollowing(it) }, { it.toBestDisplayName() })) .reversed(), ) _searchResultsNotes.emit( - LocalCache.findNotesStartingWith(searchValue) + LocalCache + .findNotesStartingWith(searchValue) .sortedWith(compareBy({ it.createdAt() }, { it.idHex })) .reversed(), ) @@ -236,10 +241,10 @@ class SearchBarViewModel(val account: Account) : ViewModel() { fun isSearchingFun() = searchValue.isNotBlank() - class Factory(val account: Account) : ViewModelProvider.Factory { - override fun create(modelClass: Class): SearchBarViewModel { - return SearchBarViewModel(account) as SearchBarViewModel - } + class Factory( + val account: Account, + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): SearchBarViewModel = SearchBarViewModel(account) as SearchBarViewModel } } @@ -377,11 +382,6 @@ private fun DisplaySearchResults( val hasNewMessages = remember { mutableStateOf(false) } - val automaticallyShowProfilePicture = - remember { - accountViewModel.settings.showProfilePictures.value - } - LazyColumn( modifier = Modifier.fillMaxHeight(), contentPadding = FeedPadding, @@ -426,7 +426,8 @@ private fun DisplaySearchResults( channelLastTime = null, channelLastContent = item.summary(), hasNewMessages = hasNewMessages, - loadProfilePicture = automaticallyShowProfilePicture, + loadProfilePicture = accountViewModel.settings.showProfilePictures.value, + loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, onClick = { nav("Channel/${item.idHex}") }, ) @@ -500,7 +501,7 @@ fun UserLine( Column( modifier = Modifier.padding(start = 10.dp).weight(1f), ) { - Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser) } + Row(verticalAlignment = Alignment.CenterVertically) { UsernameDisplay(baseUser, accountViewModel = accountViewModel) } AboutDisplay(baseUser) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt index aeb9f87f83..98e798ff97 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt @@ -147,6 +147,7 @@ fun SettingsScreen(sharedPreferencesViewModel: SharedPreferencesViewModel) { persistentListOf( TitleExplainer(stringResource(FeatureSetType.COMPLETE.resourceId)), TitleExplainer(stringResource(FeatureSetType.SIMPLIFIED.resourceId)), + TitleExplainer(stringResource(FeatureSetType.PERFORMANCE.resourceId)), ) val showImagesIndex = sharedPreferencesViewModel.sharedPrefs.automaticallyShowImages.screenCode @@ -168,7 +169,8 @@ fun SettingsScreen(sharedPreferencesViewModel: SharedPreferencesViewModel) { sharedPreferencesViewModel.sharedPrefs.featureSet.screenCode Column( - Modifier.fillMaxSize() + Modifier + .fillMaxSize() .padding(top = Size10dp, start = Size20dp, end = Size20dp) .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index 0c230a69e7..4cb6782515 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement @@ -63,6 +62,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.NostrVideoDataSource +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.navigation.routeFor @@ -176,10 +176,11 @@ fun RenderPage( ) { val feedState by videoFeedView.feedContent.collectAsStateWithLifecycle() - Crossfade( + CrossfadeIfEnabled( targetState = feedState, animationSpec = tween(durationMillis = 100), label = "RenderPage", + accountViewModel = accountViewModel, ) { state -> when (state) { is FeedState.Empty -> { @@ -315,10 +316,10 @@ private fun RenderAuthorInformation( verticalArrangement = Arrangement.Center, ) { Row(verticalAlignment = Alignment.CenterVertically) { - NoteUsernameDisplay(note, remember { Modifier.weight(1f) }) + NoteUsernameDisplay(note, Modifier.weight(1f), accountViewModel = accountViewModel) VideoUserOptionAction(note, accountViewModel, nav) } - if (accountViewModel.settings.featureSet != FeatureSetType.SIMPLIFIED) { + if (accountViewModel.settings.featureSet == FeatureSetType.COMPLETE) { Row(verticalAlignment = Alignment.CenterVertically) { ObserveDisplayNip05Status( note.author!!, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 296d2e8cfa..b3e0e6f41c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -515,6 +515,7 @@ Complete Simplified + Performance System Light diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 2034c3174d..79a4b7ec1c 100644 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.components import android.content.res.Resources -import androidx.compose.animation.Crossfade import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -59,6 +58,7 @@ import androidx.compose.ui.unit.dp import androidx.core.os.ConfigurationCompat import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService +import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.lessImportantLink @@ -94,7 +94,7 @@ fun TranslatableRichTextViewer( } } - Crossfade(targetState = translatedTextState) { + CrossfadeIfEnabled(targetState = translatedTextState, accountViewModel = accountViewModel) { RenderText( translatedTextState = it, content = content, @@ -215,8 +215,7 @@ private fun TranslationMessage( overflow = TextOverflow.Visible, maxLines = 3, ) { spanOffset -> - annotatedTranslationString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { - span -> + annotatedTranslationString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { span -> if (span.tag == "showOriginal") { onChangeWhatToShow(span.item.toBoolean()) } else { @@ -373,12 +372,12 @@ fun TranslateAndWatchLanguageChanges( // This takes some time. Launches as a Composition scope to make sure this gets cancel if this // item gets out of view. withContext(Dispatchers.IO) { - LanguageTranslatorService.autoTranslate( - content, - accountViewModel.account.dontTranslateFrom, - accountViewModel.account.translateTo, - ) - .addOnCompleteListener { task -> + LanguageTranslatorService + .autoTranslate( + content, + accountViewModel.account.dontTranslateFrom, + accountViewModel.account.translateTo, + ).addOnCompleteListener { task -> if (task.isSuccessful && !content.equals(task.result.result, true)) { if (task.result.sourceLang != null && task.result.targetLang != null) { val preference = From c27f4a62b6c7bda346a8c43126c5cccf9324cacb Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 18:15:02 -0400 Subject: [PATCH 15/45] Switches Social Icons to faster SVG versions --- .../amethyst/ui/actions/CrossfadeIfEnabled.kt | 5 +- .../amethyst/ui/layouts/RepostLayout.kt | 4 +- .../amethyst/ui/navigation/Routes.kt | 39 +++---- .../amethyst/ui/note/ChatroomHeaderCompose.kt | 2 +- .../vitorpamplona/amethyst/ui/note/Icons.kt | 82 ++++++-------- .../amethyst/ui/note/ReactionsRow.kt | 33 +++--- .../ui/note/UpdateReactionTypeDialog.kt | 30 ++--- .../amethyst/ui/note/UserReactionsRow.kt | 41 +++---- app/src/main/res/drawable-hdpi/ic_comment.png | Bin 1850 -> 0 bytes app/src/main/res/drawable-hdpi/ic_like.png | Bin 2037 -> 0 bytes app/src/main/res/drawable-hdpi/ic_liked.png | Bin 1417 -> 0 bytes app/src/main/res/drawable-hdpi/ic_retweet.png | Bin 1357 -> 0 bytes .../main/res/drawable-hdpi/ic_retweeted.png | Bin 1492 -> 0 bytes app/src/main/res/drawable-hdpi/ic_search.png | Bin 1869 -> 0 bytes app/src/main/res/drawable-hdpi/ic_share.png | Bin 1090 -> 0 bytes app/src/main/res/drawable-mdpi/ic_comment.png | Bin 1388 -> 0 bytes app/src/main/res/drawable-mdpi/ic_like.png | Bin 1450 -> 0 bytes app/src/main/res/drawable-mdpi/ic_liked.png | Bin 1148 -> 0 bytes app/src/main/res/drawable-mdpi/ic_retweet.png | Bin 1045 -> 0 bytes .../main/res/drawable-mdpi/ic_retweeted.png | Bin 1144 -> 0 bytes app/src/main/res/drawable-mdpi/ic_search.png | Bin 1421 -> 0 bytes app/src/main/res/drawable-mdpi/ic_share.png | Bin 839 -> 0 bytes .../main/res/drawable-xhdpi/ic_comment.png | Bin 2884 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_like.png | Bin 3202 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_liked.png | Bin 2256 -> 0 bytes .../main/res/drawable-xhdpi/ic_retweet.png | Bin 1877 -> 0 bytes .../main/res/drawable-xhdpi/ic_retweeted.png | Bin 2103 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_search.png | Bin 2992 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_share.png | Bin 1706 -> 0 bytes .../main/res/drawable-xxhdpi/ic_comment.png | Bin 3755 -> 0 bytes app/src/main/res/drawable-xxhdpi/ic_like.png | Bin 4204 -> 0 bytes app/src/main/res/drawable-xxhdpi/ic_liked.png | Bin 2867 -> 0 bytes .../main/res/drawable-xxhdpi/ic_retweet.png | Bin 2469 -> 0 bytes .../main/res/drawable-xxhdpi/ic_retweeted.png | Bin 2778 -> 0 bytes .../main/res/drawable-xxhdpi/ic_search.png | Bin 3914 -> 0 bytes app/src/main/res/drawable-xxhdpi/ic_share.png | Bin 2204 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_comment.png | Bin 5825 -> 0 bytes app/src/main/res/drawable-xxxhdpi/ic_like.png | Bin 6610 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_liked.png | Bin 4479 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_retweet.png | Bin 3764 -> 0 bytes .../res/drawable-xxxhdpi/ic_retweeted.png | Bin 4243 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_search.png | Bin 6090 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_share.png | Bin 3261 -> 0 bytes .../commons/{labels => icons}/Following.kt | 15 +-- .../amethyst/commons/icons/Like.kt | 82 ++++++++++++++ .../amethyst/commons/icons/Liked.kt | 73 ++++++++++++ .../amethyst/commons/icons/Reply.kt | 90 +++++++++++++++ .../amethyst/commons/icons/Repost.kt | 104 +++++++++++++++++ .../amethyst/commons/icons/Reposted.kt | 104 +++++++++++++++++ .../amethyst/commons/icons/Search.kt | 82 ++++++++++++++ .../amethyst/commons/icons/Share.kt | 106 ++++++++++++++++++ .../amethyst/commons/icons/ZapSplit.kt | 104 +++++++++++++++++ 52 files changed, 844 insertions(+), 152 deletions(-) delete mode 100644 app/src/main/res/drawable-hdpi/ic_comment.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_like.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_liked.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_retweet.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_retweeted.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_search.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_share.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_comment.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_like.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_liked.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_retweet.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_retweeted.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_search.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_share.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_comment.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_like.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_liked.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_retweet.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_retweeted.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_search.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_share.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_comment.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_like.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_liked.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_retweet.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_retweeted.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_search.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_share.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_comment.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_like.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_liked.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_retweet.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_retweeted.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_search.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_share.png rename commons/src/main/java/com/vitorpamplona/amethyst/commons/{labels => icons}/Following.kt (95%) create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Like.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Liked.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Reply.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Repost.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Reposted.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Search.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Share.kt create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/ZapSplit.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt index 145dcd44f4..c0f20510c6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/CrossfadeIfEnabled.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.actions import androidx.compose.animation.Crossfade import androidx.compose.animation.core.FiniteAnimationSpec import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.model.FeatureSetType @@ -38,7 +39,9 @@ fun CrossfadeIfEnabled( content: @Composable (T) -> Unit, ) { if (accountViewModel.settings.featureSet == FeatureSetType.PERFORMANCE) { - content(targetState) + Box(modifier) { + content(targetState) + } } else { Crossfade(targetState, modifier, animationSpec, label, content) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt index 4539b0d8f4..bf570842d8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/RepostLayout.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.ui.note.RepostedIcon +import com.vitorpamplona.amethyst.ui.note.RepostIcon import com.vitorpamplona.amethyst.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.ui.theme.Size35Modifier import com.vitorpamplona.amethyst.ui.theme.Size55Modifier @@ -55,7 +55,7 @@ fun GenericRepostLayout( Box( remember { Size18Modifier.align(Alignment.BottomStart).padding(1.dp) }, ) { - RepostedIcon(modifier = Size18Modifier, MaterialTheme.colorScheme.placeholderText) + RepostIcon(modifier = Size18Modifier, MaterialTheme.colorScheme.placeholderText) } Box( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index 5f6361890e..fce43bfe80 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -77,8 +77,7 @@ sealed class Route( nullable = true defaultValue = null }, - ) - .toImmutableList(), + ).toImmutableList(), contentDescriptor = R.string.route_home, hasNewItems = { accountViewModel, newNotes -> HomeLatestItem.hasNewItems(accountViewModel, newNotes) @@ -95,7 +94,7 @@ sealed class Route( object Search : Route( route = "Search", - icon = R.drawable.ic_search, + icon = R.drawable.ic_moments, contentDescriptor = R.string.route_search, ) @@ -212,8 +211,7 @@ sealed class Route( nullable = true defaultValue = null }, - ) - .toImmutableList(), + ).toImmutableList(), ) object RoomByAuthor : @@ -256,9 +254,7 @@ sealed class Route( open class LatestItem { var newestItemPerAccount: Map = mapOf() - fun getNewestItem(account: Account): Note? { - return newestItemPerAccount[account.userProfile().pubkeyHex] - } + fun getNewestItem(account: Account): Note? = newestItemPerAccount[account.userProfile().pubkeyHex] fun clearNewestItem(account: Account) { val userHex = account.userProfile().pubkeyHex @@ -279,9 +275,10 @@ open class LatestItem { if (newestItem == null || !account.isAcceptable(newestItem)) { filterMore(filter.feed(), account).firstOrNull { it.createdAt() != null && account.isAcceptable(it) } } else { - filter.sort( - filterMore(filter.applyFilter(newNotes), account) + newestItem, - ).firstOrNull { it.createdAt() != null && account.isAcceptable(it) } + filter + .sort( + filterMore(filter.applyFilter(newNotes), account) + newestItem, + ).firstOrNull { it.createdAt() != null && account.isAcceptable(it) } } newestItemPerAccount = newestItemPerAccount + Pair(account.userProfile().pubkeyHex, newNewest) @@ -292,16 +289,12 @@ open class LatestItem { open fun filterMore( newItems: Set, account: Account, - ): Set { - return newItems - } + ): Set = newItems open fun filterMore( newItems: List, account: Account, - ): List { - return newItems - } + ): List = newItems } object HomeLatestItem : LatestItem() { @@ -382,16 +375,12 @@ object MessagesLatestItem : LatestItem() { override fun filterMore( newItems: Set, account: Account, - ): Set { - return newItems.filter { isNew(it, account) }.toSet() - } + ): Set = newItems.filter { isNew(it, account) }.toSet() override fun filterMore( newItems: List, account: Account, - ): List { - return newItems.filter { isNew(it, account) } - } + ): List = newItems.filter { isNew(it, account) } } fun getRouteWithArguments(navController: NavHostController): String? { @@ -399,9 +388,7 @@ fun getRouteWithArguments(navController: NavHostController): String? { return getRouteWithArguments(currentEntry.destination, currentEntry.arguments) } -fun getRouteWithArguments(navState: State): String? { - return navState.value?.let { getRouteWithArguments(it.destination, it.arguments) } -} +fun getRouteWithArguments(navState: State): String? = navState.value?.let { getRouteWithArguments(it.destination, it.arguments) } private fun getRouteWithArguments( destination: NavDestination, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt index 5c0b685d54..5e736214fa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt @@ -137,7 +137,7 @@ private fun ChatroomPrivateMessages( } } - CrossfadeIfEnabled(userRoom, label = "ChatroomPrivateMessages", accountViewModel = accountViewModel) { room -> + CrossfadeIfEnabled(targetState = userRoom, label = "ChatroomPrivateMessages", accountViewModel = accountViewModel) { room -> if (room != null) { UserRoomCompose(baseNote, room, accountViewModel, nav) } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index b193661e03..ccaff8826f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.OpenInNew +import androidx.compose.material.icons.automirrored.filled.Reply import androidx.compose.material.icons.automirrored.filled.VolumeOff import androidx.compose.material.icons.automirrored.filled.VolumeUp import androidx.compose.material.icons.filled.Bolt @@ -43,8 +44,6 @@ import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.PushPin import androidx.compose.material.icons.filled.Report -import androidx.compose.material.icons.materialIcon -import androidx.compose.material.icons.materialPath import androidx.compose.material.icons.outlined.ArrowForwardIos import androidx.compose.material.icons.outlined.BarChart import androidx.compose.material.icons.outlined.Bolt @@ -56,7 +55,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -66,7 +64,14 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.Amethyst import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons -import com.vitorpamplona.amethyst.commons.labels.Following +import com.vitorpamplona.amethyst.commons.icons.Following +import com.vitorpamplona.amethyst.commons.icons.Like +import com.vitorpamplona.amethyst.commons.icons.Liked +import com.vitorpamplona.amethyst.commons.icons.Reply +import com.vitorpamplona.amethyst.commons.icons.Repost +import com.vitorpamplona.amethyst.commons.icons.Reposted +import com.vitorpamplona.amethyst.commons.icons.Search +import com.vitorpamplona.amethyst.commons.icons.ZapSplit import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -153,12 +158,15 @@ fun HashCheckFailedIcon(iconSize: Dp) { } @Composable -fun LikedIcon(modifier: Modifier) { +fun LikedIcon( + modifier: Modifier, + tint: Color = Color.Unspecified, +) { Icon( - painter = painterResource(R.drawable.ic_liked), - null, + imageVector = Liked, + stringResource(id = R.string.like_description), modifier = modifier, - tint = Color.Unspecified, + tint = tint, ) } @@ -168,20 +176,33 @@ fun LikeIcon( grayTint: Color, ) { Icon( - painter = painterResource(R.drawable.ic_like), + imageVector = Like, contentDescription = stringResource(id = R.string.like_description), modifier = iconSizeModifier, tint = grayTint, ) } +@Composable +fun RepostIcon( + modifier: Modifier, + tint: Color = Color.Unspecified, +) { + Icon( + imageVector = Repost, + contentDescription = stringResource(id = R.string.boost_or_quote_description), + modifier = modifier, + tint = tint, + ) +} + @Composable fun RepostedIcon( modifier: Modifier, tint: Color = Color.Unspecified, ) { Icon( - painter = painterResource(R.drawable.ic_retweeted), + imageVector = Reposted, contentDescription = stringResource(id = R.string.boost_or_quote_description), modifier = modifier, tint = tint, @@ -305,7 +326,7 @@ fun CommentIcon( tint: Color, ) { Icon( - painter = painterResource(R.drawable.ic_comment), + imageVector = Reply, contentDescription = stringResource(id = R.string.reply_description), modifier = iconSizeModifier, tint = tint, @@ -390,7 +411,7 @@ fun SearchIcon( tint: Color = Color.Unspecified, ) { Icon( - painter = painterResource(R.drawable.ic_search), + imageVector = Search, contentDescription = stringResource(id = R.string.search_button), modifier = modifier, tint = tint, @@ -542,7 +563,7 @@ fun ZapSplitIcon( tint: Color = BitcoinOrange, ) { Icon( - imageVector = ZapSplitVector, + imageVector = ZapSplit, contentDescription = stringResource(id = R.string.zap_split_title), modifier = modifier, tint = tint, @@ -580,38 +601,3 @@ fun ZapSplitPreview() { ZapSplitIcon(tint = BitcoinOrange) } } - -public val ZapSplitVector: ImageVector - get() { - if (zapSplit != null) { - return zapSplit!! - } - zapSplit = - materialIcon(name = "ZapSplit") { - materialPath { - moveTo(7.0f, 21.0f) - horizontalLineToRelative(-1.0f) - lineToRelative(1.0f, -7.0f) - horizontalLineTo(3.5f) - curveToRelative(-0.88f, 0.0f, -0.33f, -0.75f, -0.31f, -0.78f) - curveTo(4.48f, 10.94f, 6.42f, 7.54f, 9.01f, 3.0f) - horizontalLineToRelative(1.0f) - lineToRelative(-1.0f, 7.0f) - horizontalLineToRelative(3.51f) - curveToRelative(0.4f, 0.0f, 0.62f, 0.19f, 0.4f, 0.66f) - curveTo(8.97f, 17.55f, 7.0f, 21.0f, 7.0f, 21.0f) - close() - moveTo(14.59f, 16.59f) - lineTo(19.17f, 12.0f) - lineTo(14.59f, 7.41f) - lineTo(16.0f, 6.0f) - lineToRelative(6.0f, 6.0f) - lineToRelative(-6.0f, 6.0f) - lineToRelative(-1.41f, -1.41f) - close() - } - } - return zapSplit!! - } - -private var zapSplit: ImageVector? = null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 46f899148c..4b27dcd23b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -50,7 +50,6 @@ import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme @@ -79,7 +78,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.SpanStyle @@ -120,8 +118,8 @@ import com.vitorpamplona.amethyst.ui.theme.ReactionRowHeightWithPadding import com.vitorpamplona.amethyst.ui.theme.ReactionRowZapraiser import com.vitorpamplona.amethyst.ui.theme.ReactionRowZapraiserWithPadding import com.vitorpamplona.amethyst.ui.theme.RowColSpacing -import com.vitorpamplona.amethyst.ui.theme.Size16Modifier -import com.vitorpamplona.amethyst.ui.theme.Size17Modifier +import com.vitorpamplona.amethyst.ui.theme.Size18Modifier +import com.vitorpamplona.amethyst.ui.theme.Size18dp import com.vitorpamplona.amethyst.ui.theme.Size19Modifier import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size20dp @@ -130,7 +128,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size24dp import com.vitorpamplona.amethyst.ui.theme.TinyBorders import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.theme.placeholderTextColorFilter import com.vitorpamplona.quartz.encoders.Nip30CustomEmoji import com.vitorpamplona.quartz.events.BaseTextNoteEvent import kotlinx.collections.immutable.ImmutableList @@ -205,11 +202,11 @@ private fun InnerReactionRow( ZapReaction(baseNote, MaterialTheme.colorScheme.placeholderText, accountViewModel, nav = nav) }, six = { - ViewCountReaction( - note = baseNote, - grayTint = MaterialTheme.colorScheme.placeholderText, - viewCountColorFilter = MaterialTheme.colorScheme.placeholderTextColorFilter, - ) + // ViewCountReaction( + // note = baseNote, + // grayTint = MaterialTheme.colorScheme.placeholderText, + // viewCountColorFilter = MaterialTheme.colorScheme.placeholderTextColorFilter, + // ) }, ) } @@ -585,7 +582,7 @@ fun ReplyReaction( grayTint: Color, accountViewModel: AccountViewModel, showCounter: Boolean = true, - iconSizeModifier: Modifier = Size17Modifier, + iconSizeModifier: Modifier = Size19Modifier, onPress: () -> Unit, ) { IconButton( @@ -710,7 +707,7 @@ fun BoostReaction( baseNote: Note, grayTint: Color, accountViewModel: AccountViewModel, - iconSizeModifier: Modifier = Size20Modifier, + iconSizeModifier: Modifier = Size19Modifier, iconSize: Dp = Size20dp, onQuotePress: () -> Unit, onForkPress: () -> Unit, @@ -787,8 +784,8 @@ fun LikeReaction( grayTint: Color, accountViewModel: AccountViewModel, nav: (String) -> Unit, - iconSize: Dp = Size20dp, - heartSizeModifier: Modifier = Size16Modifier, + iconSize: Dp = Size18dp, + heartSizeModifier: Modifier = Size18Modifier, iconFontSize: TextUnit = Font14SP, ) { var wantsToChangeReactionSymbol by remember { mutableStateOf(false) } @@ -1408,12 +1405,8 @@ private fun ActionableReactionButton( } else { when (reactionType) { "+" -> { - Icon( - painter = painterResource(R.drawable.ic_liked), - null, - modifier = remember { thisModifier.size(16.dp) }, - tint = Color.White, - ) + LikedIcon(modifier = thisModifier.size(16.dp), tint = Color.White) + Text( text = removeSymbol, color = Color.White, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt index 68d1109c8e..bc00950ff7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt @@ -42,7 +42,6 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface @@ -59,7 +58,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.input.KeyboardCapitalization @@ -95,7 +93,9 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch -class UpdateReactionTypeViewModel(val account: Account) : ViewModel() { +class UpdateReactionTypeViewModel( + val account: Account, +) : ViewModel() { var nextChoice by mutableStateOf(TextFieldValue("")) var reactionSet by mutableStateOf(listOf()) @@ -103,9 +103,7 @@ class UpdateReactionTypeViewModel(val account: Account) : ViewModel() { this.reactionSet = account.reactionChoices } - fun toListOfChoices(commaSeparatedAmounts: String): List { - return commaSeparatedAmounts.split(",").map { it.trim().toLongOrNull() ?: 0 } - } + fun toListOfChoices(commaSeparatedAmounts: String): List = commaSeparatedAmounts.split(",").map { it.trim().toLongOrNull() ?: 0 } fun addChoice() { val newValue = nextChoice.text.trim().firstFullChar() @@ -131,14 +129,12 @@ class UpdateReactionTypeViewModel(val account: Account) : ViewModel() { nextChoice = TextFieldValue("") } - fun hasChanged(): Boolean { - return reactionSet != account.reactionChoices - } + fun hasChanged(): Boolean = reactionSet != account.reactionChoices - class Factory(val account: Account) : ViewModelProvider.Factory { - override fun create(modelClass: Class): UpdateReactionTypeViewModel { - return UpdateReactionTypeViewModel(account) as UpdateReactionTypeViewModel - } + class Factory( + val account: Account, + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): UpdateReactionTypeViewModel = UpdateReactionTypeViewModel(account) as UpdateReactionTypeViewModel } } @@ -297,12 +293,8 @@ private fun RenderReactionOption( } else { when (reactionType) { "+" -> { - Icon( - painter = painterResource(R.drawable.ic_liked), - null, - modifier = remember { Modifier.size(16.dp) }, - tint = Color.White, - ) + LikedIcon(modifier = Modifier.size(16.dp), tint = Color.White) + Text( text = " ✖", color = Color.White, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt index 8e96921779..81961994cf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt @@ -39,7 +39,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -93,7 +92,10 @@ fun UserReactionsRow( ) { Row( verticalAlignment = CenterVertically, - modifier = Modifier.clickable(onClick = onClick).padding(10.dp), + modifier = + Modifier + .clickable(onClick = onClick) + .padding(10.dp), ) { Row(verticalAlignment = CenterVertically, modifier = Modifier.width(68.dp)) { Text( @@ -143,12 +145,7 @@ private fun UserZapModel(model: UserReactionsViewModel) { @Composable private fun UserReactionModel(model: UserReactionsViewModel) { - Icon( - painter = painterResource(R.drawable.ic_liked), - null, - modifier = Size20Modifier, - tint = Color.Unspecified, - ) + LikedIcon(modifier = Size20Modifier) Spacer(modifier = StdHorzSpacer) @@ -157,9 +154,7 @@ private fun UserReactionModel(model: UserReactionsViewModel) { @Composable private fun UserBoostModel(model: UserReactionsViewModel) { - Icon( - painter = painterResource(R.drawable.ic_retweeted), - null, + RepostedIcon( modifier = Size24Modifier, tint = Color.Unspecified, ) @@ -171,12 +166,7 @@ private fun UserBoostModel(model: UserReactionsViewModel) { @Composable private fun UserReplyModel(model: UserReactionsViewModel) { - Icon( - painter = painterResource(R.drawable.ic_comment), - null, - modifier = Size20Modifier, - tint = RoyalBlue, - ) + CommentIcon(Size20Modifier, RoyalBlue) Spacer(modifier = StdHorzSpacer) @@ -184,7 +174,9 @@ private fun UserReplyModel(model: UserReactionsViewModel) { } @Stable -class UserReactionsViewModel(val account: Account) : ViewModel() { +class UserReactionsViewModel( + val account: Account, +) : ViewModel() { val user: User = account.userProfile() private var _reactions = MutableStateFlow>(emptyMap()) @@ -213,11 +205,10 @@ class UserReactionsViewModel(val account: Account) : ViewModel() { var shouldShowDecimalsInAxis = false - fun formatDate(createAt: Long): String { - return sdf.format( + fun formatDate(createAt: Long): String = + sdf.format( Instant.ofEpochSecond(createAt).atZone(ZoneId.systemDefault()).toLocalDateTime(), ) - } fun today() = sdf.format(LocalDateTime.now()) @@ -452,10 +443,10 @@ class UserReactionsViewModel(val account: Account) : ViewModel() { super.onCleared() } - class Factory(val account: Account) : ViewModelProvider.Factory { - override fun create(modelClass: Class): UserReactionsViewModel { - return UserReactionsViewModel(account) as UserReactionsViewModel - } + class Factory( + val account: Account, + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): UserReactionsViewModel = UserReactionsViewModel(account) as UserReactionsViewModel } } diff --git a/app/src/main/res/drawable-hdpi/ic_comment.png b/app/src/main/res/drawable-hdpi/ic_comment.png deleted file mode 100644 index 0ae259d47e25bdc15c9b9fa602d6a5ed8492e771..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1850 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 Xw=u0^6X5Qk00000NkvXXu0mjf?I)5C diff --git a/app/src/main/res/drawable-hdpi/ic_retweet.png b/app/src/main/res/drawable-hdpi/ic_retweet.png deleted file mode 100644 index 89cb87ed6434f53dd58c4abaf400e825a1ec8303..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1357 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 IM6N<$f?ZeYtN;K2 diff --git a/app/src/main/res/drawable-mdpi/ic_comment.png b/app/src/main/res/drawable-mdpi/ic_comment.png deleted file mode 100644 index 893bb49f96ec4674f7769c1ec8251c8ca031f59e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1388 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 Eg0)hQe*gdg diff --git a/app/src/main/res/drawable-mdpi/ic_liked.png b/app/src/main/res/drawable-mdpi/ic_liked.png deleted file mode 100644 index 194ff9f95019c100e43eeb3f6f6596dbc3e9f8db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1148 zcmV-?1cUpDP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR919-spN1ONa40RR919smFU0Lno(1poj8=1D|BR7efQmS1RFRUF69@0=t} zt+DNftv;yP=$NdaXtqk`Lno*(&<7v-Fl1v;tRTvK^U?XJ_%hVOI$Eb=`j7`F8(UEy zTBHe;m8qDPQMT0$=i1=nmbFc8de6`AFPMMk5rM{O+)`t{54bW_MtAron##iDlG|IQV5r4vO! zV7WThf+-pA3kP-NackY@v{G>>Iw4zBq<&%7jv2RkHa0bMw`?YpoQe%Rc_M40(J7Gd){bzi}RtgyQhYV0qL>Y*{UobLDdUXB!s`iQbBluN?s>k z?1<7%67^eJzD6?k88qTD>OBaPmf|bo!V;$L-KR9ZfL_RhzAPF`4hl<{I+ICjd>7Hi zeEh3~CCt)tVY0@*MPrIGOK%Uivthl^n2moGmTN|sI<`G)F^d`h7L6&e4rhd^RU(1? zz$9g3Xw1sHN*G3&31Q;H!v0wdUI+D(cZ9Ut!`SdFoY$9 z5*R1PGLt!n_O(sJ!dn=^s(_^uQR*f$4Wa5tdxOIfZ()>uE63iG6C*j7)VCOry>ugg za`8%vw=mX$rQ_kY$TcGV4AmRug#Z5J8{#S6)n1i1md+g)J}DSu#))|Z&D+(94c2dC z35|%ScvpL@0?WX&KYpHZS$~Cveg@@Ub+VtjXt8X*(PU4H=UVMLuq2F5Mz0vQ@{^CE zEJ>fwSkj6vtgt(HHq~{tmbT{MFs8=%K-ZQ`cxB5Rwo_aV=n06u9-B+Jos4S5ANM>~ zxb(vGAoh**Q4=g_U(C(f16^(NfnwV%Y1N9ZC`uE`{o*dx!x^p2N4fCtKW{sK-mRBh z7c2sSpLpZ7`9Cgae2aJm$M)=x&TKn*vMyA#$n_Qzdk=O5 z*!1Ft_AV}5Jy897?co*JOk)2(wnA$B`Q#~2N33VCOmBAoJ539B{(2-}1Gv1VP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR919-spN1ONa40RR919smFU0Lno(1poj8e@R3^R7ef&mP<%fVHC%`cgC4f z#xx&U7^Rp&5=0vpK|!tC6ljp3qh*!@MiXtag%DAjBm~V@Iu7VUp;bt$S{N;A5kV+a zk_l3oQ!_c~Jhk7Exx>udF++qvJn-lH?sy#h+A1GcudnsReu)B%Ql>EFT7_@ykXl(;86vwIIBm+x%6dh~!;+toFCmp>#hH{n6u1Roo6u^o6rW!s3+e=D`Lw@o1? zmdWSy?d6sj78Vv}lAR(qcs!m`BgEvITr)6tIM&CLouqnpyWIt})$7R0XqWf6$FVz4 zA256_3I38#}r02e7+^{R#FKR%yw{kVywT z1YS=}Of2gHGswLNKY3Y51wEX=1P*qixFRGugjE#+%xne8G6aGFDl(rwXYz6)Ra_4|DP)Ws1 P00000NkvXXu0mjfc&p5k diff --git a/app/src/main/res/drawable-mdpi/ic_retweeted.png b/app/src/main/res/drawable-mdpi/ic_retweeted.png deleted file mode 100644 index 39545e5000e32f187b913d702e341352d48a1689..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1144 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 RbR_@)002ovPDHLkV1mUGX$1fP diff --git a/app/src/main/res/drawable-xhdpi/ic_comment.png b/app/src/main/res/drawable-xhdpi/ic_comment.png deleted file mode 100644 index 6687355e0cf252a28577b95b365db97f39ba4033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2884 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 diff --git a/app/src/main/res/drawable-xhdpi/ic_liked.png b/app/src/main/res/drawable-xhdpi/ic_liked.png deleted file mode 100644 index d6f1bb5c41798bb9123140860f07a0d6019e4dfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2256 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 Me_XLo?fsMf3kJSslmGw# diff --git a/app/src/main/res/drawable-xhdpi/ic_retweeted.png b/app/src/main/res/drawable-xhdpi/ic_retweeted.png deleted file mode 100644 index 2b1222f982e999021842fefba881b83171ca329a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2103 zcmY*aXE+-Q8%>PXO6w7%w%lqFqd`?;q^KZ4iZo41&4}82a}%?~rfEynmfAIIk1Fb> zMy*n#R_hiuI;>vn>Ywj>?sJ~=p7Xxv{C{btSOXB3Fc$y-0HF=_%uiMGH#yFnPW8hn zpHl()nj7c>UJQw@o-TT1BHGc!1OPkr8~|XfGl1=P<&?sw1OQm`fB@E01^&L}vHUO9 z%wzq(|6NR&U%dwaoXtn;>D+c=->`6Y`r`^8q>8E)CZ+dd2-xGWQPK zS3NdrX0lOFcDmaf0t4nwj@wT{RgO-K;*@yU{)^X9fcNFQ8>Fd^_LUPl#XL)e5TtS`*vbO2I+H=8IO9vbc5GWnJPOA!O<$uWR)Qm; z6YS~y)!xcP{Co7+ko@7&D`IGK1~EGCh`!U&*S$52UD;j$@mz zazhi=9X`z8u;92g^RQ(nUtD1WCk!7_ZC13Wa&gBCu1o9)^B$l7=B19V>Y}pfS2u7sqdj0`bfRJ`OHJ+YV7Zq$ zePOQ($uLa#6#e6<38EdB#xcb3DGbf|z@>m&{3Uqn3~h{jy^($8k4CV!5b%If_p%V8 z0E|LxIACknpKmP=SOP~L+aiL)4Vd~vL?P_d^c}mm*(OOTkgi!m#zDVEuCA19?p>$H z8?A@Ycjn-SCAfVF(@+LV^`*VUUY*rIqOB zkX*J}BG0H=r{nt#v;)+fknn$W407b<8V2Hxtgw!zp(xO4hf{8Il6-ByB~5OvV`%EZz_#(lm#igQO*;$gCQs z!i8=~iX)gaVyW@67%HZJ;)2?454p%k^;vtw*K57Tfnu4}?XV2$!91+=A^zQ&HlB^} zWR0e|KGy{kMY)b6G2>nw!`0IQw6~?1j9II@OJ0XrFS?XSQMWD}F+6)C)$0Qfch?dh zA}sl*!jj>r#zNO~%V&C;z!9;;%`Qyb#j|#7SrQ`~BQq08!>VBn&oG2ynqAS!1iZtIG)NFN1 zHNYDbP-4{C5J|ex`@RA%IsYVCpmg}m=##_jhRWzs1Yz*V(n8BPcYkd8>G4Ke5Q?l~ zW?*R|)$+#SagN6 zK!@t*>vt3MrH!S&RagvLsQa|HU{FqFH;lKMcwZwY%k9zflvDRWtnU$2F3e4P$~o5o zGl9Xj+#%B9opovRl|p@x`$bfe8|DLxq6BX9cIGemp@4#@jlXh)57KhulZDNsWT4BW zp`t32ALR(v_k~8Sl?u9Pg&hqr={J|FATCL)RzMAXeuN#*gJy8N>4MbFC46PyMUQS} zQE-9_gV+I{h_}rfbuBt;u7JB^k|k7FNw(!b4;~K90ZBZO9GF``jnKw@F%xBX%mdg| z)!fgpSph>cue{EvqJp~%e_71fWjXoBxQ88;wOg+`!gM|cYmJt^zs55ZehWNvK|E1^ zO|yq~PFf~&_)#>EJiEzPgAg zc8&1ACt?i@14SyBHMtgk0-bbmQ9jCU;3zULgIL8^`qM-wl_rM+sQW>>ZA&~oq}Wkt z$miXZI*7^;A$)R1hBqh;w(?XwNnM+yNR+sA)6Ey5#(6q<-OK5nLN3md)pR<0?ix zdg0;s@bkaM^+krG0@k-;%^T;|OIphh){UnA{>P%fpZ>HW>HFXf2@z}IAHPN(QKB3r fZT|ya7z>qEY$9h|d?`iw_tQqBuzD|aZ6p5$y9vP! diff --git a/app/src/main/res/drawable-xhdpi/ic_search.png b/app/src/main/res/drawable-xhdpi/ic_search.png deleted file mode 100644 index 1da2ab0b47a20d4b9a5cb1803f8843c2c8918ede..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2992 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 diff --git a/app/src/main/res/drawable-xxhdpi/ic_comment.png b/app/src/main/res/drawable-xxhdpi/ic_comment.png deleted file mode 100644 index b73c0d8806bc9c58f8fb9a4004e96f7f76722272..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3755 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 VNw1*M^iBW(002ovPDHLkV1mmA+2;TN diff --git a/app/src/main/res/drawable-xxhdpi/ic_like.png b/app/src/main/res/drawable-xxhdpi/ic_like.png deleted file mode 100644 index 0ad7f67cda5b45f24c9c22277e5f40efa0b45ef6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4204 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 RL~Q^7002ovPDHLkV1mtiUuggU diff --git a/app/src/main/res/drawable-xxhdpi/ic_retweet.png b/app/src/main/res/drawable-xxhdpi/ic_retweet.png deleted file mode 100644 index ec694172782049d1990c2eac27bb7de01c82ac72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2469 zcmZ`*X*3iH8=f(iu}o&H!(xOp7TD0Tjquk4q*-e001#I(z7^a+g|{) zp2n+XI!vbo^s_M31yl{3T{$iETy2cq%*+6?r#Tn^jClZH{v|nu@F@TQP(Bayd|MFi# z@@6dOeSNB$y-fCP0khk&YECfln3OGM%A!a+LgOPFFP|QtX)Hn5I22G!ma&nEiYq3c zoM}1q)!1v0%WtNTEox4T0lPW=J13X?D}A=E(oTt18n#{Nqw zegJOQE5F~LrHU4J4ly({UQ!|K+UlG#8MHD++vkon&) z9k1Y>?d+xnS5{V*nyle#*5cxWuImUFkPB=yBBvF%K_h&QmF%EU&VZIRQ@X&;UO@+m zNK%vULeD^WcsSc9_*$9ggy@U(^zmwwbosZL51(ZZ`LH{<;qm*6)6>(@ZU<2=l@85; zN{*z`h<*L&_3w&>JTt?+Jv}YHo~<6}3DKEXmZjH1QE2`mvIccvZKiS0k7MQ$@xrC* z;kNUAF(tiy`xLXJmzS<;~cnq^B=p25Wiw;-Wvi;^*f_%mf%X zIXT7jrYmTHmg`@RS63EzDK1AA!5Kd!xl02DcMx3yr4f6AJJQO^%1>1&@8#xSaHYmb zej6zC>L$v~UBJXHe!<{^shLb%jp3tFxp{1S^HSIM-~w%IQLkTo9Oz&zqN)CO!xSh&(ly0m_URTYCi))!tmrCgG4Cj#(6yQXTS=T7+_^vs?bU; zO`Ix`!FHFw%i7!D-hPHUGBTocrKbaXlC_7>NbH3Fp81@r*QuHpt}Uh&(v(xY-W1Wa%O^fVDCPePxFZGX`@InRD4vXIoAOdoSq!RT9BSX4Q_39uPy;(Ft%_`(_R z$(mZ`FziY#B(0Qsfw)VgCH_1O`18_ zqVT#cXoHtY^VN`OW!Nq|FmD8#G^TwR8H)BG8+ztH(QT7fr4|0OMiV&0Xr0wu*|CQh zA{gs`os%(N(nd>_R;3jc7awmFBkism&;4w#=sMeVyWYFIyE~hyl%uM=K^|p0um|+H zfRR_||LV|3I$I+qy98+lG?tYupJ|&R9NBHZ&FPUXtE$R%PWw)fP>4^ci5EmL169_4-xoI(7;=Y%*8o=RTuqK_m<*3 zYnk)V9Yc9Yj(bxNE`dXO7Xh;-$$l^ysepS3(x=X9ObukVvLN~BkS7;&XB3#}y7Ct; zG_d38ZBTTbq{D1XPH_l&03mETuD!Q9S|J*iW?2$Iwmau($sU7c+!eI8aC4q`fS7N8 zy9d~fP5TILd=}*4>DgNJHz2#kH}r|30#yTF*}UiO#@n8`Zj*oU&H@fla0e`MT$%|vsc72nK8Cv zq#I?5{PEIV^lrCrhI$%x&I+e;2qTs{?kNFM?%nq&XL@75nQH+*#P&j1OiZJ3F#LCA z&qd4nP_F)F!(K-L(6zD<)78buf=Rn~Px);16h2=X?p3!8f*{Qk&s2<0>zVm$r-=pK z9tJ_zwbL+7b04EPeH$kPTwr{PP}5p=cpVGI11>u+m$X5vUDHu@Ak5Vz$9DTJYlU zFlJh_FIyKpdx_yJ>4jEX-m8dj1i?`~b+nGc2{A{?MZX3C2 zgg_nPO0LyJu^7z9+UCLL=amcp<}Uuvdx+bDkJ!L_vPA$b&GG+QBz<$eDqY9${{U^o Ba`XTI diff --git a/app/src/main/res/drawable-xxhdpi/ic_retweeted.png b/app/src/main/res/drawable-xxhdpi/ic_retweeted.png deleted file mode 100644 index 5a3025a57b6ac4f8bdfd0b9d431f68ae28f944b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2778 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 Yf2+04U%3BY^Z)<=07*qoM6N<$f-o3b8~^|S diff --git a/app/src/main/res/drawable-xxhdpi/ic_share.png b/app/src/main/res/drawable-xxhdpi/ic_share.png deleted file mode 100644 index 63728b0ed4ede4ce5d021e276dfa1edc3241043e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2204 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 D*scqt diff --git a/app/src/main/res/drawable-xxxhdpi/ic_comment.png b/app/src/main/res/drawable-xxxhdpi/ic_comment.png deleted file mode 100644 index 924df61350be768124669ed0c28250cd99d8755b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5825 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 LNkvXXu0mjfu6ye+ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_like.png b/app/src/main/res/drawable-xxxhdpi/ic_like.png deleted file mode 100644 index 2883a6428fd3d48c16f3d79160e4b8a76dcc7033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6610 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 CL8XKM diff --git a/app/src/main/res/drawable-xxxhdpi/ic_liked.png b/app/src/main/res/drawable-xxxhdpi/ic_liked.png deleted file mode 100644 index 526a708089bec667f0c75ab7068ec805611efe84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4479 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 Q+yDRo07*qoM6N<$f>+~$BLDyZ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_share.png b/app/src/main/res/drawable-xxxhdpi/ic_share.png deleted file mode 100644 index 1b556d7dd0af62fcb97b4856c38a6aeb4c22943a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3261 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 Unit, +) = path( + fill = SolidColor(Color.Black), + fillAlpha = fillAlpha, + stroke = null, + strokeAlpha = strokeAlpha, + strokeLineWidth = 1f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Bevel, + strokeLineMiter = 1f, + pathFillType = pathFillType, + pathBuilder = pathBuilder, +) + +inline fun materialIcon( + name: String, + autoMirror: Boolean = false, + block: ImageVector.Builder.() -> ImageVector.Builder, +): ImageVector = + ImageVector + .Builder( + name = name, + defaultWidth = 24.dp, + defaultHeight = 24.dp, + viewportWidth = 24f, + viewportHeight = 24f, + autoMirror = autoMirror, + ).block() + .build() From 548dd9e34ff3f7d7442acfad0641535addd36f0a Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 18:20:58 -0400 Subject: [PATCH 16/45] Makes sure the isAcceptable runs on IO thread --- .../amethyst/ui/screen/loggedIn/AccountViewModel.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index e0833cf901..294300cf0d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -269,6 +269,8 @@ class AccountViewModel( accountChoices: Account.LiveHiddenUsers, followUsers: Set, ): NoteComposeReportState { + checkNotInMainThread() + val isFromLoggedIn = note.author?.pubkeyHex == userProfile().pubkeyHex val isFromLoggedInFollow = note.author?.let { followUsers.contains(it.pubkeyHex) } ?: true val isPostHidden = note.isHiddenFor(accountChoices) @@ -310,7 +312,11 @@ class AccountViewModel( note.flow().metadata.stateFlow, note.flow().reports.stateFlow, ) { hiddenUsers, followingUsers, metadata, reports -> - emit(isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.users)) + val isAcceptable = + withContext(Dispatchers.IO) { + isNoteAcceptable(metadata.note, hiddenUsers, followingUsers.users) + } + emit(isAcceptable) }.stateIn( viewModelScope, SharingStarted.Eagerly, From a23cbd1a388477c3572dce5da3eab2ed7325c68f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 18:21:27 -0400 Subject: [PATCH 17/45] Formatting --- .../amethyst/service/relays/Relay.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index 8bb9f95f66..ab7108d842 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -87,9 +87,7 @@ class Relay( listeners = listeners.minus(listener) } - fun isConnected(): Boolean { - return socket != null - } + fun isConnected(): Boolean = socket != null fun connect() { connectAndRun { @@ -123,7 +121,8 @@ class Relay( lastConnectTentative = TimeUtils.now() val request = - Request.Builder() + Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url(url.trim()) .build() @@ -141,7 +140,9 @@ class Relay( } } - inner class RelayListener(val onConnected: (Relay) -> Unit) : WebSocketListener() { + inner class RelayListener( + val onConnected: (Relay) -> Unit, + ) : WebSocketListener() { override fun onOpen( webSocket: WebSocket, response: Response, @@ -524,12 +525,11 @@ class Relay( writeToSocket("""["CLOSE","$subscriptionId"]""") } - fun isSameRelayConfig(other: RelaySetupInfo): Boolean { - return url == other.url && + fun isSameRelayConfig(other: RelaySetupInfo): Boolean = + url == other.url && write == other.write && read == other.read && activeTypes == other.feedTypes - } enum class StateType { // Websocket connected From 224e54cc721f4c5aab52e523061374b78072ab70 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Tue, 18 Jun 2024 22:23:30 +0000 Subject: [PATCH 18/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-pl-rPL/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index f9d3b679a7..51949274ab 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -1,6 +1,6 @@ - Najedź na kod QR + Najedź na QR kod Pokaż QR kod Zdjęcie profilowe Twoje zdjęcie profilowe @@ -451,6 +451,7 @@ Nigdy Kompletny Uproszczony + Wydajność Automatyczny Jasny Ciemny From a463e8889cee787fee62cc544dd9ac0f626fbf09 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 18:59:41 -0400 Subject: [PATCH 19/45] Adds an outlined Zap icon to match the other icons --- .../vitorpamplona/amethyst/ui/note/Icons.kt | 16 ++++ .../amethyst/ui/note/ReactionsRow.kt | 2 +- .../amethyst/commons/icons/Zap.kt | 81 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index ccaff8826f..5d62d22d3c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -71,6 +71,7 @@ import com.vitorpamplona.amethyst.commons.icons.Reply import com.vitorpamplona.amethyst.commons.icons.Repost import com.vitorpamplona.amethyst.commons.icons.Reposted import com.vitorpamplona.amethyst.commons.icons.Search +import com.vitorpamplona.amethyst.commons.icons.Zap import com.vitorpamplona.amethyst.commons.icons.ZapSplit import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.Size18Modifier @@ -239,6 +240,7 @@ fun ReactionRowIconPreview() { CommentIcon(Size20Modifier, Color.Unspecified) RepostedIcon(Size20Modifier) LikeIcon(Size20Modifier, Color.Unspecified) + OutlinedZapIcon(Size20Modifier) ZapIcon(Size20Modifier) ZappedIcon(Size20Modifier) } @@ -258,6 +260,20 @@ fun ZapIcon( ) } +@Composable +fun OutlinedZapIcon( + modifier: Modifier, + tint: Color = Color.Unspecified, + contentDescriptor: Int = R.string.zap_description, +) { + Icon( + imageVector = Zap, + contentDescription = stringResource(contentDescriptor), + tint = tint, + modifier = modifier, + ) +} + @Composable fun CashuIcon(modifier: Modifier) { Icon( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 4b27dcd23b..775798ef47 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -1094,7 +1094,7 @@ fun ZapReaction( if (it) { ZappedIcon(iconSizeModifier) } else { - ZapIcon(iconSizeModifier, grayTint) + OutlinedZapIcon(iconSizeModifier, grayTint) } } } diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt new file mode 100644 index 0000000000..c5caf56ca4 --- /dev/null +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.icons + +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.vector.DefaultFillType +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.PathBuilder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview + +@Preview +@Composable +private fun VectorPreview() { + Image(Zap, null) +} + +private var zap: ImageVector? = null + +val Zap: ImageVector + get() = + zap ?: materialIcon(name = "Zap") { + materialOutlinedPath { + moveTo(11.0f, 21.0f) + horizontalLineToRelative(-1.0f) + lineToRelative(1.0f, -7.0f) + horizontalLineTo(7.5f) + curveToRelative(-0.58f, 0.0f, -0.57f, -0.32f, -0.38f, -0.66f) + curveToRelative(0.19f, -0.34f, 0.05f, -0.08f, 0.07f, -0.12f) + curveTo(8.48f, 10.94f, 10.42f, 7.54f, 13.0f, 3.0f) + horizontalLineToRelative(1.0f) + lineToRelative(-1.0f, 7.0f) + horizontalLineToRelative(3.5f) + curveToRelative(0.49f, 0.0f, 0.56f, 0.33f, 0.47f, 0.51f) + lineToRelative(-0.07f, 0.15f) + curveTo(12.96f, 17.55f, 11.0f, 21.0f, 11.0f, 21.0f) + close() + } + }.also { zap = it } + +inline fun ImageVector.Builder.materialOutlinedPath( + fillAlpha: Float = 1f, + strokeAlpha: Float = 1f, + pathFillType: PathFillType = DefaultFillType, + pathBuilder: PathBuilder.() -> Unit, +) = path( + fill = null, + fillAlpha = fillAlpha, + stroke = SolidColor(Color.Black), + strokeAlpha = strokeAlpha, + strokeLineWidth = 1.4f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Bevel, + strokeLineMiter = 1f, + pathFillType = pathFillType, + pathBuilder = pathBuilder, +) From 442322f708d550e64f7812d2fed4ad650ce8af0f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 19:00:10 -0400 Subject: [PATCH 20/45] Removes the alpha channel for the performance placeholder painter --- .../vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt index 35aa692d3a..6a6d673225 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt @@ -123,7 +123,6 @@ fun RobohashFallbackAsyncImage( image = Icons.Default.Face, ), colorFilter = MaterialTheme.colorScheme.onBackgroundColorFilter, - alpha = 0.5f, ) } From f28d96d303e1f7bb3af43aa30f7ef324e108c94f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 19:00:26 -0400 Subject: [PATCH 21/45] removes remember from LoadUrlPreview --- .../vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt index 70a6f97e1f..7ef2508c6c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.model.UrlCachedPreviewer @@ -39,9 +38,7 @@ fun LoadUrlPreview( callbackUri: String? = null, accountViewModel: AccountViewModel, ) { - val automaticallyShowUrlPreview = remember { accountViewModel.settings.showUrlPreview.value } - - if (!automaticallyShowUrlPreview) { + if (!accountViewModel.settings.showUrlPreview.value) { ClickableUrl(urlText, url) } else { val urlPreviewState by From 5da9e430b0d0cb0dddf4411b11d424698515ca91 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 19:33:04 -0400 Subject: [PATCH 22/45] Get's rid of the view count. --- .../vitorpamplona/amethyst/ui/note/Icons.kt | 29 +++--- .../amethyst/ui/note/ReactionsRow.kt | 91 +++++++++---------- .../ui/screen/loggedIn/VideoScreen.kt | 9 -- .../vitorpamplona/amethyst/ui/theme/Shape.kt | 2 +- .../amethyst/commons/icons/Zap.kt | 2 +- 5 files changed, 61 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index 5d62d22d3c..f35750f112 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -44,8 +44,8 @@ import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.PushPin import androidx.compose.material.icons.filled.Report +import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.outlined.ArrowForwardIos -import androidx.compose.material.icons.outlined.BarChart import androidx.compose.material.icons.outlined.Bolt import androidx.compose.material.icons.outlined.PlayCircle import androidx.compose.material3.Icon @@ -243,6 +243,7 @@ fun ReactionRowIconPreview() { OutlinedZapIcon(Size20Modifier) ZapIcon(Size20Modifier) ZappedIcon(Size20Modifier) + ShareIcon(Size20Modifier, Color.Unspecified) } } @@ -274,6 +275,19 @@ fun OutlinedZapIcon( ) } +@Composable +fun ShareIcon( + modifier: Modifier, + tint: Color = Color.Unspecified, +) { + Icon( + imageVector = Icons.Default.Share, + modifier = modifier, + contentDescription = stringResource(R.string.share_or_save), + tint = tint, + ) +} + @Composable fun CashuIcon(modifier: Modifier) { Icon( @@ -349,19 +363,6 @@ fun CommentIcon( ) } -@Composable -fun ViewCountIcon( - modifier: Modifier, - tint: Color = Color.Unspecified, -) { - Icon( - imageVector = Icons.Outlined.BarChart, - null, - modifier = modifier, - tint = tint, - ) -} - @Composable fun PollIcon() { Icon( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 775798ef47..11db3728ec 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.ui.note import android.content.Context +import android.content.Intent import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform @@ -75,7 +76,6 @@ import androidx.compose.ui.Alignment.Companion.CenterStart import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource @@ -87,13 +87,11 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Popup +import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map -import coil.compose.AsyncImage -import coil.request.CachePolicy -import coil.request.ImageRequest import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.Note @@ -109,7 +107,6 @@ import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DarkerGreen import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer -import com.vitorpamplona.amethyst.ui.theme.Height24dpModifier import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp import com.vitorpamplona.amethyst.ui.theme.NoSoTinyBorders import com.vitorpamplona.amethyst.ui.theme.ReactionRowExpandButton @@ -202,15 +199,51 @@ private fun InnerReactionRow( ZapReaction(baseNote, MaterialTheme.colorScheme.placeholderText, accountViewModel, nav = nav) }, six = { - // ViewCountReaction( - // note = baseNote, - // grayTint = MaterialTheme.colorScheme.placeholderText, - // viewCountColorFilter = MaterialTheme.colorScheme.placeholderTextColorFilter, - // ) + ShareReaction( + note = baseNote, + grayTint = MaterialTheme.colorScheme.placeholderText, + ) }, ) } +@Composable +fun ShareReaction( + note: Note, + grayTint: Color, + barChartModifier: Modifier = Size19Modifier, +) { + val context = LocalContext.current + + IconButton( + modifier = barChartModifier, + onClick = { + val sendIntent = + Intent().apply { + action = Intent.ACTION_SEND + type = "text/plain" + putExtra( + Intent.EXTRA_TEXT, + externalLinkForNote(note), + ) + putExtra( + Intent.EXTRA_TITLE, + context.getString(R.string.quick_action_share_browser_link), + ) + } + + val shareIntent = + Intent.createChooser( + sendIntent, + context.getString(R.string.quick_action_share), + ) + ContextCompat.startActivity(context, shareIntent, null) + }, + ) { + ShareIcon(barChartModifier, grayTint) + } +} + @Composable private fun GenericInnerReactionRow( showReactionDetail: Boolean, @@ -244,7 +277,7 @@ private fun GenericInnerReactionRow( Row(verticalAlignment = CenterVertically, modifier = Modifier.weight(1f)) { five() } - Row(verticalAlignment = CenterVertically, modifier = Modifier.weight(1f)) { six() } + Row(verticalAlignment = CenterVertically, modifier = Modifier) { six() } } } @@ -1201,42 +1234,6 @@ fun ObserveZapAmountText( } } -@Composable -fun ViewCountReaction( - note: Note, - grayTint: Color, - barChartModifier: Modifier = Size19Modifier, - numberSizeModifier: Modifier = Height24dpModifier, - viewCountColorFilter: ColorFilter, -) { - ViewCountIcon(barChartModifier, grayTint) - DrawViewCount(note, numberSizeModifier, viewCountColorFilter) -} - -@Composable -private fun DrawViewCount( - note: Note, - iconModifier: Modifier = Modifier, - viewCountColorFilter: ColorFilter, -) { - val context = LocalContext.current - - AsyncImage( - model = - remember(note) { - ImageRequest - .Builder(context) - .data("https://counter.amethyst.social/${note.idHex}.svg?label=+&color=00000000") - .diskCachePolicy(CachePolicy.DISABLED) - .memoryCachePolicy(CachePolicy.ENABLED) - .build() - }, - contentDescription = context.getString(R.string.view_count), - modifier = iconModifier, - colorFilter = viewCountColorFilter, - ) -} - @OptIn(ExperimentalLayoutApi::class) @Composable private fun BoostTypeChoicePopup( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index 4cb6782515..d88d5de76c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -73,7 +73,6 @@ import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay import com.vitorpamplona.amethyst.ui.note.RenderAllRelayList import com.vitorpamplona.amethyst.ui.note.ReplyReaction -import com.vitorpamplona.amethyst.ui.note.ViewCountReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.note.types.FileHeaderDisplay @@ -92,12 +91,10 @@ import com.vitorpamplona.amethyst.ui.theme.AuthorInfoVideoFeed import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size35Modifier import com.vitorpamplona.amethyst.ui.theme.Size35dp -import com.vitorpamplona.amethyst.ui.theme.Size39Modifier import com.vitorpamplona.amethyst.ui.theme.Size40Modifier import com.vitorpamplona.amethyst.ui.theme.Size40dp import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.VideoReactionColumnPadding -import com.vitorpamplona.amethyst.ui.theme.onBackgroundColorFilter import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.FileStorageHeaderEvent @@ -444,11 +441,5 @@ fun ReactionsColumn( animationSize = Size35dp, nav = nav, ) - ViewCountReaction( - note = baseNote, - grayTint = MaterialTheme.colorScheme.onBackground, - barChartModifier = Size39Modifier, - viewCountColorFilter = MaterialTheme.colorScheme.onBackgroundColorFilter, - ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt index 5f3bce586b..dd4d233a63 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt @@ -157,7 +157,7 @@ val VideoReactionColumnPadding = Modifier.padding(bottom = 75.dp) val DividerThickness = 0.25.dp val ReactionRowHeight = Modifier.padding(vertical = 7.dp).height(24.dp) -val ReactionRowHeightWithPadding = Modifier.padding(vertical = 7.dp).height(24.dp).padding(start = 10.dp) +val ReactionRowHeightWithPadding = Modifier.padding(vertical = 7.dp).height(24.dp).padding(horizontal = 10.dp) val ReactionRowHeightChat = Modifier.height(25.dp) val UserNameRowHeight = Modifier.fillMaxWidth() val UserNameMaxRowHeight = Modifier.fillMaxWidth() diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt index c5caf56ca4..5617c78cd8 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt @@ -72,7 +72,7 @@ inline fun ImageVector.Builder.materialOutlinedPath( fillAlpha = fillAlpha, stroke = SolidColor(Color.Black), strokeAlpha = strokeAlpha, - strokeLineWidth = 1.4f, + strokeLineWidth = 1.3f, strokeLineCap = StrokeCap.Butt, strokeLineJoin = StrokeJoin.Bevel, strokeLineMiter = 1f, From 614e9ff661275f27109766811f02dfca43d25a14 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 19:33:22 -0400 Subject: [PATCH 23/45] Correctly tints the search button --- .../vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt | 3 +-- .../java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt | 3 +-- .../vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt index 373b28c438..996f09c6e5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt @@ -59,7 +59,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource @@ -285,7 +284,7 @@ private fun SearchEditTextForJoin( searchBarViewModel.updateSearchValue(it) scope.launch(Dispatchers.IO) { searchTextChanges.trySend(it) } }, - leadingIcon = { SearchIcon(modifier = Size20Modifier, Color.Unspecified) }, + leadingIcon = { SearchIcon(modifier = Size20Modifier, MaterialTheme.colorScheme.placeholderText) }, modifier = Modifier .weight(1f, true) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index 7406e60e94..48245d22c3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -61,7 +61,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -569,7 +568,7 @@ private fun SearchButton(onClick: () -> Unit) { IconButton( onClick = onClick, ) { - SearchIcon(modifier = Size22Modifier, Color.Unspecified) + SearchIcon(modifier = Size22Modifier, MaterialTheme.colorScheme.placeholderText) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt index 27e6bb35f9..29deb85c3e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt @@ -330,7 +330,7 @@ private fun SearchTextField( KeyboardOptions.Default.copy( capitalization = KeyboardCapitalization.Sentences, ), - leadingIcon = { SearchIcon(modifier = Size20Modifier, Color.Unspecified) }, + leadingIcon = { SearchIcon(modifier = Size20Modifier, MaterialTheme.colorScheme.placeholderText) }, modifier = Modifier .weight(1f, true) From 6550bdefd5ebd803343ee9d96f53661d2660ae7c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 18 Jun 2024 19:34:43 -0400 Subject: [PATCH 24/45] Thinner Zap button --- .../main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt index 5617c78cd8..bd45756ed1 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/icons/Zap.kt @@ -72,7 +72,7 @@ inline fun ImageVector.Builder.materialOutlinedPath( fillAlpha = fillAlpha, stroke = SolidColor(Color.Black), strokeAlpha = strokeAlpha, - strokeLineWidth = 1.3f, + strokeLineWidth = 1.2f, strokeLineCap = StrokeCap.Butt, strokeLineJoin = StrokeJoin.Bevel, strokeLineMiter = 1f, From 157fad6a845e67b2a924da671a27f445bdaeac3f Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 19 Jun 2024 12:48:33 +0000 Subject: [PATCH 25/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-hi-rIN/strings.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index c1fc16b02b..9284d42163 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -8,7 +8,7 @@ फिर भी दिखाएँ इस प्रकाशित पत्र को छिपाया गया क्योंकि इसमें आपके आच्छाद्य उपयोगकर्ता अथवा शब्द उल्लेखित हैं प्रकाशित पत्र को मौन किया गया अथवा सूचित किया गया इनके द्वारा - घटना उपलब्ध किया जा रहा है अथवा आपके पुनःप्रसारक सूची में से प्राप्त नहीं + घटना उपलब्ध की जा रही है अथवा आपके पुनःप्रसारक सूची में से प्राप्त नहीं प्रणाली चित्र उद्धृत घटना अप्राप्त सन्देश का अरहस्यीकरण असफल @@ -419,13 +419,13 @@ न्यूनतम श्रमप्रमाण प्रमाणीकरण भुगतान - काशयु लिपिखण्ड + काशयु राशिखण्ड चुकाएँ ज्साप धनकोष को भेजें काशयु धनकोष में खोलें - लिपिखण्ड की अनुकृति करें + राशिखण्ड की अनुकृति करें कोई लैटनिंग पता स्थापित नहीं - लिपिखण्ड की अनुकृति की गयी टाँकाफलक में + राशिखण्ड की अनुकृति की गयी टाँकाफलक में तत्क्षणप्रसार जालरहित समाप्त @@ -451,6 +451,7 @@ कभी नहीं सम्पूर्ण सरलीकृत + प्रदर्शन यन्त्रव्यवस्था प्रकाशवान अन्धकारमय @@ -559,7 +560,7 @@ निप॰-४७ संयोजन सूत्र परखने में अपक्रम। जाँच करें यदि यह सम्यक है अपने धनकोष सेवा प्रदाता के साथ : %1$s। काशयु नहीं चुका पाए टकसाल ने यह अपक्रम संदेश उपलब्ध किया : %1$s - काशयु लिपिखण्ड का व्यय हो चुका। + काशयु राशिखण्ड का व्यय हो चुका। काशयु प्राप्त %1$s साट्स भेजे गये आपके धनकोष में। (शुल्क : %2$s साट्स) कोई अनुकूल काशयु धनकोष उपलब्ध नहीं यन्त्र में From e9456af15c645a4b9a105eeb0730d916b1138efb Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 08:48:41 -0400 Subject: [PATCH 26/45] Fixes the inconsistency of button animations in the reaction row --- .../amethyst/ui/note/ReactionsRow.kt | 48 +++++++++++++------ .../amethyst/ui/note/RelayListRow.kt | 3 +- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 11db3728ec..54fe2c103a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -34,6 +34,7 @@ import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.animation.togetherWith import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement @@ -51,7 +52,6 @@ import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.IconButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ProgressIndicatorDefaults @@ -215,7 +215,7 @@ fun ShareReaction( ) { val context = LocalContext.current - IconButton( + ClickableBox( modifier = barChartModifier, onClick = { val sendIntent = @@ -412,7 +412,7 @@ private fun RenderShowIndividualReactionsButton( wantsToSeeReactions: MutableState, accountViewModel: AccountViewModel, ) { - IconButton( + ClickableBox( onClick = { wantsToSeeReactions.value = !wantsToSeeReactions.value }, modifier = Size20Modifier, ) { @@ -609,6 +609,24 @@ private fun ReplyReactionWithDialog( ReplyReaction(baseNote, grayTint, accountViewModel) { wantsToReplyTo = baseNote } } +@Composable +fun ClickableBox( + modifier: Modifier, + onClick: () -> Unit, + content: @Composable () -> Unit, +) { + Box( + modifier.clickable( + role = Role.Button, + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(bounded = false, radius = Size24dp), + onClick = onClick, + ), + ) { + content() + } +} + @Composable fun ReplyReaction( baseNote: Note, @@ -618,7 +636,7 @@ fun ReplyReaction( iconSizeModifier: Modifier = Size19Modifier, onPress: () -> Unit, ) { - IconButton( + ClickableBox( modifier = iconSizeModifier, onClick = { if (baseNote.isDraft()) { @@ -626,15 +644,15 @@ fun ReplyReaction( R.string.draft_note, R.string.it_s_not_possible_to_reply_to_a_draft_note, ) - return@IconButton - } - if (accountViewModel.isWriteable()) { - onPress() } else { - accountViewModel.toast( - R.string.read_only_user, - R.string.login_with_a_private_key_to_be_able_to_reply, - ) + if (accountViewModel.isWriteable()) { + onPress() + } else { + accountViewModel.toast( + R.string.read_only_user, + R.string.login_with_a_private_key_to_be_able_to_reply, + ) + } } }, ) { @@ -747,9 +765,11 @@ fun BoostReaction( ) { var wantsToBoost by remember { mutableStateOf(false) } - IconButton( + ClickableBox( modifier = iconSizeModifier, - onClick = { accountViewModel.tryBoost(baseNote) { wantsToBoost = true } }, + onClick = { + accountViewModel.tryBoost(baseNote) { wantsToBoost = true } + }, ) { ObserveBoostIcon(baseNote, accountViewModel) { hasBoosted -> RepostedIcon(iconSizeModifier, if (hasBoosted) Color.Unspecified else grayTint) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt index 4dd5231a95..e7cccd1bd4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -88,7 +87,7 @@ fun ShouldShowExpandButton( @Composable fun ChatRelayExpandButton(onClick: () -> Unit) { - IconButton( + ClickableBox( modifier = Size15Modifier, onClick = onClick, ) { From bff662b85d8279a113bb285a47e5e01f680070b1 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 19 Jun 2024 12:53:07 +0000 Subject: [PATCH 27/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-hi-rIN/strings.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index c1fc16b02b..9284d42163 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -8,7 +8,7 @@ फिर भी दिखाएँ इस प्रकाशित पत्र को छिपाया गया क्योंकि इसमें आपके आच्छाद्य उपयोगकर्ता अथवा शब्द उल्लेखित हैं प्रकाशित पत्र को मौन किया गया अथवा सूचित किया गया इनके द्वारा - घटना उपलब्ध किया जा रहा है अथवा आपके पुनःप्रसारक सूची में से प्राप्त नहीं + घटना उपलब्ध की जा रही है अथवा आपके पुनःप्रसारक सूची में से प्राप्त नहीं प्रणाली चित्र उद्धृत घटना अप्राप्त सन्देश का अरहस्यीकरण असफल @@ -419,13 +419,13 @@ न्यूनतम श्रमप्रमाण प्रमाणीकरण भुगतान - काशयु लिपिखण्ड + काशयु राशिखण्ड चुकाएँ ज्साप धनकोष को भेजें काशयु धनकोष में खोलें - लिपिखण्ड की अनुकृति करें + राशिखण्ड की अनुकृति करें कोई लैटनिंग पता स्थापित नहीं - लिपिखण्ड की अनुकृति की गयी टाँकाफलक में + राशिखण्ड की अनुकृति की गयी टाँकाफलक में तत्क्षणप्रसार जालरहित समाप्त @@ -451,6 +451,7 @@ कभी नहीं सम्पूर्ण सरलीकृत + प्रदर्शन यन्त्रव्यवस्था प्रकाशवान अन्धकारमय @@ -559,7 +560,7 @@ निप॰-४७ संयोजन सूत्र परखने में अपक्रम। जाँच करें यदि यह सम्यक है अपने धनकोष सेवा प्रदाता के साथ : %1$s। काशयु नहीं चुका पाए टकसाल ने यह अपक्रम संदेश उपलब्ध किया : %1$s - काशयु लिपिखण्ड का व्यय हो चुका। + काशयु राशिखण्ड का व्यय हो चुका। काशयु प्राप्त %1$s साट्स भेजे गये आपके धनकोष में। (शुल्क : %2$s साट्स) कोई अनुकूल काशयु धनकोष उपलब्ध नहीं यन्त्र में From a0271a2982cefc4aedaa766de803b181d5d30879 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 12:35:25 -0400 Subject: [PATCH 28/45] Moves ClickableBox to it's own file --- .../amethyst/ui/components/ClickableBox.kt | 49 +++++++++++++++++++ .../amethyst/ui/note/ReactionsRow.kt | 20 +------- .../amethyst/ui/note/RelayListRow.kt | 1 + .../amethyst/ui/note/elements/DropDownMenu.kt | 16 ++++-- .../components/TranslatableRichTextViewer.kt | 2 +- 5 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt new file mode 100644 index 0000000000..341e970246 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.material.ripple.rememberRipple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role +import com.vitorpamplona.amethyst.ui.theme.Size24dp + +@Composable +fun ClickableBox( + modifier: Modifier, + onClick: () -> Unit, + content: @Composable () -> Unit, +) { + Box( + modifier.clickable( + role = Role.Button, + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(bounded = false, radius = Size24dp), + onClick = onClick, + ), + ) { + content() + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 54fe2c103a..7ba6115247 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -34,7 +34,6 @@ import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.animation.togetherWith import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement @@ -98,6 +97,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.ZapPaymentHandler import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.NewPostView +import com.vitorpamplona.amethyst.ui.components.ClickableBox import com.vitorpamplona.amethyst.ui.components.GenericLoadable import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer import com.vitorpamplona.amethyst.ui.navigation.routeToMessage @@ -609,24 +609,6 @@ private fun ReplyReactionWithDialog( ReplyReaction(baseNote, grayTint, accountViewModel) { wantsToReplyTo = baseNote } } -@Composable -fun ClickableBox( - modifier: Modifier, - onClick: () -> Unit, - content: @Composable () -> Unit, -) { - Box( - modifier.clickable( - role = Role.Button, - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple(bounded = false, radius = Size24dp), - onClick = onClick, - ), - ) { - content() - } -} - @Composable fun ReplyReaction( baseNote: Note, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt index e7cccd1bd4..9050224366 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt @@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11CachedRetriever import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog +import com.vitorpamplona.amethyst.ui.components.ClickableBox import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt index fbc0d82985..9559ab5750 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt @@ -24,7 +24,6 @@ import android.content.Intent import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable @@ -46,6 +45,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.actions.EditPostView import com.vitorpamplona.amethyst.ui.actions.NewPostView +import com.vitorpamplona.amethyst.ui.components.ClickableBox import com.vitorpamplona.amethyst.ui.components.GenericLoadable import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon import com.vitorpamplona.amethyst.ui.note.externalLinkForNote @@ -67,7 +67,7 @@ fun MoreOptionsButton( ) { val popupExpanded = remember { mutableStateOf(false) } - IconButton( + ClickableBox( modifier = Size24Modifier, onClick = { popupExpanded.value = true }, ) { @@ -388,8 +388,16 @@ fun WatchBookmarksFollowsAndAccount( accountViewModel: AccountViewModel, onNew: (DropDownParams) -> Unit, ) { - val followState by accountViewModel.userProfile().live().follows.observeAsState() - val bookmarkState by accountViewModel.userProfile().live().bookmarks.observeAsState() + val followState by accountViewModel + .userProfile() + .live() + .follows + .observeAsState() + val bookmarkState by accountViewModel + .userProfile() + .live() + .bookmarks + .observeAsState() val showSensitiveContent by accountViewModel.showSensitiveContentChanges.observeAsState( accountViewModel.account.showSensitiveContent, diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 79a4b7ec1c..33d736973d 100644 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -82,7 +82,7 @@ fun TranslatableRichTextViewer( nav: (String) -> Unit, ) { var translatedTextState by - remember(content) { mutableStateOf(TranslationConfig(content, null, null, false)) } + remember(id, content.length) { mutableStateOf(TranslationConfig(content, null, null, false)) } TranslateAndWatchLanguageChanges(content, accountViewModel) { result -> if ( From d39d1239f653cc78a1e61db2878703e35d3e9e6e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 12:36:09 -0400 Subject: [PATCH 29/45] Moves uncited hashtag parsing to a thread --- .../note/elements/DisplayUncitedHashtags.kt | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt index 97c48e96f5..a65af11051 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt @@ -37,7 +37,7 @@ import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.toImmutableListOfLists import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import kotlinx.coroutines.launch @Composable fun DisplayUncitedHashtags( @@ -56,35 +56,34 @@ fun DisplayUncitedHashtags( ) { val unusedHashtags by produceState(initialValue = emptyList()) { - withContext(Dispatchers.Default) { - val state = CachedRichTextParser.parseText(content, event.tags.toImmutableListOfLists()) + val tagsInEvent = event.hashtags() + if (tagsInEvent.isNotEmpty()) { + launch(Dispatchers.Default) { + val state = CachedRichTextParser.parseText(content, event.tags.toImmutableListOfLists()) - val tagsInEvent = event.hashtags() - - if (tagsInEvent.isEmpty()) return@withContext - - val tagsInContent = - state - .paragraphs - .map { - it.words.mapNotNull { - if (it is HashTagSegment) { - it.hashtag - } else { - null + val tagsInContent = + state + .paragraphs + .map { + it.words.mapNotNull { + if (it is HashTagSegment) { + it.hashtag + } else { + null + } } + }.flatten() + + val unusedHashtags = + tagsInEvent.filterNot { eventTag -> + tagsInContent.any { contentTag -> + eventTag.equals(contentTag, true) } - }.flatten() - - val unusedHashtags = - tagsInEvent.filterNot { eventTag -> - tagsInContent.any { contentTag -> - eventTag.equals(contentTag, true) } - } - if (unusedHashtags.isNotEmpty()) { - value = unusedHashtags + if (unusedHashtags.isNotEmpty()) { + value = unusedHashtags + } } } } From 7bf5c03637af759c795a7634b59abd77b92e319d Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 12:36:22 -0400 Subject: [PATCH 30/45] removing the state needs for rendering text. --- .../amethyst/ui/note/types/Text.kt | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt index e98dcec4c5..afd11a0d99 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt @@ -100,31 +100,26 @@ fun RenderTextEvent( note, accountViewModel, ) { body -> - val eventContent by + val eventContent = remember(note.event) { - derivedStateOf { - val subject = (note.event as? TextNoteEvent)?.subject()?.ifEmpty { null } - val newBody = - if (editState.value is GenericLoadable.Loaded) { - val state = - (editState.value as? GenericLoadable.Loaded)?.loaded?.modificationToShow - state?.value?.event?.content() ?: body - } else { - body - } - - if (!subject.isNullOrBlank() && !newBody.split("\n")[0].contains(subject)) { - "### $subject\n$newBody" + val subject = (note.event as? TextNoteEvent)?.subject()?.ifEmpty { null } + val newBody = + if (editState.value is GenericLoadable.Loaded) { + val state = + (editState.value as? GenericLoadable.Loaded)?.loaded?.modificationToShow + state?.value?.event?.content() ?: body } else { - newBody + body } + + if (!subject.isNullOrBlank() && !newBody.split("\n")[0].contains(subject)) { + "### $subject\n$newBody" + } else { + newBody } } - val isAuthorTheLoggedUser = - remember(note.event) { accountViewModel.isLoggedUser(note.author) } - - if (makeItShort && isAuthorTheLoggedUser) { + if (makeItShort && accountViewModel.isLoggedUser(note.author)) { Text( text = eventContent, color = MaterialTheme.colorScheme.placeholderText, From 2cb1e7017025600af59c38bcd27361dba0837dd0 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 19 Jun 2024 16:38:15 +0000 Subject: [PATCH 31/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-cs/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-sv-rSE/strings.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 0f16d07bfe..ffc1055b66 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -449,6 +449,7 @@ Nikdy Hotovo Zjednodušené + Výkonost Systém Světlý Tmavý diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 90a71c1625..7a28822936 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -454,6 +454,7 @@ anz der Bedingungen ist erforderlich Nie Fertig Vereinfacht + Leistung System Hell Dunkel diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index df1720bc08..d14bf16161 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -449,6 +449,7 @@ Nunca Concluído Simplificado + Desempenho Sistema Claro Escuro diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index a9647edcfe..bd0dcf9c9d 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -448,6 +448,7 @@ Aldrig Slutförd Förenklad + Prestanda System Ljus Mörk From f115111c49df6a0441fb3b3454ac890a57e7cc1c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 15:12:07 -0400 Subject: [PATCH 32/45] Centralizes stringResource calls to cache them. --- .../components/SelectNotificationProvider.kt | 26 ++-- .../amethyst/service/CashuProcessor.kt | 60 ++++++--- .../amethyst/service/ZapPaymentHandler.kt | 67 ++++++---- .../service/lnurl/LightningAddressResolver.kt | 58 ++++---- .../EventNotificationConsumer.kt | 30 +++-- .../notifications/NotificationUtils.kt | 53 ++++---- .../amethyst/service/ots/OkHttpCalendar.kt | 11 +- .../vitorpamplona/amethyst/ui/MainActivity.kt | 10 +- .../amethyst/ui/StringResourceCache.kt | 79 +++++++++++ .../amethyst/ui/actions/EditPostView.kt | 24 ++-- .../amethyst/ui/actions/InformationDialog.kt | 4 +- .../ui/actions/JoinUserOrChannelView.kt | 10 +- .../amethyst/ui/actions/NewChannelView.kt | 15 ++- .../amethyst/ui/actions/NewMediaModel.kt | 34 +++-- .../amethyst/ui/actions/NewMediaView.kt | 21 +-- .../amethyst/ui/actions/NewPollClosing.kt | 6 +- .../ui/actions/NewPollConsensusThreshold.kt | 6 +- .../amethyst/ui/actions/NewPollOption.kt | 8 +- .../ui/actions/NewPollPrimaryDescription.kt | 6 +- .../ui/actions/NewPollRecipientsField.kt | 6 +- .../ui/actions/NewPollVoteValueRange.kt | 12 +- .../amethyst/ui/actions/NewPostView.kt | 126 +++++++++--------- .../ui/actions/NewUserMetadataView.kt | 36 ++--- .../ui/actions/NotifyRequestDialog.kt | 4 +- .../ui/actions/RelaySelectionDialog.kt | 17 ++- .../amethyst/ui/actions/SaveToGallery.kt | 54 ++++---- .../amethyst/ui/actions/UploadFromGallery.kt | 10 +- .../ui/actions/relays/AddDMRelayListDialog.kt | 8 +- .../relays/AddSearchRelayListDialog.kt | 8 +- .../ui/actions/relays/AllRelayListView.kt | 36 ++--- .../relays/BasicRelaySetupInfoDialog.kt | 15 ++- .../ui/actions/relays/DMRelayListView.kt | 1 - .../ui/actions/relays/Kind3RelayListView.kt | 60 +++++---- .../ui/actions/relays/LocalRelayListView.kt | 1 - .../ui/actions/relays/Nip65RelayListView.kt | 1 - .../relays/PrivateOutboxRelayListView.kt | 1 - .../actions/relays/RelayInformationDialog.kt | 58 ++++---- .../relays/RelayNameAndRemoveButton.kt | 4 +- .../ui/actions/relays/RelayStatusRow.kt | 22 +-- .../ui/actions/relays/RelayUrlEditField.kt | 6 +- .../ui/actions/relays/SearchRelayListView.kt | 1 - .../amethyst/ui/buttons/ChannelFabColumn.kt | 8 +- .../amethyst/ui/buttons/NewChannelButton.kt | 4 +- .../ui/buttons/NewCommunityNoteButton.kt | 4 +- .../amethyst/ui/buttons/NewImageButton.kt | 7 +- .../amethyst/ui/buttons/NewNoteButton.kt | 4 +- .../amethyst/ui/components/CashuRedeem.kt | 20 +-- .../amethyst/ui/components/ClickableRoute.kt | 19 ++- .../ui/components/ClickableWithdrawal.kt | 3 +- .../ui/components/ExpandableRichTextViewer.kt | 7 +- .../amethyst/ui/components/InvoicePreview.kt | 10 +- .../amethyst/ui/components/InvoiceRequest.kt | 19 ++- .../amethyst/ui/components/RichTextViewer.kt | 1 - .../ui/components/RobohashAsyncImage.kt | 1 - .../ui/components/SelectTextDialog.kt | 4 +- .../ui/components/SensitivityWarning.kt | 12 +- .../amethyst/ui/components/UrlPreviewCard.kt | 6 +- .../amethyst/ui/components/VideoView.kt | 43 +++--- .../ui/components/ZapRaiserRequest.kt | 8 +- .../ui/components/ZoomableContentDialog.kt | 16 ++- .../ui/components/ZoomableContentView.kt | 32 +++-- .../amethyst/ui/layouts/ChatHeaderLayout.kt | 6 +- .../amethyst/ui/layouts/LeftPictureLayout.kt | 4 +- .../ui/navigation/AccountSwitchBottomSheet.kt | 22 +-- .../amethyst/ui/navigation/AppBottomBar.kt | 4 +- .../amethyst/ui/navigation/AppTopBar.kt | 19 ++- .../amethyst/ui/navigation/DrawerContent.kt | 50 ++++--- .../amethyst/ui/navigation/Routes.kt | 1 - .../amethyst/ui/note/BadgeCompose.kt | 17 ++- .../amethyst/ui/note/BlankNote.kt | 12 +- .../amethyst/ui/note/BlockReportChecker.kt | 1 - .../amethyst/ui/note/ChatroomHeaderCompose.kt | 12 +- .../ui/note/ChatroomMessageCompose.kt | 23 ++-- .../vitorpamplona/amethyst/ui/note/Icons.kt | 85 ++++++------ .../amethyst/ui/note/MultiSetCompose.kt | 4 +- .../amethyst/ui/note/NoteCompose.kt | 4 +- .../amethyst/ui/note/NoteQuickActionMenu.kt | 46 +++---- .../amethyst/ui/note/PollNote.kt | 10 +- .../amethyst/ui/note/ReactionsRow.kt | 24 ++-- .../amethyst/ui/note/RelayCompose.kt | 17 +-- .../amethyst/ui/note/RelayListBox.kt | 4 +- .../amethyst/ui/note/RelayListRow.kt | 6 +- .../amethyst/ui/note/ReplyInformation.kt | 6 +- .../amethyst/ui/note/TimeAgoFormatter.kt | 35 ++--- .../ui/note/UpdateReactionTypeDialog.kt | 6 +- .../amethyst/ui/note/UpdateZapAmountDialog.kt | 104 +++++++-------- .../amethyst/ui/note/UserProfilePicture.kt | 9 +- .../amethyst/ui/note/UserReactionsRow.kt | 6 +- .../amethyst/ui/note/ZapCustomDialog.kt | 50 +++---- .../note/elements/AddInboxRelayForDMCard.kt | 10 +- .../elements/AddInboxRelayForSearchCard.kt | 8 +- .../ui/note/elements/AddRemoveButtons.kt | 6 +- .../amethyst/ui/note/elements/BoostedMark.kt | 4 +- .../ui/note/elements/DefaultImageHeader.kt | 6 +- .../ui/note/elements/DisplayEditStatus.kt | 8 +- .../amethyst/ui/note/elements/DisplayOts.kt | 11 +- .../ui/note/elements/DisplayReward.kt | 12 +- .../ui/note/elements/DisplayZapSplits.kt | 2 - .../amethyst/ui/note/elements/DropDownMenu.kt | 46 +++---- .../amethyst/ui/note/elements/ForkInfo.kt | 6 +- .../ui/note/elements/ZapTheDevsCard.kt | 29 ++-- .../amethyst/ui/note/types/AppDefinition.kt | 9 +- .../amethyst/ui/note/types/Badge.kt | 14 +- .../amethyst/ui/note/types/ChannelMessage.kt | 1 - .../amethyst/ui/note/types/Classifieds.kt | 4 +- .../amethyst/ui/note/types/CommunityHeader.kt | 12 +- .../amethyst/ui/note/types/Git.kt | 10 +- .../amethyst/ui/note/types/LiveActivity.kt | 6 +- .../ui/note/types/LiveActivityChatMessage.kt | 1 - .../amethyst/ui/note/types/LongForm.kt | 4 +- .../amethyst/ui/note/types/PrivateMessage.kt | 4 +- .../ui/note/types/RenderPostApproval.kt | 4 +- .../amethyst/ui/note/types/Report.kt | 26 ++-- .../ui/note/types/TextModification.kt | 11 +- .../amethyst/ui/note/types/Video.kt | 4 +- .../amethyst/ui/note/types/Wiki.kt | 4 +- .../amethyst/ui/qrcode/QrCodeScanner.kt | 4 +- .../amethyst/ui/qrcode/ShowQRDialog.kt | 7 +- .../amethyst/ui/screen/AccountScreen.kt | 16 ++- .../amethyst/ui/screen/FeedView.kt | 12 +- .../amethyst/ui/screen/StringFeedView.kt | 6 +- .../amethyst/ui/screen/ThreadFeedView.kt | 16 +-- .../ui/screen/loggedIn/AccountBackupDialog.kt | 81 ++++++----- .../ui/screen/loggedIn/AccountViewModel.kt | 7 +- .../ui/screen/loggedIn/BookmarkListScreen.kt | 6 +- .../ui/screen/loggedIn/ChannelScreen.kt | 36 ++--- .../ui/screen/loggedIn/ChatroomListScreen.kt | 20 +-- .../ui/screen/loggedIn/ChatroomScreen.kt | 50 ++----- .../ui/screen/loggedIn/ConnectOrbotDialog.kt | 10 +- .../ui/screen/loggedIn/DiscoverScreen.kt | 4 +- .../ui/screen/loggedIn/DraftListScreen.kt | 1 - .../ui/screen/loggedIn/GeoHashScreen.kt | 7 +- .../ui/screen/loggedIn/HiddenUsersScreen.kt | 20 +-- .../amethyst/ui/screen/loggedIn/HomeScreen.kt | 11 +- .../ui/screen/loggedIn/LoadRedirectScreen.kt | 4 +- .../amethyst/ui/screen/loggedIn/MainScreen.kt | 14 +- .../loggedIn/NIP90ContentDiscoveryScreen.kt | 21 +-- .../ui/screen/loggedIn/ProfileScreen.kt | 75 +++++------ .../ui/screen/loggedIn/ReportNoteDialog.kt | 34 ++--- .../ui/screen/loggedIn/SearchScreen.kt | 4 +- .../ui/screen/loggedIn/SettingsScreen.kt | 32 +++-- .../ui/screen/loggedIn/VideoScreen.kt | 4 +- .../ui/screen/loggedOff/LoginScreen.kt | 115 ++++++++-------- .../ui/screen/loggedOff/SignUpScreen.kt | 30 ++--- .../components/TranslatableRichTextViewer.kt | 16 +-- 145 files changed, 1443 insertions(+), 1312 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt index b0712305af..41ab2ef745 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt @@ -43,7 +43,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted @@ -79,7 +78,7 @@ fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesView LoadDistributors { currentDistributor, list, readableListWithExplainer -> if (readableListWithExplainer.size > 1) { SpinnerSelectionDialog( - title = stringResource(id = R.string.select_push_server), + title = stringRes(id = R.string.select_push_server), options = readableListWithExplainer, onSelect = { index -> if (list[index] == "None") { @@ -101,9 +100,9 @@ fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesView } else { AlertDialog( onDismissRequest = { distributorPresent = true }, - title = { Text(stringResource(R.string.push_server_install_app)) }, + title = { Text(stringRes(R.string.push_server_install_app)) }, text = { - val content = stringResource(R.string.push_server_install_app_description) + val content = stringRes(R.string.push_server_install_app_description) val astNode = remember { @@ -128,7 +127,7 @@ fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesView sharedPreferencesViewModel.dontShowPushNotificationSelector() }, ) { - Text(stringResource(R.string.quick_action_dont_show_again_button)) + Text(stringRes(R.string.quick_action_dont_show_again_button)) } Button( onClick = { distributorPresent = true }, @@ -142,7 +141,7 @@ fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesView contentDescription = null, ) Spacer(Modifier.width(8.dp)) - Text(stringResource(R.string.error_dialog_button_ok)) + Text(stringRes(R.string.error_dialog_button_ok)) } } } @@ -168,20 +167,19 @@ fun LoadDistributors(onInner: @Composable (String, ImmutableList, Immuta } val readableListWithExplainer = - PushDistributorHandler.formattedDistributorNames() + PushDistributorHandler + .formattedDistributorNames() .mapIndexed { index, name -> TitleExplainer( name, - stringResource(id = R.string.push_server_uses_app_explainer, list[index]), + stringRes(id = R.string.push_server_uses_app_explainer, list[index]), ) - } - .plus( + }.plus( TitleExplainer( - stringResource(id = R.string.push_server_none), - stringResource(id = R.string.push_server_none_explainer), + stringRes(id = R.string.push_server_none), + stringRes(id = R.string.push_server_none_explainer), ), - ) - .toImmutableList() + ).toImmutableList() onInner( currentDistributor, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt index ce3b280c6d..50203703b1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/CashuProcessor.kt @@ -28,6 +28,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver import com.vitorpamplona.amethyst.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.events.Event import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request @@ -46,9 +47,7 @@ data class CashuToken( object CachedCashuProcessor { val cashuCache = LruCache>(20) - fun cached(token: String): GenericLoadable { - return cashuCache[token] ?: GenericLoadable.Loading() - } + fun cached(token: String): GenericLoadable = cashuCache[token] ?: GenericLoadable.Loading() fun parse(token: String): GenericLoadable { if (cashuCache[token] !is GenericLoadable.Loaded) { @@ -150,7 +149,12 @@ class CashuProcessor { val mediaType = "application/json; charset=utf-8".toMediaType() val requestBody = jsonObject.toString().toRequestBody(mediaType) - val request = Request.Builder().url(url).post(requestBody).build() + val request = + Request + .Builder() + .url(url) + .post(requestBody) + .build() client.newCall(request).execute().use { val body = it.body.string() @@ -163,13 +167,19 @@ class CashuProcessor { feeCost, ) } else { - val msg = tree?.get("detail")?.asText()?.split('.')?.getOrNull(0)?.ifBlank { null } + val msg = + tree + ?.get("detail") + ?.asText() + ?.split('.') + ?.getOrNull(0) + ?.ifBlank { null } onError( - context.getString(R.string.cashu_failed_redemption), + stringRes(context, R.string.cashu_failed_redemption), if (msg != null) { - context.getString(R.string.cashu_failed_redemption_explainer_error_msg, msg) + stringRes(context, R.string.cashu_failed_redemption_explainer_error_msg, msg) } else { - context.getString(R.string.cashu_failed_redemption_explainer_error_msg) + stringRes(context, R.string.cashu_failed_redemption_explainer_error_msg) }, ) } @@ -177,8 +187,8 @@ class CashuProcessor { } catch (e: Exception) { if (e is CancellationException) throw e onError( - context.getString(R.string.cashu_successful_redemption), - context.getString(R.string.cashu_failed_redemption_explainer_error_msg, e.message), + stringRes(context, R.string.cashu_successful_redemption), + stringRes(context, R.string.cashu_failed_redemption_explainer_error_msg, e.message), ) } } @@ -203,7 +213,12 @@ class CashuProcessor { val mediaType = "application/json; charset=utf-8".toMediaType() val requestBody = jsonObject.toString().toRequestBody(mediaType) - val request = Request.Builder().url(url).post(requestBody).build() + val request = + Request + .Builder() + .url(url) + .post(requestBody) + .build() client.newCall(request).execute().use { val body = it.body.string() @@ -213,21 +228,28 @@ class CashuProcessor { if (successful) { onSuccess( - context.getString(R.string.cashu_successful_redemption), - context.getString( + stringRes(context, R.string.cashu_successful_redemption), + stringRes( + context, R.string.cashu_successful_redemption_explainer, token.totalAmount.toString(), fees.toString(), ), ) } else { - val msg = tree?.get("detail")?.asText()?.split('.')?.getOrNull(0)?.ifBlank { null } + val msg = + tree + ?.get("detail") + ?.asText() + ?.split('.') + ?.getOrNull(0) + ?.ifBlank { null } onError( - context.getString(R.string.cashu_failed_redemption), + stringRes(context, R.string.cashu_failed_redemption), if (msg != null) { - context.getString(R.string.cashu_failed_redemption_explainer_error_msg, msg) + stringRes(context, R.string.cashu_failed_redemption_explainer_error_msg, msg) } else { - context.getString(R.string.cashu_failed_redemption_explainer_error_msg) + stringRes(context, R.string.cashu_failed_redemption_explainer_error_msg) }, ) } @@ -235,8 +257,8 @@ class CashuProcessor { } catch (e: Exception) { if (e is CancellationException) throw e onError( - context.getString(R.string.cashu_successful_redemption), - context.getString(R.string.cashu_failed_redemption_explainer_error_msg, e.message), + stringRes(context, R.string.cashu_successful_redemption), + stringRes(context, R.string.cashu_failed_redemption_explainer_error_msg, e.message), ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt index 4839064959..8489374d33 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt @@ -29,6 +29,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver import com.vitorpamplona.amethyst.ui.screen.loggedIn.collectSuccessfulSigningOperations +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.LiveActivitiesEvent @@ -41,7 +42,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlin.math.round -class ZapPaymentHandler(val account: Account) { +class ZapPaymentHandler( + val account: Account, +) { @Immutable data class Payable( val info: ZapSplitSetup, @@ -79,8 +82,9 @@ class ZapPaymentHandler(val account: Account) { if (lud16.isNullOrBlank()) { onError( - context.getString(R.string.missing_lud16), - context.getString( + stringRes(context, R.string.missing_lud16), + stringRes( + context, R.string.user_does_not_have_a_lightning_address_setup_to_receive_sats, ), ) @@ -94,8 +98,9 @@ class ZapPaymentHandler(val account: Account) { if (lud16.isNullOrBlank()) { onError( - context.getString(R.string.missing_lud16), - context.getString( + stringRes(context, R.string.missing_lud16), + stringRes( + context, R.string.user_does_not_have_a_lightning_address_setup_to_receive_sats, ), ) @@ -132,14 +137,15 @@ class ZapPaymentHandler(val account: Account) { } } else { onPayViaIntent( - it.map { - Payable( - info = it.key.first, - user = it.key.second.user, - amountMilliSats = it.value.zapValue, - invoice = it.value.invoice, - ) - }.toImmutableList(), + it + .map { + Payable( + info = it.key.first, + user = it.key.second.user, + amountMilliSats = it.value.zapValue, + invoice = it.value.invoice, + ) + }.toImmutableList(), ) onProgress(0f) @@ -172,13 +178,16 @@ class ZapPaymentHandler(val account: Account) { onAllDone: suspend (MutableMap) -> Unit, ) { val authorRelayList = - note.author?.pubkeyHex?.let { - ( - LocalCache.getAddressableNoteIfExists( - AdvertisedRelayListEvent.createAddressTag(it), - )?.event as? AdvertisedRelayListEvent? - )?.readRelays() - }?.toSet() + note.author + ?.pubkeyHex + ?.let { + ( + LocalCache + .getAddressableNoteIfExists( + AdvertisedRelayListEvent.createAddressTag(it), + )?.event as? AdvertisedRelayListEvent? + )?.readRelays() + }?.toSet() collectSuccessfulSigningOperations( operationsInput = zapsToSend, @@ -194,9 +203,10 @@ class ZapPaymentHandler(val account: Account) { val userRelayList = ( ( - LocalCache.getAddressableNoteIfExists( - AdvertisedRelayListEvent.createAddressTag(next.lnAddressOrPubKeyHex), - )?.event as? AdvertisedRelayListEvent? + LocalCache + .getAddressableNoteIfExists( + AdvertisedRelayListEvent.createAddressTag(next.lnAddressOrPubKeyHex), + )?.event as? AdvertisedRelayListEvent? )?.readRelays()?.toSet() ?: emptySet() ) + (authorRelayList ?: emptySet()) @@ -272,8 +282,9 @@ class ZapPaymentHandler(val account: Account) { progressAllPayments += 0.5f / invoices.size onProgress(progressAllPayments) onError( - context.getString(R.string.error_dialog_pay_invoice_error), - context.getString( + stringRes(context, R.string.error_dialog_pay_invoice_error), + stringRes( + context, R.string.wallet_connect_pay_invoice_error_error, response.error?.message ?: response.error?.code?.toString() ?: "Error parsing error message", @@ -339,10 +350,12 @@ class ZapPaymentHandler(val account: Account) { } else { if (showErrorIfNoLnAddress) { onError( - context.getString( + stringRes( + context, R.string.missing_lud16, ), - context.getString( + stringRes( + context, R.string.user_x_does_not_have_a_lightning_address_setup_to_receive_sats, user?.toBestDisplayName() ?: splitSetup.lnAddressOrPubKeyHex, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index feaaa76b19..85b19ebce8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -26,6 +26,7 @@ import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.HttpClientManager import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.encoders.LnInvoiceUtil import com.vitorpamplona.quartz.encoders.Lud06 import okhttp3.Request @@ -34,7 +35,7 @@ import java.math.RoundingMode import java.net.URLEncoder import kotlin.coroutines.cancellation.CancellationException -class LightningAddressResolver() { +class LightningAddressResolver { val client = HttpClientManager.getHttpClient() fun assembleUrl(lnaddress: String): String? { @@ -63,8 +64,9 @@ class LightningAddressResolver() { if (url == null) { onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string.could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup, lnaddress, ), @@ -74,7 +76,8 @@ class LightningAddressResolver() { try { val request: Request = - Request.Builder() + Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url(url) .build() @@ -84,8 +87,9 @@ class LightningAddressResolver() { onSuccess(it.body.string()) } else { onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string .the_receiver_s_lightning_service_at_is_not_available_it_was_calculated_from_the_lightning_address_error_check_if_the_server_is_up_and_if_the_lightning_address_is_correct, url, @@ -99,8 +103,9 @@ class LightningAddressResolver() { if (e is CancellationException) throw e e.printStackTrace() onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string .could_not_resolve_check_if_you_are_connected_if_the_server_is_up_and_if_the_lightning_address_is_correct_exception, url, @@ -133,7 +138,8 @@ class LightningAddressResolver() { } val request: Request = - Request.Builder() + Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .url(url) .build() @@ -143,8 +149,8 @@ class LightningAddressResolver() { onSuccess(it.body.string()) } else { onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString(R.string.could_not_fetch_invoice_from, lnCallback), + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes(context, R.string.could_not_fetch_invoice_from, lnCallback), ) } } @@ -173,8 +179,9 @@ class LightningAddressResolver() { } catch (t: Throwable) { if (t is CancellationException) throw t onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string.error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup_with_user, lnaddress, ), @@ -186,8 +193,9 @@ class LightningAddressResolver() { if (callback == null) { onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string.callback_url_not_found_in_the_user_s_lightning_address_server_configuration_with_user, lnaddress, ), @@ -211,8 +219,9 @@ class LightningAddressResolver() { } catch (t: Throwable) { if (t is CancellationException) throw t onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string .error_parsing_json_from_lightning_address_s_invoice_fetch_check_the_user_s_lightning_setup_with_user, lnaddress, @@ -236,8 +245,9 @@ class LightningAddressResolver() { } else { onProgress(0.0f) onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string.incorrect_invoice_amount_sats_from_it_should_have_been, invoiceAmount.toLong().toString(), lnaddress, @@ -253,8 +263,9 @@ class LightningAddressResolver() { ?.let { reason -> onProgress(0.0f) onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string .unable_to_create_a_lightning_invoice_before_sending_the_zap_the_receiver_s_lightning_wallet_sent_the_following_error_with_user, lnaddress, @@ -265,8 +276,9 @@ class LightningAddressResolver() { ?: run { onProgress(0.0f) onError( - context.getString(R.string.error_unable_to_fetch_invoice), - context.getString( + stringRes(context, R.string.error_unable_to_fetch_invoice), + stringRes( + context, R.string .unable_to_create_a_lightning_invoice_before_sending_the_zap_element_pr_not_found_in_the_resulting_json_with_user, lnaddress, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index ee0bfd54de..4ff65b4742 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -31,6 +31,7 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification import com.vitorpamplona.amethyst.ui.note.showAmount +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.events.ChatMessageEvent import com.vitorpamplona.quartz.events.ChatroomKey @@ -44,7 +45,9 @@ import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.persistentSetOf import java.math.BigDecimal -class EventNotificationConsumer(private val applicationContext: Context) { +class EventNotificationConsumer( + private val applicationContext: Context, +) { suspend fun consume(event: GiftWrapEvent) { Log.d("EventNotificationConsumer", "New Notification Arrived") if (!LocalCache.justVerify(event)) return @@ -124,7 +127,8 @@ class EventNotificationConsumer(private val applicationContext: Context) { acc: Account, ) { if ( - event.createdAt > TimeUtils.fifteenMinutesAgo() && // old event being re-broadcasted + event.createdAt > TimeUtils.fifteenMinutesAgo() && + // old event being re-broadcasted event.pubKey != acc.userProfile().pubkeyHex ) { // from the user @@ -137,7 +141,8 @@ class EventNotificationConsumer(private val applicationContext: Context) { ( acc.userProfile().privateChatrooms[chatRoom]?.senderIntersects(followingKeySet) == true || acc.userProfile().hasSentMessagesTo(chatRoom) - ) && !acc.isAllHidden(chatRoom.users) + ) && + !acc.isAllHidden(chatRoom.users) if (isKnownRoom) { val content = chatNote.event?.content() ?: "" @@ -178,9 +183,9 @@ class EventNotificationConsumer(private val applicationContext: Context) { ( acc.userProfile().privateChatrooms[it]?.senderIntersects(followingKeySet) == true || acc.userProfile().hasSentMessagesTo(it) - ) && !acc.isAllHidden(it.users) - } - .toSet() + ) && + !acc.isAllHidden(it.users) + }.toSet() note.author?.let { if (ChatroomKey(persistentSetOf(it.pubkeyHex)) in knownChatrooms) { @@ -223,17 +228,19 @@ class EventNotificationConsumer(private val applicationContext: Context) { val user = senderInfo.first.toBestDisplayName() var title = - applicationContext.getString(R.string.app_notification_zaps_channel_message, amount) + stringRes(applicationContext, R.string.app_notification_zaps_channel_message, amount) senderInfo.second?.ifBlank { null }?.let { title += " ($it)" } var content = - applicationContext.getString( + stringRes( + applicationContext, R.string.app_notification_zaps_channel_message_from, user, ) zappedContent?.let { content += " " + - applicationContext.getString( + stringRes( + applicationContext, R.string.app_notification_zaps_channel_message_for, zappedContent, ) @@ -255,8 +262,7 @@ class EventNotificationConsumer(private val applicationContext: Context) { } } - fun notificationManager(): NotificationManager { - return ContextCompat.getSystemService(applicationContext, NotificationManager::class.java) + fun notificationManager(): NotificationManager = + ContextCompat.getSystemService(applicationContext, NotificationManager::class.java) as NotificationManager - } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt index 834c040529..4bc761c5de 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationUtils.kt @@ -34,6 +34,7 @@ import coil.executeBlocking import coil.request.ImageRequest import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.MainActivity +import com.vitorpamplona.amethyst.ui.stringRes object NotificationUtils { private var dmChannel: NotificationChannel? = null @@ -46,14 +47,13 @@ object NotificationUtils { dmChannel = NotificationChannel( - applicationContext.getString(R.string.app_notification_dms_channel_id), - applicationContext.getString(R.string.app_notification_dms_channel_name), + stringRes(applicationContext, R.string.app_notification_dms_channel_id), + stringRes(applicationContext, R.string.app_notification_dms_channel_name), NotificationManager.IMPORTANCE_DEFAULT, - ) - .apply { - description = - applicationContext.getString(R.string.app_notification_dms_channel_description) - } + ).apply { + description = + stringRes(applicationContext, R.string.app_notification_dms_channel_description) + } // Register the channel with the system val notificationManager: NotificationManager = @@ -69,14 +69,13 @@ object NotificationUtils { zapChannel = NotificationChannel( - applicationContext.getString(R.string.app_notification_zaps_channel_id), - applicationContext.getString(R.string.app_notification_zaps_channel_name), + stringRes(applicationContext, R.string.app_notification_zaps_channel_id), + stringRes(applicationContext, R.string.app_notification_zaps_channel_name), NotificationManager.IMPORTANCE_DEFAULT, - ) - .apply { - description = - applicationContext.getString(R.string.app_notification_zaps_channel_description) - } + ).apply { + description = + stringRes(applicationContext, R.string.app_notification_zaps_channel_description) + } // Register the channel with the system val notificationManager: NotificationManager = @@ -96,7 +95,7 @@ object NotificationUtils { applicationContext: Context, ) { val zapChannel = getOrCreateZapChannel(applicationContext) - val channelId = applicationContext.getString(R.string.app_notification_zaps_channel_id) + val channelId = stringRes(applicationContext, R.string.app_notification_zaps_channel_id) sendNotification( id, @@ -119,7 +118,7 @@ object NotificationUtils { applicationContext: Context, ) { val dmChannel = getOrCreateDMChannel(applicationContext) - val channelId = applicationContext.getString(R.string.app_notification_dms_channel_id) + val channelId = stringRes(applicationContext, R.string.app_notification_dms_channel_id) sendNotification( id, @@ -205,13 +204,13 @@ object NotificationUtils { // Build the notification val builderPublic = - NotificationCompat.Builder( - applicationContext, - channelId, - ) - .setSmallIcon(R.drawable.amethyst) + NotificationCompat + .Builder( + applicationContext, + channelId, + ).setSmallIcon(R.drawable.amethyst) .setContentTitle(messageTitle) - .setContentText(applicationContext.getString(R.string.app_notification_private_message)) + .setContentText(stringRes(applicationContext, R.string.app_notification_private_message)) .setLargeIcon(picture?.bitmap) // .setGroup(messageTitle) // .setGroup(notificationGroupKey) //-> Might need a Group summary as well before we @@ -222,11 +221,11 @@ object NotificationUtils { // Build the notification val builder = - NotificationCompat.Builder( - applicationContext, - channelId, - ) - .setSmallIcon(R.drawable.amethyst) + NotificationCompat + .Builder( + applicationContext, + channelId, + ).setSmallIcon(R.drawable.amethyst) .setContentTitle(messageTitle) .setContentText(messageBody) .setLargeIcon(picture?.bitmap) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt index f14d5048a5..91db7a2b49 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/ots/OkHttpCalendar.kt @@ -30,14 +30,15 @@ import com.vitorpamplona.quartz.ots.exceptions.CommitmentNotFoundException import com.vitorpamplona.quartz.ots.exceptions.DeserializationException import com.vitorpamplona.quartz.ots.exceptions.ExceededSizeException import com.vitorpamplona.quartz.ots.exceptions.UrlException -import com.vitorpamplona.quartz.ots.http.Request import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody /** * Class representing remote calendar server interface. */ -class OkHttpCalendar(val url: String) : ICalendar { +class OkHttpCalendar( + val url: String, +) : ICalendar { /** * Submitting a digest to remote calendar. Returns a com.eternitywall.ots.Timestamp committing to that digest. * @@ -57,7 +58,8 @@ class OkHttpCalendar(val url: String) : ICalendar { val requestBody = digest.toRequestBody(mediaType) val request = - okhttp3.Request.Builder() + okhttp3.Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .header("Accept", "application/vnd.opentimestamps.v1") .header("Content-Type", "application/x-www-form-urlencoded") @@ -104,7 +106,8 @@ class OkHttpCalendar(val url: String) : ICalendar { val url = url + "/timestamp/" + Hex.encode(commitment) val request = - okhttp3.Request.Builder() + okhttp3.Request + .Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") .header("Accept", "application/vnd.opentimestamps.v1") .header("Content-Type", "application/x-www-form-urlencoded") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 4f054fa6a0..ba1ead032e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -90,6 +90,11 @@ class MainActivity : AppCompatActivity() { override fun onResume() { super.onResume() + val locales = this.applicationContext.resources.configuration.locales + if (!locales.isEmpty) { + checkLanguage(locales.get(0).language) + } + Log.d("Lifetime Event", "MainActivity.onResume") // starts muted every time @@ -263,8 +268,8 @@ class GetMediaActivityResultContract : ActivityResultContracts.GetContent() { } } -fun uriToRoute(uri: String?): String? { - return if (uri.equals("nostr:Notifications", true)) { +fun uriToRoute(uri: String?): String? = + if (uri.equals("nostr:Notifications", true)) { Route.Notification.route.replace("{scrollToTop}", "true") } else { if (uri?.startsWith("nostr:Hashtag?id=") == true) { @@ -317,4 +322,3 @@ fun uriToRoute(uri: String?): String? { null } } -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt new file mode 100644 index 0000000000..2caf1d52b2 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/StringResourceCache.kt @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui + +import android.content.Context +import android.util.LruCache +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.res.stringResource + +/** + * Cache for stringResource because it seems to be > 1ms function in some phones + */ +private val resourceCache = LruCache(300) +private var resourceCacheLanguage: String? = null + +fun checkLanguage(currentLanguage: String) { + if (resourceCacheLanguage == null) { + resourceCacheLanguage = currentLanguage + } else { + if (resourceCacheLanguage != currentLanguage) { + resourceCacheLanguage = currentLanguage + resourceCache.evictAll() + } + } +} + +@Composable +fun stringRes(id: Int): String = resourceCache.get(id) ?: stringResource(id).also { resourceCache.put(id, it) } + +@Composable +fun stringRes( + id: Int, + vararg args: Any, +): String = + String + .format( + LocalConfiguration.current.locales.get(0), + resourceCache.get(id) ?: stringResource(id), + *args, + ).also { resourceCache.put(id, it) } + +fun stringRes( + ctx: Context, + id: Int, +): String = resourceCache.get(id) ?: ctx.getString(id).also { resourceCache.put(id, it) } + +fun stringRes( + ctx: Context, + id: Int, + vararg args: Any?, +): String { + val res = ctx.resources + + return String + .format( + res.configuration.locales.get(0), + resourceCache.get(id) ?: res.getString(id), + *args, + ).also { resourceCache.put(id, it) } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt index 82dacec419..62ef237caa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt @@ -78,7 +78,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextDirection @@ -98,6 +97,7 @@ import com.vitorpamplona.amethyst.ui.components.VideoView import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.QuoteBorder @@ -189,7 +189,7 @@ fun EditPostView( ) { Icon( painter = painterResource(R.drawable.relays), - contentDescription = stringResource(id = R.string.relay_list_selector), + contentDescription = stringRes(id = R.string.relay_list_selector), modifier = Modifier.height(25.dp), tint = MaterialTheme.colorScheme.onBackground, ) @@ -236,8 +236,7 @@ fun EditPostView( top = pad.calculateTopPadding(), end = Size10dp, bottom = pad.calculateBottomPadding(), - ) - .fillMaxSize(), + ).fillMaxSize(), ) { Column( modifier = @@ -365,8 +364,8 @@ fun EditPostView( lud16, user.pubkeyHex, accountViewModel.account, - stringResource(id = R.string.lightning_invoice), - stringResource(id = R.string.lightning_create_and_add_invoice), + stringRes(id = R.string.lightning_invoice), + stringRes(id = R.string.lightning_create_and_add_invoice), onSuccess = { postViewModel.message = TextFieldValue(postViewModel.message.text + "\n\n" + it) @@ -386,7 +385,7 @@ fun EditPostView( ) { Column { Text( - text = stringResource(R.string.message_to_author), + text = stringRes(R.string.message_to_author), fontSize = 18.sp, fontWeight = FontWeight.W500, ) @@ -399,7 +398,7 @@ fun EditPostView( modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.message_to_author_placeholder), + text = stringRes(R.string.message_to_author_placeholder), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -514,8 +513,7 @@ private fun MessageField(postViewModel: EditPostViewModel) { width = 1.dp, color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(8.dp), - ) - .focusRequester(focusRequester) + ).focusRequester(focusRequester) .onFocusChanged { if (it.isFocused) { keyboardController?.show() @@ -523,7 +521,7 @@ private fun MessageField(postViewModel: EditPostViewModel) { }, placeholder = { Text( - text = stringResource(R.string.what_s_on_your_mind), + text = stringRes(R.string.what_s_on_your_mind), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -548,14 +546,14 @@ private fun AddLnInvoiceButton( if (!isLnInvoiceActive) { Icon( imageVector = Icons.Default.CurrencyBitcoin, - contentDescription = stringResource(id = R.string.add_bitcoin_invoice), + contentDescription = stringRes(id = R.string.add_bitcoin_invoice), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onBackground, ) } else { Icon( imageVector = Icons.Default.CurrencyBitcoin, - contentDescription = stringResource(id = R.string.cancel_bitcoin_invoice), + contentDescription = stringRes(id = R.string.cancel_bitcoin_invoice), modifier = Modifier.size(20.dp), tint = BitcoinOrange, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt index f2cc82d6ce..b443c53e63 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt @@ -34,8 +34,8 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment -import androidx.compose.ui.res.stringResource import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size16dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer @@ -64,7 +64,7 @@ fun InformationDialog( contentDescription = null, ) Spacer(StdHorzSpacer) - Text(stringResource(R.string.error_dialog_button_ok)) + Text(stringRes(R.string.error_dialog_button_ok)) } } }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt index 996f09c6e5..57b596c40f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/JoinUserOrChannelView.kt @@ -61,7 +61,6 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -83,6 +82,7 @@ import com.vitorpamplona.amethyst.ui.note.SearchIcon import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchBarViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -161,7 +161,7 @@ fun JoinUserOrChannelView( ) Text( - text = stringResource(R.string.channel_list_join_conversation), + text = stringRes(R.string.channel_list_join_conversation), fontWeight = FontWeight.Bold, ) @@ -278,7 +278,7 @@ private fun SearchEditTextForJoin( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.channel_list_user_or_group_id)) }, + label = { Text(text = stringRes(R.string.channel_list_user_or_group_id)) }, value = searchBarViewModel.searchValue, onValueChange = { searchBarViewModel.updateSearchValue(it) @@ -297,7 +297,7 @@ private fun SearchEditTextForJoin( }, placeholder = { Text( - text = stringResource(R.string.channel_list_user_or_group_id_demo), + text = stringRes(R.string.channel_list_user_or_group_id_demo), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -311,7 +311,7 @@ private fun SearchEditTextForJoin( ) { Icon( imageVector = Icons.Default.Clear, - contentDescription = stringResource(R.string.clear), + contentDescription = stringRes(R.string.clear), ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt index 15f5cf8f42..e9db99763c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewChannelView.kt @@ -38,7 +38,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.dp @@ -48,6 +47,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText @Composable @@ -87,20 +87,21 @@ fun NewChannelView( postViewModel.create() onClose() }, - postViewModel.channelName.value.text.isNotBlank(), + postViewModel.channelName.value.text + .isNotBlank(), ) } Spacer(modifier = Modifier.height(15.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.channel_name)) }, + label = { Text(text = stringRes(R.string.channel_name)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.channelName.value, onValueChange = { postViewModel.channelName.value = it }, placeholder = { Text( - text = stringResource(R.string.my_awesome_group), + text = stringRes(R.string.my_awesome_group), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -114,7 +115,7 @@ fun NewChannelView( Spacer(modifier = Modifier.height(15.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.picture_url)) }, + label = { Text(text = stringRes(R.string.picture_url)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.channelPicture.value, onValueChange = { postViewModel.channelPicture.value = it }, @@ -129,13 +130,13 @@ fun NewChannelView( Spacer(modifier = Modifier.height(15.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.description)) }, + label = { Text(text = stringRes(R.string.description)) }, modifier = Modifier.fillMaxWidth().height(100.dp), value = postViewModel.channelDescription.value, onValueChange = { postViewModel.channelDescription.value = it }, placeholder = { Text( - text = stringResource(R.string.about_us), + text = stringRes(R.string.about_us), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt index 16d9a02582..91c0bf1c8d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt @@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.Nip96MediaServers import com.vitorpamplona.amethyst.service.Nip96Uploader import com.vitorpamplona.amethyst.ui.components.MediaCompressor +import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -114,7 +115,7 @@ open class NewMediaModel : ViewModel() { } ?: run { viewModelScope.launch { - onError(context.getString(R.string.could_not_open_the_compressed_file)) + onError(stringRes(context, R.string.could_not_open_the_compressed_file)) isUploadingImage = false uploadingPercentage.value = 0.00f uploadingDescription.value = null @@ -153,7 +154,7 @@ open class NewMediaModel : ViewModel() { isUploadingImage = false uploadingPercentage.value = 0.00f uploadingDescription.value = null - onError(context.getString(R.string.failed_to_upload_media, e.message)) + onError(stringRes(context, R.string.failed_to_upload_media, e.message)) } } } @@ -162,7 +163,7 @@ open class NewMediaModel : ViewModel() { isUploadingImage = false uploadingPercentage.value = 0.00f uploadingDescription.value = null - onError(context.getString(R.string.error_when_compressing_media, it)) + onError(stringRes(context, R.string.error_when_compressing_media, it)) }, ) } @@ -179,9 +180,7 @@ open class NewMediaModel : ViewModel() { selectedServer = ServerOption(defaultServer(), false) } - fun canPost(): Boolean { - return !isUploadingImage && galleryUri != null && selectedServer != null - } + fun canPost(): Boolean = !isUploadingImage && galleryUri != null && selectedServer != null suspend fun createNIP94Record( uploadingResult: Nip96Uploader.PartialEvent, @@ -197,11 +196,20 @@ open class NewMediaModel : ViewModel() { val imageUrl = uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "url" }?.get(1) val remoteMimeType = - uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "m" }?.get(1)?.ifBlank { null } + uploadingResult.tags + ?.firstOrNull { it.size > 1 && it[0] == "m" } + ?.get(1) + ?.ifBlank { null } val originalHash = - uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "ox" }?.get(1)?.ifBlank { null } + uploadingResult.tags + ?.firstOrNull { it.size > 1 && it[0] == "ox" } + ?.get(1) + ?.ifBlank { null } val dim = - uploadingResult.tags?.firstOrNull { it.size > 1 && it[0] == "dim" }?.get(1)?.ifBlank { null } + uploadingResult.tags + ?.firstOrNull { it.size > 1 && it[0] == "dim" } + ?.get(1) + ?.ifBlank { null } val magnet = uploadingResult.tags ?.firstOrNull { it.size > 1 && it[0] == "magnet" } @@ -214,7 +222,7 @@ open class NewMediaModel : ViewModel() { uploadingPercentage.value = 0.00f uploadingDescription.value = null isUploadingImage = false - onError(context.getString(R.string.server_did_not_provide_a_url_after_uploading)) + onError(stringRes(context, R.string.server_did_not_provide_a_url_after_uploading)) return } @@ -254,7 +262,7 @@ open class NewMediaModel : ViewModel() { uploadingPercentage.value = 0.00f uploadingDescription.value = null isUploadingImage = false - onError(context.getString(R.string.could_not_prepare_local_file_to_upload, it)) + onError(stringRes(context, R.string.could_not_prepare_local_file_to_upload, it)) }, ) } else { @@ -263,7 +271,7 @@ open class NewMediaModel : ViewModel() { uploadingPercentage.value = 0.00f uploadingDescription.value = null isUploadingImage = false - onError(context.getString(R.string.could_not_download_from_the_server)) + onError(stringRes(context, R.string.could_not_download_from_the_server)) } } @@ -312,7 +320,7 @@ open class NewMediaModel : ViewModel() { uploadingPercentage.value = 0.00f isUploadingImage = false cancel() - onError(context.getString(R.string.could_not_prepare_local_file_to_upload, it)) + onError(stringRes(context, R.string.could_not_prepare_local_file_to_upload, it)) }, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt index 0f94874f22..28df2df0f1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt @@ -58,7 +58,6 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog @@ -70,6 +69,7 @@ import com.vitorpamplona.amethyst.ui.components.VideoView import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CancellationException @@ -93,7 +93,7 @@ fun NewMediaView( LaunchedEffect(uri) { val mediaType = resolver.getType(uri) ?: "" postViewModel.load(account, uri, mediaType) { - accountViewModel.toast(context.getString(R.string.failed_to_upload_media_no_details), it) + accountViewModel.toast(stringRes(context, R.string.failed_to_upload_media_no_details), it) } } @@ -124,7 +124,8 @@ fun NewMediaView( Column( modifier = - Modifier.padding(start = 10.dp, end = 10.dp, top = 10.dp) + Modifier + .padding(start = 10.dp, end = 10.dp, top = 10.dp) .fillMaxWidth() .fillMaxHeight() .imePadding(), @@ -194,7 +195,7 @@ fun ImageVideoPost( ServerOption( Nip96MediaServers.ServerName( "NIP95", - stringResource(id = R.string.upload_server_relays_nip95), + stringRes(id = R.string.upload_server_relays_nip95), ), true, ), @@ -209,7 +210,8 @@ fun ImageVideoPost( Row( verticalAlignment = Alignment.CenterVertically, modifier = - Modifier.fillMaxWidth() + Modifier + .fillMaxWidth() .padding(bottom = 10.dp) .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)), ) { @@ -219,7 +221,8 @@ fun ImageVideoPost( contentDescription = postViewModel.galleryUri.toString(), contentScale = ContentScale.FillWidth, modifier = - Modifier.padding(top = 4.dp) + Modifier + .padding(top = 4.dp) .fillMaxWidth() .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)), ) @@ -265,7 +268,7 @@ fun ImageVideoPost( modifier = Modifier.fillMaxWidth(), ) { TextSpinner( - label = stringResource(id = R.string.file_server), + label = stringRes(id = R.string.file_server), placeholder = fileServers .firstOrNull { it.server == accountViewModel.account.defaultFileServer } @@ -296,13 +299,13 @@ fun ImageVideoPost( modifier = Modifier.fillMaxWidth().windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)), ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.content_description)) }, + label = { Text(text = stringRes(R.string.content_description)) }, modifier = Modifier.fillMaxWidth().windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)), value = postViewModel.alt, onValueChange = { postViewModel.alt = it }, placeholder = { Text( - text = stringResource(R.string.content_description_example), + text = stringRes(R.string.content_description_example), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt index b17ade6d8d..8c8a61c203 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollClosing.kt @@ -36,12 +36,12 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.coroutines.CancellationException @@ -87,13 +87,13 @@ fun NewPollClosing(pollViewModel: NewPostViewModel) { colors = if (pollViewModel.isValidClosedAt.value) colorValid else colorInValid, label = { Text( - text = stringResource(R.string.poll_closing_time), + text = stringRes(R.string.poll_closing_time), color = MaterialTheme.colorScheme.placeholderText, ) }, placeholder = { Text( - text = stringResource(R.string.poll_closing_time_days), + text = stringRes(R.string.poll_closing_time_days), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt index d181c873dc..277b89d761 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollConsensusThreshold.kt @@ -36,12 +36,12 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.coroutines.CancellationException @@ -87,13 +87,13 @@ fun NewPollConsensusThreshold(pollViewModel: NewPostViewModel) { colors = if (pollViewModel.isValidConsensusThreshold.value) colorValid else colorInValid, label = { Text( - text = stringResource(R.string.poll_consensus_threshold), + text = stringRes(R.string.poll_consensus_threshold), color = MaterialTheme.colorScheme.placeholderText, ) }, placeholder = { Text( - text = stringResource(R.string.poll_consensus_threshold_percent), + text = stringRes(R.string.poll_consensus_threshold_percent), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt index 086035c0a5..a630d31575 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollOption.kt @@ -31,10 +31,10 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText @Composable @@ -51,7 +51,7 @@ fun NewPollOption( ) { Icon( imageVector = Icons.Default.Delete, - contentDescription = stringResource(R.string.clear), + contentDescription = stringRes(R.string.clear), ) } } @@ -64,13 +64,13 @@ fun NewPollOption( }, label = { Text( - text = stringResource(R.string.poll_option_index).format(optionIndex + 1), + text = stringRes(R.string.poll_option_index).format(optionIndex + 1), color = MaterialTheme.colorScheme.placeholderText, ) }, placeholder = { Text( - text = stringResource(R.string.poll_option_description), + text = stringRes(R.string.poll_option_description), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt index 4c355c6b2d..c368dde526 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollPrimaryDescription.kt @@ -37,13 +37,13 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText @OptIn(ExperimentalComposeUiApi::class) @@ -74,7 +74,7 @@ fun NewPollPrimaryDescription(pollViewModel: NewPostViewModel) { onValueChange = { pollViewModel.updateMessage(it) }, label = { Text( - text = stringResource(R.string.poll_primary_description), + text = stringRes(R.string.poll_primary_description), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -90,7 +90,7 @@ fun NewPollPrimaryDescription(pollViewModel: NewPostViewModel) { }, placeholder = { Text( - text = stringResource(R.string.poll_primary_description), + text = stringRes(R.string.poll_primary_description), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt index 10cb12bc36..e575252319 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollRecipientsField.kt @@ -26,10 +26,10 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText @Composable @@ -51,13 +51,13 @@ fun NewPollRecipientsField( enabled = false, label = { Text( - text = stringResource(R.string.poll_zap_recipients), + text = stringRes(R.string.poll_zap_recipients), color = MaterialTheme.colorScheme.placeholderText, ) }, placeholder = { Text( - text = stringResource(R.string.poll_zap_recipients), + text = stringRes(R.string.poll_zap_recipients), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt index 806eee50bd..a49b488daf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPollVoteValueRange.kt @@ -34,11 +34,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -67,13 +67,13 @@ fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) { colors = if (pollViewModel.isValidvalueMinimum.value) colorValid else colorInValid, label = { Text( - text = stringResource(R.string.poll_zap_value_min), + text = stringRes(R.string.poll_zap_value_min), color = MaterialTheme.colorScheme.placeholderText, ) }, placeholder = { Text( - text = stringResource(R.string.sats), + text = stringRes(R.string.sats), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -89,13 +89,13 @@ fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) { colors = if (pollViewModel.isValidvalueMaximum.value) colorValid else colorInValid, label = { Text( - text = stringResource(R.string.poll_zap_value_max), + text = stringRes(R.string.poll_zap_value_max), color = MaterialTheme.colorScheme.placeholderText, ) }, placeholder = { Text( - text = stringResource(R.string.sats), + text = stringRes(R.string.sats), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -107,7 +107,7 @@ fun NewPollVoteValueRange(pollViewModel: NewPostViewModel) { horizontalArrangement = Arrangement.Center, ) { Text( - text = stringResource(R.string.poll_zap_value_min_max_explainer), + text = stringRes(R.string.poll_zap_value_min_max_explainer), color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.padding(vertical = 10.dp), ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 225f63b40c..c6a2b83b22 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -105,7 +105,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization @@ -150,6 +149,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.MyTextField import com.vitorpamplona.amethyst.ui.screen.loggedIn.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -276,7 +276,7 @@ fun NewPostView( ) { Icon( painter = painterResource(R.drawable.relays), - contentDescription = stringResource(id = R.string.relay_list_selector), + contentDescription = stringRes(id = R.string.relay_list_selector), modifier = Modifier.height(25.dp), tint = MaterialTheme.colorScheme.onBackground, ) @@ -510,8 +510,8 @@ fun NewPostView( lud16, accountViewModel.account.userProfile().pubkeyHex, accountViewModel.account, - stringResource(id = R.string.lightning_invoice), - stringResource(id = R.string.lightning_create_and_add_invoice), + stringRes(id = R.string.lightning_invoice), + stringRes(id = R.string.lightning_create_and_add_invoice), onSuccess = { postViewModel.insertAtCursor(it) postViewModel.wantsInvoice = false @@ -530,7 +530,7 @@ fun NewPostView( modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp), ) { ZapRaiserRequest( - stringResource(id = R.string.zapraiser), + stringRes(id = R.string.zapraiser), postViewModel, ) } @@ -574,7 +574,7 @@ private fun BottomRowActions(postViewModel: NewPostViewModel) { if (postViewModel.canUsePoll) { // These should be hashtag recommendations the user selects in the future. - // val hashtag = stringResource(R.string.poll_hashtag) + // val hashtag = stringRes(R.string.poll_hashtag) // postViewModel.includePollHashtagInMessage(postViewModel.wantsPoll, hashtag) AddPollButton(postViewModel.wantsPoll) { postViewModel.wantsPoll = !postViewModel.wantsPoll @@ -685,9 +685,9 @@ private fun MessageField(postViewModel: NewPostViewModel) { Text( text = if (postViewModel.wantsProduct) { - stringResource(R.string.description) + stringRes(R.string.description) } else { - stringResource(R.string.what_s_on_your_mind) + stringRes(R.string.what_s_on_your_mind) }, color = MaterialTheme.colorScheme.placeholderText, ) @@ -721,7 +721,7 @@ fun ContentSensitivityExplainer(postViewModel: NewPostViewModel) { ) { Icon( imageVector = Icons.Default.VisibilityOff, - contentDescription = stringResource(id = R.string.content_warning), + contentDescription = stringRes(id = R.string.content_warning), modifier = Modifier .size(18.dp) @@ -730,7 +730,7 @@ fun ContentSensitivityExplainer(postViewModel: NewPostViewModel) { ) Icon( imageVector = Icons.Rounded.Warning, - contentDescription = stringResource(id = R.string.content_warning), + contentDescription = stringRes(id = R.string.content_warning), modifier = Modifier .size(10.dp) @@ -740,7 +740,7 @@ fun ContentSensitivityExplainer(postViewModel: NewPostViewModel) { } Text( - text = stringResource(R.string.add_sensitive_content_label), + text = stringRes(R.string.add_sensitive_content_label), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(start = 10.dp), @@ -750,7 +750,7 @@ fun ContentSensitivityExplainer(postViewModel: NewPostViewModel) { HorizontalDivider(thickness = DividerThickness) Text( - text = stringResource(R.string.add_sensitive_content_explainer), + text = stringRes(R.string.add_sensitive_content_explainer), color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.padding(vertical = 10.dp), ) @@ -767,7 +767,7 @@ fun SendDirectMessageTo(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.messages_new_message_to), + text = stringRes(R.string.messages_new_message_to), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -778,7 +778,7 @@ fun SendDirectMessageTo(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.messages_new_message_to_caption), + text = stringRes(R.string.messages_new_message_to_caption), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -801,7 +801,7 @@ fun SendDirectMessageTo(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.messages_new_message_subject), + text = stringRes(R.string.messages_new_message_subject), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -812,7 +812,7 @@ fun SendDirectMessageTo(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.messages_new_message_subject_caption), + text = stringRes(R.string.messages_new_message_subject_caption), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -842,7 +842,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.classifieds_title), + text = stringRes(R.string.classifieds_title), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -855,7 +855,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.classifieds_title_placeholder), + text = stringRes(R.string.classifieds_title_placeholder), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -878,7 +878,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.classifieds_price), + text = stringRes(R.string.classifieds_price), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -915,7 +915,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.classifieds_condition), + text = stringRes(R.string.classifieds_condition), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -924,23 +924,23 @@ fun SellProduct(postViewModel: NewPostViewModel) { listOf( Triple( ClassifiedsEvent.CONDITION.NEW, - stringResource(id = R.string.classifieds_condition_new), - stringResource(id = R.string.classifieds_condition_new_explainer), + stringRes(id = R.string.classifieds_condition_new), + stringRes(id = R.string.classifieds_condition_new_explainer), ), Triple( ClassifiedsEvent.CONDITION.USED_LIKE_NEW, - stringResource(id = R.string.classifieds_condition_like_new), - stringResource(id = R.string.classifieds_condition_like_new_explainer), + stringRes(id = R.string.classifieds_condition_like_new), + stringRes(id = R.string.classifieds_condition_like_new_explainer), ), Triple( ClassifiedsEvent.CONDITION.USED_GOOD, - stringResource(id = R.string.classifieds_condition_good), - stringResource(id = R.string.classifieds_condition_good_explainer), + stringRes(id = R.string.classifieds_condition_good), + stringRes(id = R.string.classifieds_condition_good_explainer), ), Triple( ClassifiedsEvent.CONDITION.USED_FAIR, - stringResource(id = R.string.classifieds_condition_fair), - stringResource(id = R.string.classifieds_condition_fair_explainer), + stringRes(id = R.string.classifieds_condition_fair), + stringRes(id = R.string.classifieds_condition_fair_explainer), ), ) @@ -982,7 +982,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.classifieds_category), + text = stringRes(R.string.classifieds_category), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -1007,7 +1007,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { R.string.classifieds_category_other, ) - val categoryTypes = categoryList.map { Triple(it, stringResource(id = it), null) } + val categoryTypes = categoryList.map { Triple(it, stringRes(id = it), null) } val categoryOptions = remember { @@ -1048,7 +1048,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(R.string.classifieds_location), + text = stringRes(R.string.classifieds_location), fontSize = Font14SP, fontWeight = FontWeight.W500, ) @@ -1061,7 +1061,7 @@ fun SellProduct(postViewModel: NewPostViewModel) { modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.classifieds_location_placeholder), + text = stringRes(R.string.classifieds_location_placeholder), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -1099,21 +1099,21 @@ fun FowardZapTo( ZapSplitIcon() Text( - text = stringResource(R.string.zap_split_title), + text = stringRes(R.string.zap_split_title), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(horizontal = 10.dp).weight(1f), ) OutlinedButton(onClick = { postViewModel.updateZapFromText() }) { - Text(text = stringResource(R.string.load_from_text)) + Text(text = stringRes(R.string.load_from_text)) } } HorizontalDivider(thickness = DividerThickness) Text( - text = stringResource(R.string.zap_split_explainer), + text = stringRes(R.string.zap_split_explainer), color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.padding(vertical = 10.dp), ) @@ -1154,11 +1154,11 @@ fun FowardZapTo( OutlinedTextField( value = postViewModel.forwardZapToEditting, onValueChange = { postViewModel.updateZapForwardTo(it) }, - label = { Text(text = stringResource(R.string.zap_split_search_and_add_user)) }, + label = { Text(text = stringRes(R.string.zap_split_search_and_add_user)) }, modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.zap_split_search_and_add_user_placeholder), + text = stringRes(R.string.zap_split_search_and_add_user_placeholder), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -1205,7 +1205,7 @@ fun LocationAsHash(postViewModel: NewPostViewModel) { } Text( - text = stringResource(R.string.geohash_title), + text = stringRes(R.string.geohash_title), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(start = 10.dp), @@ -1217,7 +1217,7 @@ fun LocationAsHash(postViewModel: NewPostViewModel) { HorizontalDivider(thickness = DividerThickness) Text( - text = stringResource(R.string.geohash_explainer), + text = stringRes(R.string.geohash_explainer), color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.padding(vertical = 10.dp), ) @@ -1275,7 +1275,7 @@ fun Notifying( FlowRow(horizontalArrangement = Arrangement.spacedBy(5.dp)) { if (!mentions.isNullOrEmpty()) { Text( - stringResource(R.string.reply_notify), + stringRes(R.string.reply_notify), fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.align(CenterVertically), @@ -1348,7 +1348,7 @@ private fun AddZapraiserButton( ) Icon( imageVector = Icons.Default.Bolt, - contentDescription = stringResource(R.string.add_zapraiser), + contentDescription = stringRes(R.string.add_zapraiser), modifier = Modifier .size(13.dp) @@ -1367,7 +1367,7 @@ private fun AddZapraiserButton( ) Icon( imageVector = Icons.Default.Bolt, - contentDescription = stringResource(R.string.cancel_zapraiser), + contentDescription = stringRes(R.string.cancel_zapraiser), modifier = Modifier .size(13.dp) @@ -1390,14 +1390,14 @@ fun AddGeoHash( if (!postViewModel.wantsToAddGeoHash) { Icon( imageVector = Icons.Default.LocationOff, - contentDescription = stringResource(id = R.string.add_location), + contentDescription = stringRes(id = R.string.add_location), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onBackground, ) } else { Icon( imageVector = Icons.Default.LocationOn, - contentDescription = stringResource(id = R.string.remove_location), + contentDescription = stringRes(id = R.string.remove_location), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.primary, ) @@ -1416,14 +1416,14 @@ private fun AddLnInvoiceButton( if (!isLnInvoiceActive) { Icon( imageVector = Icons.Default.CurrencyBitcoin, - contentDescription = stringResource(id = R.string.add_bitcoin_invoice), + contentDescription = stringRes(id = R.string.add_bitcoin_invoice), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onBackground, ) } else { Icon( imageVector = Icons.Default.CurrencyBitcoin, - contentDescription = stringResource(id = R.string.cancel_bitcoin_invoice), + contentDescription = stringRes(id = R.string.cancel_bitcoin_invoice), modifier = Modifier.size(20.dp), tint = BitcoinOrange, ) @@ -1458,14 +1458,14 @@ private fun AddClassifiedsButton( if (!postViewModel.wantsProduct) { Icon( imageVector = Icons.Default.Sell, - contentDescription = stringResource(R.string.classifieds), + contentDescription = stringRes(R.string.classifieds), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onBackground, ) } else { Icon( imageVector = Icons.Default.Sell, - contentDescription = stringResource(id = R.string.cancel_classifieds), + contentDescription = stringRes(id = R.string.cancel_classifieds), modifier = Modifier.size(20.dp), tint = BitcoinOrange, ) @@ -1489,7 +1489,7 @@ private fun MarkAsSensitive( if (!postViewModel.wantsToMarkAsSensitive) { Icon( imageVector = Icons.Default.Visibility, - contentDescription = stringResource(R.string.add_content_warning), + contentDescription = stringRes(R.string.add_content_warning), modifier = Modifier .size(18.dp) @@ -1498,7 +1498,7 @@ private fun MarkAsSensitive( ) Icon( imageVector = Icons.Rounded.Warning, - contentDescription = stringResource(R.string.add_content_warning), + contentDescription = stringRes(R.string.add_content_warning), modifier = Modifier .size(10.dp) @@ -1508,7 +1508,7 @@ private fun MarkAsSensitive( } else { Icon( imageVector = Icons.Default.VisibilityOff, - contentDescription = stringResource(id = R.string.remove_content_warning), + contentDescription = stringRes(id = R.string.remove_content_warning), modifier = Modifier .size(18.dp) @@ -1517,7 +1517,7 @@ private fun MarkAsSensitive( ) Icon( imageVector = Icons.Rounded.Warning, - contentDescription = stringResource(id = R.string.remove_content_warning), + contentDescription = stringRes(id = R.string.remove_content_warning), modifier = Modifier .size(10.dp) @@ -1550,7 +1550,7 @@ fun PostButton( enabled = isActive, onClick = onPost, ) { - Text(text = stringResource(R.string.post)) + Text(text = stringRes(R.string.post)) } } @@ -1565,7 +1565,7 @@ fun SaveButton( modifier = modifier, onClick = onPost, ) { - Text(text = stringResource(R.string.save)) + Text(text = stringRes(R.string.save)) } } @@ -1588,7 +1588,7 @@ fun CreateButton( containerColor = if (isActive) MaterialTheme.colorScheme.primary else Color.Gray, ), ) { - Text(text = stringResource(R.string.create), color = Color.White) + Text(text = stringRes(R.string.create), color = Color.White) } } @@ -1613,7 +1613,7 @@ fun ImageVideoDescription( ServerOption( Nip96MediaServers.ServerName( "NIP95", - stringResource(id = R.string.upload_server_relays_nip95), + stringRes(id = R.string.upload_server_relays_nip95), ), true, ), @@ -1655,7 +1655,7 @@ fun ImageVideoDescription( ) { Text( text = - stringResource( + stringRes( if (isImage) { R.string.content_description_add_image } else { @@ -1745,7 +1745,7 @@ fun ImageVideoDescription( modifier = Modifier.fillMaxWidth(), ) { TextSpinner( - label = stringResource(id = R.string.file_server), + label = stringRes(id = R.string.file_server), placeholder = fileServers .firstOrNull { it.server == accountViewModel.account.defaultFileServer } @@ -1785,7 +1785,7 @@ fun ImageVideoDescription( .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)), ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.content_description)) }, + label = { Text(text = stringRes(R.string.content_description)) }, modifier = Modifier .fillMaxWidth() @@ -1794,7 +1794,7 @@ fun ImageVideoDescription( onValueChange = { message = it }, placeholder = { Text( - text = stringResource(R.string.content_description_example), + text = stringRes(R.string.content_description_example), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -1817,7 +1817,7 @@ fun ImageVideoDescription( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(text = stringResource(R.string.add_content), color = Color.White, fontSize = 20.sp) + Text(text = stringRes(R.string.add_content), color = Color.White, fontSize = 20.sp) } } } @@ -1851,12 +1851,12 @@ fun SettingSwitchItem( verticalArrangement = Arrangement.spacedBy(Size5dp), ) { Text( - text = stringResource(id = title), + text = stringRes(id = title), maxLines = 1, overflow = TextOverflow.Ellipsis, ) Text( - text = stringResource(id = description), + text = stringRes(id = description), style = MaterialTheme.typography.bodySmall, color = Color.Gray, maxLines = 2, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt index dd0446d20e..e4dbc5a8f6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog @@ -48,6 +47,7 @@ import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -108,13 +108,13 @@ fun NewUserMetadataView( modifier = Modifier.padding(10.dp).verticalScroll(rememberScrollState()), ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.display_name)) }, + label = { Text(text = stringRes(R.string.display_name)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.displayName.value, onValueChange = { postViewModel.displayName.value = it }, placeholder = { Text( - text = stringResource(R.string.my_display_name), + text = stringRes(R.string.my_display_name), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -128,13 +128,13 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.about_me)) }, + label = { Text(text = stringRes(R.string.about_me)) }, modifier = Modifier.fillMaxWidth().height(100.dp), value = postViewModel.about.value, onValueChange = { postViewModel.about.value = it }, placeholder = { Text( - text = stringResource(id = R.string.about_me), + text = stringRes(id = R.string.about_me), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -148,7 +148,7 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.avatar_url)) }, + label = { Text(text = stringRes(R.string.avatar_url)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.picture.value, onValueChange = { postViewModel.picture.value = it }, @@ -173,7 +173,7 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.banner_url)) }, + label = { Text(text = stringRes(R.string.banner_url)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.banner.value, onValueChange = { postViewModel.banner.value = it }, @@ -198,7 +198,7 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.website_url)) }, + label = { Text(text = stringRes(R.string.website_url)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.website.value, onValueChange = { postViewModel.website.value = it }, @@ -214,7 +214,7 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.nip_05)) }, + label = { Text(text = stringRes(R.string.nip_05)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.nip05.value, onValueChange = { postViewModel.nip05.value = it }, @@ -229,7 +229,7 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.ln_address)) }, + label = { Text(text = stringRes(R.string.ln_address)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.lnAddress.value, onValueChange = { postViewModel.lnAddress.value = it }, @@ -245,13 +245,13 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.ln_url_outdated)) }, + label = { Text(text = stringRes(R.string.ln_url_outdated)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.lnURL.value, onValueChange = { postViewModel.lnURL.value = it }, placeholder = { Text( - text = stringResource(R.string.lnurl), + text = stringRes(R.string.lnurl), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -260,13 +260,13 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.twitter)) }, + label = { Text(text = stringRes(R.string.twitter)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.twitter.value, onValueChange = { postViewModel.twitter.value = it }, placeholder = { Text( - text = stringResource(R.string.twitter_proof_url_template), + text = stringRes(R.string.twitter_proof_url_template), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -275,13 +275,13 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.mastodon)) }, + label = { Text(text = stringRes(R.string.mastodon)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.mastodon.value, onValueChange = { postViewModel.mastodon.value = it }, placeholder = { Text( - text = stringResource(R.string.mastodon_proof_url_template), + text = stringRes(R.string.mastodon_proof_url_template), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -290,13 +290,13 @@ fun NewUserMetadataView( Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.github)) }, + label = { Text(text = stringRes(R.string.github)) }, modifier = Modifier.fillMaxWidth(), value = postViewModel.github.value, onValueChange = { postViewModel.github.value = it }, placeholder = { Text( - text = stringResource(R.string.github_proof_url_template), + text = stringRes(R.string.github_proof_url_template), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt index 4c80efb0b4..806e20a060 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt @@ -38,10 +38,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size16dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.quartz.events.EmptyTagList @@ -89,7 +89,7 @@ fun NotifyRequestDialog( contentDescription = null, ) Spacer(StdHorzSpacer) - Text(stringResource(R.string.error_dialog_button_ok)) + Text(stringRes(R.string.error_dialog_button_ok)) } } }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt index 9addb828c1..fceca37605 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/RelaySelectionDialog.kt @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.quartz.encoders.Nip11RelayInformation import kotlinx.collections.immutable.ImmutableList @@ -141,7 +142,7 @@ fun RelaySelectionDialog( } RelaySwitch( - text = context.getString(R.string.select_deselect_all), + text = stringRes(context, R.string.select_deselect_all), checked = selected, onClick = { selected = !selected @@ -185,25 +186,29 @@ fun RelaySelectionDialog( val msg = when (errorCode) { Nip11Retriever.ErrorCode.FAIL_TO_ASSEMBLE_URL -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_TO_REACH_SERVER -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_TO_PARSE_RESULT -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_WITH_HTTP_STATUS -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, @@ -211,7 +216,7 @@ fun RelaySelectionDialog( } accountViewModel.toast( - context.getString(R.string.unable_to_download_relay_document), + stringRes(context, R.string.unable_to_download_relay_document), msg, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt index 10e8ec0dbe..7c6ffb30de 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt @@ -28,11 +28,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import kotlinx.coroutines.launch import java.io.File @@ -54,22 +54,22 @@ fun SaveToGallery(url: String) { url = url, onSuccess = { scope.launch { - Toast.makeText( - localContext, - localContext.getString(R.string.image_saved_to_the_gallery), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + localContext, + stringRes(localContext, R.string.image_saved_to_the_gallery), + Toast.LENGTH_SHORT, + ).show() } }, onError = { scope.launch { - Toast.makeText( - localContext, - localContext.getString(R.string.failed_to_save_the_image), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + localContext, + stringRes(localContext, R.string.failed_to_save_the_image), + Toast.LENGTH_SHORT, + ).show() } }, ) @@ -96,7 +96,7 @@ fun SaveToGallery(url: String) { } }, ) { - Text(text = stringResource(id = R.string.save)) + Text(text = stringRes(id = R.string.save)) } } @@ -116,22 +116,22 @@ fun SaveToGallery( mimeType = mimeType, onSuccess = { scope.launch { - Toast.makeText( - localContext, - localContext.getString(R.string.image_saved_to_the_gallery), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + localContext, + stringRes(localContext, R.string.image_saved_to_the_gallery), + Toast.LENGTH_SHORT, + ).show() } }, onError = { scope.launch { - Toast.makeText( - localContext, - localContext.getString(R.string.failed_to_save_the_image), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + localContext, + stringRes(localContext, R.string.failed_to_save_the_image), + Toast.LENGTH_SHORT, + ).show() } }, ) @@ -159,6 +159,6 @@ fun SaveToGallery( }, shape = ButtonBorder, ) { - Text(text = stringResource(id = R.string.save)) + Text(text = stringRes(id = R.string.save)) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt index 0384ca6524..8c8d6b3a80 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt @@ -50,7 +50,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -58,6 +57,7 @@ import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.GetMediaActivityResultContract +import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import java.util.concurrent.atomic.AtomicBoolean @@ -114,7 +114,7 @@ private fun UploadBoxButton( if (!isUploading) { Icon( imageVector = Icons.Default.AddPhotoAlternate, - contentDescription = stringResource(id = R.string.upload_image), + contentDescription = stringRes(id = R.string.upload_image), modifier = Modifier.height(25.dp), tint = tint, ) @@ -137,8 +137,7 @@ val DefaultAnimationColors = Color(0xFFFCAF45), Color(0xFFFFDC80), Color(0xFF5851D8), - ) - .toImmutableList() + ).toImmutableList() @Composable fun LoadingAnimation( @@ -164,7 +163,8 @@ fun LoadingAnimation( CircularProgressIndicator( modifier = - Modifier.size(size = indicatorSize) + Modifier + .size(size = indicatorSize) .rotate(degrees = rotateAnimation) .border( width = 4.dp, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt index 90f684c6d6..77e55e9eca 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddDMRelayListDialog.kt @@ -37,7 +37,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -46,6 +45,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.SaveButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.imageModifier @@ -76,7 +76,7 @@ fun AddDMRelayListDialog( ) { Spacer(modifier = StdHorzSpacer) - Text(stringResource(R.string.dm_relays_title)) + Text(stringRes(R.string.dm_relays_title)) SaveButton( onPost = { @@ -126,13 +126,13 @@ private fun Explanation() { Card(modifier = MaterialTheme.colorScheme.imageModifier) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(id = R.string.dm_relays_not_found_editing), + text = stringRes(id = R.string.dm_relays_not_found_editing), ) Spacer(modifier = StdVertSpacer) Text( - text = stringResource(id = R.string.dm_relays_not_found_examples), + text = stringRes(id = R.string.dm_relays_not_found_examples), ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt index 62e3469378..137024d701 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AddSearchRelayListDialog.kt @@ -37,7 +37,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -46,6 +45,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.SaveButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.imageModifier @@ -76,7 +76,7 @@ fun AddSearchRelayListDialog( ) { Spacer(modifier = StdHorzSpacer) - Text(stringResource(R.string.search_relays_title)) + Text(stringRes(R.string.search_relays_title)) SaveButton( onPost = { @@ -126,13 +126,13 @@ private fun Explanation() { Card(modifier = MaterialTheme.colorScheme.imageModifier) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(id = R.string.search_relays_not_found_editing), + text = stringRes(id = R.string.search_relays_not_found_editing), ) Spacer(modifier = StdVertSpacer) Text( - text = stringResource(id = R.string.search_relays_not_found_examples), + text = stringRes(id = R.string.search_relays_not_found_examples), ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt index 0dbf3bc8f6..d4171938e2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/AllRelayListView.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -52,6 +51,7 @@ import com.vitorpamplona.amethyst.service.relays.RelayStat import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.SaveButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.MinHorzSpacer import com.vitorpamplona.amethyst.ui.theme.RowColSpacing @@ -110,7 +110,7 @@ fun AllRelayListView( Spacer(modifier = MinHorzSpacer) Text( - text = stringResource(R.string.relay_settings), + text = stringRes(R.string.relay_settings), style = MaterialTheme.typography.titleLarge, ) @@ -166,8 +166,8 @@ fun AllRelayListView( LazyColumn(contentPadding = FeedPadding) { item { SettingsCategory( - stringResource(R.string.public_home_section), - stringResource(R.string.public_home_section_explainer), + stringRes(R.string.public_home_section), + stringRes(R.string.public_home_section_explainer), Modifier.padding(bottom = 8.dp), ) } @@ -175,32 +175,32 @@ fun AllRelayListView( item { SettingsCategory( - stringResource(R.string.public_notif_section), - stringResource(R.string.public_notif_section_explainer), + stringRes(R.string.public_notif_section), + stringRes(R.string.public_notif_section_explainer), ) } renderNip65NotifItems(notifFeedState, nip65ViewModel, accountViewModel, onClose, nav) item { SettingsCategory( - stringResource(R.string.private_inbox_section), - stringResource(R.string.private_inbox_section_explainer), + stringRes(R.string.private_inbox_section), + stringRes(R.string.private_inbox_section_explainer), ) } renderDMItems(dmFeedState, dmViewModel, accountViewModel, onClose, nav) item { SettingsCategory( - stringResource(R.string.private_outbox_section), - stringResource(R.string.private_outbox_section_explainer), + stringRes(R.string.private_outbox_section), + stringRes(R.string.private_outbox_section_explainer), ) } renderPrivateOutboxItems(privateOutboxFeedState, privateOutboxViewModel, accountViewModel, onClose, nav) item { SettingsCategoryWithButton( - stringResource(R.string.search_section), - stringResource(R.string.search_section_explainer), + stringRes(R.string.search_section), + stringRes(R.string.search_section_explainer), action = { ResetSearchRelays(searchViewModel) }, @@ -210,16 +210,16 @@ fun AllRelayListView( item { SettingsCategory( - stringResource(R.string.local_section), - stringResource(R.string.local_section_explainer), + stringRes(R.string.local_section), + stringRes(R.string.local_section_explainer), ) } renderLocalItems(localFeedState, localViewModel, accountViewModel, onClose, nav) item { SettingsCategoryWithButton( - stringResource(R.string.kind_3_section), - stringResource(R.string.kind_3_section_description), + stringRes(R.string.kind_3_section), + stringRes(R.string.kind_3_section_description), action = { ResetKind3Relays(kind3ViewModel) }, @@ -241,7 +241,7 @@ fun ResetKind3Relays(postViewModel: Kind3RelayListViewModel) { postViewModel.loadRelayDocuments() }, ) { - Text(stringResource(R.string.default_relays)) + Text(stringRes(R.string.default_relays)) } } @@ -254,7 +254,7 @@ fun ResetSearchRelays(postViewModel: SearchRelayListViewModel) { postViewModel.loadRelayDocuments() }, ) { - Text(stringResource(R.string.default_relays)) + Text(stringRes(R.string.default_relays)) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt index 3bd774fb7b..cc69a83c41 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoDialog.kt @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.model.RelayBriefInfoCache import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes @Composable fun BasicRelaySetupInfoDialog( @@ -69,28 +70,32 @@ fun BasicRelaySetupInfoDialog( val msg = when (errorCode) { Nip11Retriever.ErrorCode.FAIL_TO_ASSEMBLE_URL -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_TO_REACH_SERVER -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_TO_PARSE_RESULT -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_WITH_HTTP_STATUS -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, @@ -98,7 +103,7 @@ fun BasicRelaySetupInfoDialog( } accountViewModel.toast( - context.getString(R.string.unable_to_download_relay_document), + stringRes(context, R.string.unable_to_download_relay_document), msg, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt index f0f09b413c..e6d6cd0a51 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListView.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt index f6199fc5be..0eba7699e2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListView.kt @@ -61,7 +61,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -77,6 +76,7 @@ import com.vitorpamplona.amethyst.service.relays.RelayStat import com.vitorpamplona.amethyst.ui.actions.RelayInfoDialog import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding @@ -224,28 +224,32 @@ fun LoadRelayInfo( val msg = when (errorCode) { Nip11Retriever.ErrorCode.FAIL_TO_ASSEMBLE_URL -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_TO_REACH_SERVER -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_TO_PARSE_RESULT -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, ) Nip11Retriever.ErrorCode.FAIL_WITH_HTTP_STATUS -> - context.getString( + stringRes( + context, R.string.relay_information_document_error_assemble_url, url, exceptionMessage, @@ -253,7 +257,7 @@ fun LoadRelayInfo( } accountViewModel.toast( - context.getString(R.string.unable_to_download_relay_document), + stringRes(context, R.string.unable_to_download_relay_document), msg, ) }, @@ -346,7 +350,7 @@ private fun StatusRow( Icon( imageVector = Icons.Default.Download, - contentDescription = stringResource(R.string.read_from_relay), + contentDescription = stringRes(R.string.read_from_relay), modifier = Modifier .size(15.dp) @@ -357,7 +361,7 @@ private fun StatusRow( Toast .makeText( context, - context.getString(R.string.read_from_relay), + stringRes(context, R.string.read_from_relay), Toast.LENGTH_SHORT, ).show() } @@ -383,7 +387,7 @@ private fun StatusRow( Icon( imageVector = Icons.Default.Upload, - stringResource(R.string.write_to_relay), + stringRes(R.string.write_to_relay), modifier = Modifier .size(15.dp) @@ -394,7 +398,7 @@ private fun StatusRow( Toast .makeText( context, - context.getString(R.string.write_to_relay), + stringRes(context, R.string.write_to_relay), Toast.LENGTH_SHORT, ).show() } @@ -420,7 +424,7 @@ private fun StatusRow( Icon( imageVector = Icons.Default.SyncProblem, - stringResource(R.string.errors), + stringRes(R.string.errors), modifier = Modifier .size(15.dp) @@ -431,7 +435,7 @@ private fun StatusRow( Toast .makeText( context, - context.getString(R.string.errors), + stringRes(context, R.string.errors), Toast.LENGTH_SHORT, ).show() } @@ -455,7 +459,7 @@ private fun StatusRow( Icon( imageVector = Icons.Default.DeleteSweep, - stringResource(R.string.spam), + stringRes(R.string.spam), modifier = Modifier .size(15.dp) @@ -466,7 +470,7 @@ private fun StatusRow( Toast .makeText( context, - context.getString(R.string.spam), + stringRes(context, R.string.spam), Toast.LENGTH_SHORT, ).show() } @@ -502,7 +506,7 @@ private fun ActiveToggles( val context = LocalContext.current Text( - text = stringResource(id = R.string.active_for), + text = stringRes(id = R.string.active_for), maxLines = 1, overflow = TextOverflow.Ellipsis, color = MaterialTheme.colorScheme.placeholderText, @@ -516,7 +520,7 @@ private fun ActiveToggles( ) { Icon( painterResource(R.drawable.ic_home), - stringResource(R.string.home_feed), + stringRes(R.string.home_feed), modifier = Modifier .padding(horizontal = 5.dp) @@ -528,7 +532,7 @@ private fun ActiveToggles( Toast .makeText( context, - context.getString(R.string.home_feed), + stringRes(context, R.string.home_feed), Toast.LENGTH_SHORT, ).show() } @@ -550,7 +554,7 @@ private fun ActiveToggles( ) { Icon( painterResource(R.drawable.ic_dm), - stringResource(R.string.private_message_feed), + stringRes(R.string.private_message_feed), modifier = Modifier .padding(horizontal = 5.dp) @@ -562,7 +566,7 @@ private fun ActiveToggles( Toast .makeText( context, - context.getString(R.string.private_message_feed), + stringRes(context, R.string.private_message_feed), Toast.LENGTH_SHORT, ).show() } @@ -584,7 +588,7 @@ private fun ActiveToggles( ) { Icon( imageVector = Icons.Default.Groups, - contentDescription = stringResource(R.string.public_chat_feed), + contentDescription = stringRes(R.string.public_chat_feed), modifier = Modifier .padding(horizontal = 5.dp) @@ -596,7 +600,7 @@ private fun ActiveToggles( Toast .makeText( context, - context.getString(R.string.public_chat_feed), + stringRes(context, R.string.public_chat_feed), Toast.LENGTH_SHORT, ).show() } @@ -618,7 +622,7 @@ private fun ActiveToggles( ) { Icon( imageVector = Icons.Default.Public, - stringResource(R.string.global_feed), + stringRes(R.string.global_feed), modifier = Modifier .padding(horizontal = 5.dp) @@ -630,7 +634,7 @@ private fun ActiveToggles( Toast .makeText( context, - context.getString(R.string.global_feed), + stringRes(context, R.string.global_feed), Toast.LENGTH_SHORT, ).show() } @@ -680,7 +684,7 @@ private fun FirstLine( ) { Icon( imageVector = Icons.Default.Cancel, - contentDescription = stringResource(id = R.string.remove), + contentDescription = stringRes(id = R.string.remove), modifier = Modifier.padding(start = 10.dp).size(15.dp), tint = WarningColor, ) @@ -699,7 +703,7 @@ fun Kind3RelayEditBox( Row(verticalAlignment = Alignment.CenterVertically) { OutlinedTextField( - label = { Text(text = stringResource(R.string.add_a_relay)) }, + label = { Text(text = stringRes(R.string.add_a_relay)) }, modifier = Modifier.weight(1f), value = url, onValueChange = { url = it }, @@ -716,7 +720,7 @@ fun Kind3RelayEditBox( IconButton(onClick = { read = !read }) { Icon( imageVector = Icons.Default.Download, - contentDescription = stringResource(id = R.string.read_from_relay), + contentDescription = stringRes(id = R.string.read_from_relay), modifier = Modifier.size(Size35dp).padding(horizontal = 5.dp), tint = if (read) { @@ -730,7 +734,7 @@ fun Kind3RelayEditBox( IconButton(onClick = { write = !write }) { Icon( imageVector = Icons.Default.Upload, - contentDescription = stringResource(id = R.string.write_to_relay), + contentDescription = stringRes(id = R.string.write_to_relay), modifier = Modifier.size(Size35dp).padding(horizontal = 5.dp), tint = if (write) { @@ -769,7 +773,7 @@ fun Kind3RelayEditBox( }, ), ) { - Text(text = stringResource(id = R.string.add), color = Color.White) + Text(text = stringRes(id = R.string.add), color = Color.White) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt index af9d2bc7d8..13d4406003 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListView.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt index ce285786a3..275b09c725 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListView.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt index 009da474d2..a1d051b9f3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListView.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt index 695e477478..fa4b5c0862 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayInformationDialog.kt @@ -42,7 +42,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -62,6 +61,7 @@ import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.amethyst.ui.note.timeAgo import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding @@ -144,7 +144,7 @@ fun RelayInformationDialog( } } item { - Section(stringResource(R.string.owner)) + Section(stringRes(R.string.owner)) relayInfo.pubkey?.let { DisplayOwnerInformation(it, accountViewModel) { @@ -154,16 +154,16 @@ fun RelayInformationDialog( } } item { - Section(stringResource(R.string.software)) + Section(stringRes(R.string.software)) DisplaySoftwareInformation(relayInfo) - Section(stringResource(R.string.version)) + Section(stringRes(R.string.version)) SectionContent(relayInfo.version ?: "") } item { - Section(stringResource(R.string.contact)) + Section(stringRes(R.string.contact)) Box(modifier = Modifier.padding(start = 10.dp)) { relayInfo.contact?.let { @@ -178,21 +178,21 @@ fun RelayInformationDialog( } } item { - Section(stringResource(R.string.supports)) + Section(stringRes(R.string.supports)) DisplaySupportedNips(relayInfo) } item { relayInfo.fees?.admission?.let { if (it.isNotEmpty()) { - Section(stringResource(R.string.admission_fees)) + Section(stringRes(R.string.admission_fees)) it.forEach { item -> SectionContent("${item.amount?.div(1000) ?: 0} sats") } } } relayInfo.payments_url?.let { - Section(stringResource(R.string.payments_url)) + Section(stringRes(R.string.payments_url)) Box(modifier = Modifier.padding(start = 10.dp)) { ClickableUrl( @@ -204,68 +204,68 @@ fun RelayInformationDialog( } item { relayInfo.limitation?.let { - Section(stringResource(R.string.limitations)) + Section(stringRes(R.string.limitations)) val authRequiredText = - if (it.auth_required ?: false) stringResource(R.string.yes) else stringResource(R.string.no) + if (it.auth_required ?: false) stringRes(R.string.yes) else stringRes(R.string.no) val paymentRequiredText = - if (it.payment_required ?: false) stringResource(R.string.yes) else stringResource(R.string.no) + if (it.payment_required ?: false) stringRes(R.string.yes) else stringRes(R.string.no) val restrictedWritesText = - if (it.restricted_writes ?: false) stringResource(R.string.yes) else stringResource(R.string.no) + if (it.restricted_writes ?: false) stringRes(R.string.yes) else stringRes(R.string.no) Column { SectionContent( - "${stringResource(R.string.message_length)}: ${it.max_message_length ?: 0}", + "${stringRes(R.string.message_length)}: ${it.max_message_length ?: 0}", ) SectionContent( - "${stringResource(R.string.subscriptions)}: ${it.max_subscriptions ?: 0}", + "${stringRes(R.string.subscriptions)}: ${it.max_subscriptions ?: 0}", ) - SectionContent("${stringResource(R.string.filters)}: ${it.max_filters ?: 0}") + SectionContent("${stringRes(R.string.filters)}: ${it.max_filters ?: 0}") SectionContent( - "${stringResource(R.string.subscription_id_length)}: ${it.max_subid_length ?: 0}", + "${stringRes(R.string.subscription_id_length)}: ${it.max_subid_length ?: 0}", ) - SectionContent("${stringResource(R.string.minimum_prefix)}: ${it.min_prefix ?: 0}") + SectionContent("${stringRes(R.string.minimum_prefix)}: ${it.min_prefix ?: 0}") SectionContent( - "${stringResource(R.string.maximum_event_tags)}: ${it.max_event_tags ?: 0}", + "${stringRes(R.string.maximum_event_tags)}: ${it.max_event_tags ?: 0}", ) SectionContent( - "${stringResource(R.string.content_length)}: ${it.max_content_length ?: 0}", + "${stringRes(R.string.content_length)}: ${it.max_content_length ?: 0}", ) SectionContent( - "${stringResource(R.string.max_limit)}: ${it.max_limit ?: 0}", + "${stringRes(R.string.max_limit)}: ${it.max_limit ?: 0}", ) - SectionContent("${stringResource(R.string.minimum_pow)}: ${it.min_pow_difficulty ?: 0}") - SectionContent("${stringResource(R.string.auth)}: $authRequiredText") - SectionContent("${stringResource(R.string.payment)}: $paymentRequiredText") - SectionContent("${stringResource(R.string.restricted_writes)}: $restrictedWritesText") + SectionContent("${stringRes(R.string.minimum_pow)}: ${it.min_pow_difficulty ?: 0}") + SectionContent("${stringRes(R.string.auth)}: $authRequiredText") + SectionContent("${stringRes(R.string.payment)}: $paymentRequiredText") + SectionContent("${stringRes(R.string.restricted_writes)}: $restrictedWritesText") } } } item { relayInfo.relay_countries?.let { - Section(stringResource(R.string.countries)) + Section(stringRes(R.string.countries)) FlowRow { it.forEach { item -> SectionContent(item) } } } } item { relayInfo.language_tags?.let { - Section(stringResource(R.string.languages)) + Section(stringRes(R.string.languages)) FlowRow { it.forEach { item -> SectionContent(item) } } } } item { relayInfo.tags?.let { - Section(stringResource(R.string.tags)) + Section(stringRes(R.string.tags)) FlowRow { it.forEach { item -> SectionContent(item) } } } } item { relayInfo.posting_policy?.let { - Section(stringResource(R.string.posting_policy)) + Section(stringRes(R.string.posting_policy)) Box(Modifier.padding(10.dp)) { ClickableUrl( @@ -277,7 +277,7 @@ fun RelayInformationDialog( } item { - Section(stringResource(R.string.relay_error_messages)) + Section(stringRes(R.string.relay_error_messages)) } items(messages) { msg -> diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt index 18e0d36fb5..4d71d403f8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayNameAndRemoveButton.kt @@ -34,10 +34,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.WarningColor import com.vitorpamplona.amethyst.ui.theme.allGoodColor @@ -76,7 +76,7 @@ fun RelayNameAndRemoveButton( ) { Icon( imageVector = Icons.Default.Cancel, - contentDescription = stringResource(id = R.string.remove), + contentDescription = stringRes(id = R.string.remove), modifier = Modifier .padding(start = 10.dp) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt index 755a3566d8..8ebf04afad 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayStatusRow.kt @@ -36,11 +36,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.allGoodColor import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.warningColor @@ -58,7 +58,7 @@ fun RelayStatusRow( Icon( imageVector = Icons.Default.Download, - contentDescription = stringResource(R.string.read_from_relay), + contentDescription = stringRes(R.string.read_from_relay), modifier = Modifier .size(15.dp) @@ -84,7 +84,7 @@ fun RelayStatusRow( Icon( imageVector = Icons.Default.Upload, - stringResource(R.string.write_to_relay), + stringRes(R.string.write_to_relay), modifier = Modifier .size(15.dp) @@ -110,7 +110,7 @@ fun RelayStatusRow( Icon( imageVector = Icons.Default.SyncProblem, - stringResource(R.string.errors), + stringRes(R.string.errors), modifier = Modifier .size(15.dp) @@ -141,7 +141,7 @@ fun RelayStatusRow( Icon( imageVector = Icons.Default.DeleteSweep, - stringResource(R.string.spam), + stringRes(R.string.spam), modifier = Modifier .size(15.dp) @@ -153,12 +153,12 @@ fun RelayStatusRow( R.string.spam_description, ) scope.launch { - Toast.makeText( - context, - context.getString(R.string.spam), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + stringRes(context, R.string.spam), + Toast.LENGTH_SHORT, + ).show() } }, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt index 9af9c83262..ded0da3987 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/RelayUrlEditField.kt @@ -35,9 +35,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.relays.RelayStat +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -49,7 +49,7 @@ fun RelayUrlEditField(onNewRelay: (BasicRelaySetupInfo) -> Unit) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(Size10dp)) { OutlinedTextField( - label = { Text(text = stringResource(R.string.add_a_relay)) }, + label = { Text(text = stringRes(R.string.add_a_relay)) }, modifier = Modifier.weight(1f), value = url, onValueChange = { url = it }, @@ -81,7 +81,7 @@ fun RelayUrlEditField(onNewRelay: (BasicRelaySetupInfo) -> Unit) { }, ), ) { - Text(text = stringResource(id = R.string.add), color = Color.White) + Text(text = stringRes(id = R.string.add), color = Color.White) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt index bb9f1489c3..e203c9e397 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListView.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt index 5eb6d9e041..d556fe6f9c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/ChannelFabColumn.kt @@ -38,13 +38,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.NewChannelView import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Font12SP import com.vitorpamplona.amethyst.ui.theme.Size55Modifier @@ -86,7 +86,7 @@ fun ChannelFabColumn( containerColor = MaterialTheme.colorScheme.primary, ) { Text( - text = stringResource(R.string.messages_new_message), + text = stringRes(R.string.messages_new_message), color = Color.White, textAlign = TextAlign.Center, fontSize = Font12SP, @@ -105,7 +105,7 @@ fun ChannelFabColumn( containerColor = MaterialTheme.colorScheme.primary, ) { Text( - text = stringResource(R.string.messages_create_public_chat), + text = stringRes(R.string.messages_create_public_chat), color = Color.White, textAlign = TextAlign.Center, fontSize = Font12SP, @@ -123,7 +123,7 @@ fun ChannelFabColumn( ) { Icon( imageVector = Icons.Outlined.Add, - contentDescription = stringResource(R.string.messages_create_public_private_chat_description), + contentDescription = stringRes(R.string.messages_create_public_private_chat_description), modifier = Modifier.size(26.dp), tint = Color.White, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt index 2ca79c6849..7d69fc9540 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewChannelButton.kt @@ -35,11 +35,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.NewChannelView import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.ui.theme.ZeroPadding @@ -61,7 +61,7 @@ fun NewChannelButton(accountViewModel: AccountViewModel) { ) { Icon( imageVector = Icons.Outlined.Add, - contentDescription = stringResource(R.string.new_channel), + contentDescription = stringRes(R.string.new_channel), modifier = Modifier.size(26.dp), tint = Color.White, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt index 63f132eebc..78f39e7692 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewCommunityNoteButton.kt @@ -33,13 +33,13 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size55Modifier @Composable @@ -73,7 +73,7 @@ fun NewCommunityNoteButton( ) { Icon( painter = painterResource(R.drawable.ic_compose), - contentDescription = stringResource(id = R.string.new_community_note), + contentDescription = stringRes(id = R.string.new_community_note), modifier = Modifier.size(26.dp), tint = Color.White, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt index 16973d1c33..5724d57b45 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewImageButton.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -60,6 +59,7 @@ import com.vitorpamplona.amethyst.ui.actions.NewMediaModel import com.vitorpamplona.amethyst.ui.actions.NewMediaView import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size55Modifier import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -136,7 +136,7 @@ fun NewImageButton( ) { Icon( painter = painterResource(R.drawable.ic_compose), - contentDescription = stringResource(id = R.string.new_short), + contentDescription = stringRes(id = R.string.new_short), modifier = Modifier.size(26.dp), tint = Color.White, ) @@ -152,8 +152,7 @@ private fun ShowProgress(postViewModel: NewMediaModel) { animateFloatAsState( targetValue = postViewModel.uploadingPercentage.value, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, - ) - .value, + ).value, modifier = Size55Modifier .clip(CircleShape) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt index a0e8fe4407..cac2b8c490 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/buttons/NewNoteButton.kt @@ -33,11 +33,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size55Modifier @Composable @@ -59,7 +59,7 @@ fun NewNoteButton( ) { Icon( painter = painterResource(R.drawable.ic_compose), - contentDescription = stringResource(R.string.new_post), + contentDescription = stringRes(R.string.new_post), modifier = Modifier.size(26.dp), tint = Color.White, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt index 2ef53e03a0..9b7e17876d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt @@ -52,7 +52,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDirection @@ -76,6 +75,7 @@ import com.vitorpamplona.amethyst.ui.note.OpenInNewIcon import com.vitorpamplona.amethyst.ui.note.ZapIcon import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.AmethystTheme import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer @@ -190,7 +190,7 @@ fun CashuPreview( ) Text( - text = stringResource(R.string.cashu), + text = stringRes(R.string.cashu), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(start = 10.dp), @@ -200,7 +200,7 @@ fun CashuPreview( HorizontalDivider(thickness = DividerThickness) Text( - text = "${token.totalAmount} ${stringResource(id = R.string.sats)}", + text = "${token.totalAmount} ${stringRes(id = R.string.sats)}", fontSize = 25.sp, fontWeight = FontWeight.W500, modifier = @@ -239,7 +239,7 @@ fun CashuPreview( Spacer(DoubleHorzSpacer) Text( - stringResource(id = R.string.cashu_redeem_to_zap), + stringRes(id = R.string.cashu_redeem_to_zap), color = Color.White, fontSize = 16.sp, ) @@ -256,7 +256,7 @@ fun CashuPreview( startActivity(context, intent, null) } catch (e: Exception) { if (e is CancellationException) throw e - toast("Cashu", context.getString(R.string.cashu_no_wallet_found)) + toast(stringRes(context, R.string.cashu), stringRes(context, R.string.cashu_no_wallet_found)) } }, shape = QuoteBorder, @@ -268,7 +268,7 @@ fun CashuPreview( CashuIcon(Size20Modifier) Spacer(DoubleHorzSpacer) Text( - stringResource(id = R.string.cashu_redeem_to_cashu), + stringRes(id = R.string.cashu_redeem_to_cashu), color = Color.White, fontSize = 16.sp, ) @@ -287,7 +287,7 @@ fun CashuPreview( ) { CopyIcon(Size20Modifier, Color.White) Spacer(DoubleHorzSpacer) - Text(stringResource(id = R.string.cashu_copy_token), color = Color.White, fontSize = 16.sp) + Text(stringRes(id = R.string.cashu_copy_token), color = Color.White, fontSize = 16.sp) } Spacer(modifier = StdHorzSpacer) } @@ -328,14 +328,14 @@ fun CashuPreviewNew( ) Text( - text = stringResource(R.string.cashu), + text = stringRes(R.string.cashu), fontSize = 12.sp, modifier = Modifier.padding(start = 5.dp, bottom = 1.dp), ) } Text( - text = "${token.totalAmount} ${stringResource(id = R.string.sats)}", + text = "${token.totalAmount} ${stringRes(id = R.string.sats)}", fontSize = 20.sp, modifier = Modifier.padding(top = 5.dp), ) @@ -378,7 +378,7 @@ fun CashuPreviewNew( startActivity(context, intent, null) } catch (e: Exception) { if (e is CancellationException) throw e - toast("Cashu", context.getString(R.string.cashu_no_wallet_found)) + toast(stringRes(context, R.string.cashu), stringRes(context, R.string.cashu_no_wallet_found)) } }, shape = SmallishBorder, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt index 3dca50c64e..dd7cbea9af 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt @@ -470,13 +470,12 @@ fun CreateTextWithEmoji( overflow: TextOverflow = TextOverflow.Clip, modifier: Modifier = Modifier, ) { - val textColor = - color.takeOrElse { LocalTextStyle.current.color.takeOrElse { LocalContentColor.current } } - CustomEmojiChecker( text, tags, onEmojiText = { + val textColor = + color.takeOrElse { LocalTextStyle.current.color.takeOrElse { LocalContentColor.current } } val style = LocalTextStyle.current .merge( @@ -486,12 +485,13 @@ fun CreateTextWithEmoji( fontWeight = fontWeight, fontSize = fontSize, ), - ) - .toSpanStyle() + ).toSpanStyle() InLineIconRenderer(it, style, fontSize, maxLines, overflow, modifier) }, onRegularText = { + val textColor = + color.takeOrElse { LocalTextStyle.current.color.takeOrElse { LocalContentColor.current } } Text( text = it, color = textColor, @@ -536,8 +536,7 @@ fun CreateTextWithEmoji( fontWeight = fontWeight, fontSize = fontSize, ), - ) - .toSpanStyle() + ).toSpanStyle() } InLineIconRenderer(it, style, fontSize, maxLines, overflow, modifier) @@ -672,8 +671,7 @@ fun ClickableInLineIconRenderer( } else { null } - } - .associate { it.first to it.second } + }.associate { it.first to it.second } val annotatedText = buildAnnotatedString { @@ -757,8 +755,7 @@ fun InLineIconRenderer( } else { null } - } - .associate { it.first to it.second } + }.associate { it.first to it.second } val annotatedText = remember { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt index 67258d71fc..647d31c395 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt @@ -38,6 +38,7 @@ import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.ui.note.payViaIntent import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.encoders.LnWithdrawalUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -75,7 +76,7 @@ fun ClickableWithdrawal(withdrawalString: String) { if (showErrorMessageDialog != null) { ErrorMessageDialog( - title = context.getString(R.string.error_dialog_pay_withdraw_error), + title = stringRes(context, R.string.error_dialog_pay_withdraw_error), textContent = showErrorMessageDialog ?: "", onDismiss = { showErrorMessageDialog = null }, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index ae858719b7..c4445c71cf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -40,11 +40,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.richtext.ExpandableTextCutOffCalculator import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.StdTopPadding @@ -110,7 +110,8 @@ fun ExpandableRichTextViewer( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center, modifier = - Modifier.align(Alignment.BottomCenter) + Modifier + .align(Alignment.BottomCenter) .fillMaxWidth() .background(getGradient(backgroundColor)), ) { @@ -135,6 +136,6 @@ fun ShowMoreButton(onClick: () -> Unit) { ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.show_more), color = Color.White) + Text(text = stringRes(R.string.show_more), color = Color.White) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt index 623c66991a..bacc64738f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt @@ -43,7 +43,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.dp @@ -57,6 +56,7 @@ import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.ui.note.payViaIntent import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -112,7 +112,7 @@ fun InvoicePreview( if (showErrorMessageDialog != null) { ErrorMessageDialog( - title = context.getString(R.string.error_dialog_pay_invoice_error), + title = stringRes(context, R.string.error_dialog_pay_invoice_error), textContent = showErrorMessageDialog ?: "", onDismiss = { showErrorMessageDialog = null }, ) @@ -147,7 +147,7 @@ fun InvoicePreview( ) Text( - text = stringResource(R.string.lightning_invoice), + text = stringRes(R.string.lightning_invoice), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(start = 10.dp), @@ -158,7 +158,7 @@ fun InvoicePreview( amount?.let { Text( - text = "$it ${stringResource(id = R.string.sats)}", + text = "$it ${stringRes(id = R.string.sats)}", fontSize = 25.sp, fontWeight = FontWeight.W500, modifier = @@ -180,7 +180,7 @@ fun InvoicePreview( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(text = stringResource(R.string.pay), color = Color.White, fontSize = 20.sp) + Text(text = stringRes(R.string.pay), color = Color.White, fontSize = 20.sp) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt index 89a976e46a..915df45fa6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt @@ -44,7 +44,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -56,6 +55,7 @@ import com.vitorpamplona.amethyst.commons.hashtags.Lightning import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -78,7 +78,8 @@ fun InvoiceRequestCard( ) { Column( modifier = - Modifier.fillMaxWidth() + Modifier + .fillMaxWidth() .padding(start = 30.dp, end = 30.dp) .clip(shape = QuoteBorder) .border(1.dp, MaterialTheme.colorScheme.subtleBorder, QuoteBorder), @@ -126,7 +127,7 @@ fun InvoiceRequest( ) Text( - text = titleText ?: stringResource(R.string.lightning_tips), + text = titleText ?: stringRes(R.string.lightning_tips), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(start = 10.dp), @@ -139,13 +140,13 @@ fun InvoiceRequest( var amount by remember { mutableStateOf(1000L) } OutlinedTextField( - label = { Text(text = stringResource(R.string.note_to_receiver)) }, + label = { Text(text = stringRes(R.string.note_to_receiver)) }, modifier = Modifier.fillMaxWidth(), value = message, onValueChange = { message = it }, placeholder = { Text( - text = stringResource(R.string.thank_you_so_much), + text = stringRes(R.string.thank_you_so_much), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -157,7 +158,7 @@ fun InvoiceRequest( ) OutlinedTextField( - label = { Text(text = stringResource(R.string.amount_in_sats)) }, + label = { Text(text = stringRes(R.string.amount_in_sats)) }, modifier = Modifier.fillMaxWidth(), value = amount.toString(), onValueChange = { @@ -199,9 +200,7 @@ fun InvoiceRequest( context = context, ) } else { - account.createZapRequestFor(toUserPubKeyHex, message, account.defaultZapType) { - zapRequest, - -> + account.createZapRequestFor(toUserPubKeyHex, message, account.defaultZapType) { zapRequest -> LocalCache.justConsume(zapRequest, null) LightningAddressResolver() .lnAddressInvoice( @@ -225,7 +224,7 @@ fun InvoiceRequest( ), ) { Text( - text = buttonText ?: stringResource(R.string.send_sats), + text = buttonText ?: stringRes(R.string.send_sats), color = Color.White, fontSize = 20.sp, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index bfad6b30b1..a499e4b98b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -29,7 +29,6 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent import androidx.compose.material3.Icon diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt index 6a6d673225..1970fee3c5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RobohashAsyncImage.kt @@ -29,7 +29,6 @@ import androidx.compose.material.icons.filled.Face import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable -import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt index 52b3844c75..db8f877e6d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SelectTextDialog.kt @@ -37,11 +37,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size24dp @@ -74,7 +74,7 @@ fun SelectTextDialog( ) { ArrowBackIcon() } - Text(text = stringResource(R.string.select_text_dialog_top)) + Text(text = stringRes(R.string.select_text_dialog_top)) } HorizontalDivider(thickness = DividerThickness) Column( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt index 5d8dedc8dd..3866f34474 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt @@ -46,7 +46,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -55,6 +54,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.quartz.events.EventInterface @@ -122,13 +122,13 @@ fun ContentWarningNote(onDismiss: () -> Unit) { ) { Icon( imageVector = Icons.Default.Visibility, - contentDescription = stringResource(R.string.content_warning), + contentDescription = stringRes(R.string.content_warning), modifier = Modifier.size(70.dp).align(Alignment.BottomStart), tint = MaterialTheme.colorScheme.onBackground, ) Icon( imageVector = Icons.Rounded.Warning, - contentDescription = stringResource(R.string.content_warning), + contentDescription = stringRes(R.string.content_warning), modifier = Modifier.size(30.dp).align(Alignment.TopEnd), tint = MaterialTheme.colorScheme.onBackground, ) @@ -137,7 +137,7 @@ fun ContentWarningNote(onDismiss: () -> Unit) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Text( - text = stringResource(R.string.content_warning), + text = stringRes(R.string.content_warning), fontWeight = FontWeight.Bold, fontSize = 18.sp, ) @@ -145,7 +145,7 @@ fun ContentWarningNote(onDismiss: () -> Unit) { Row { Text( - text = stringResource(R.string.content_warning_explanation), + text = stringRes(R.string.content_warning_explanation), color = Color.Gray, modifier = Modifier.padding(top = 10.dp), textAlign = TextAlign.Center, @@ -164,7 +164,7 @@ fun ContentWarningNote(onDismiss: () -> Unit) { contentPadding = ButtonPadding, ) { Text( - text = stringResource(R.string.show_anyway), + text = stringRes(R.string.show_anyway), color = Color.White, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt index 781c12ac5d..ab89efc627 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt @@ -36,12 +36,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.previews.UrlInfoItem +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.MaxWidthWithHorzPadding import com.vitorpamplona.amethyst.ui.theme.innerPostModifier @@ -59,7 +59,7 @@ private fun CopyToClipboard( ) { val clipboardManager = LocalClipboardManager.current DropdownMenuItem( - text = { Text(stringResource(R.string.copy_url_to_clipboard)) }, + text = { Text(stringRes(R.string.copy_url_to_clipboard)) }, onClick = { clipboardManager.setText(AnnotatedString(content)) onDismiss() @@ -103,7 +103,7 @@ fun UrlPreviewCard( ) { AsyncImage( model = previewInfo.imageUrlFullPath, - contentDescription = stringResource(R.string.preview_card_image_for, previewInfo.url), + contentDescription = previewInfo.title, contentScale = ContentScale.Crop, modifier = previewCardImageModifier, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 68e4c61cb4..9e0801307e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -81,7 +81,6 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.Lifecycle @@ -108,6 +107,7 @@ import com.vitorpamplona.amethyst.ui.note.LyricsOffIcon import com.vitorpamplona.amethyst.ui.note.MuteIcon import com.vitorpamplona.amethyst.ui.note.MutedIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.PinBottomIconSize import com.vitorpamplona.amethyst.ui.theme.Size110dp import com.vitorpamplona.amethyst.ui.theme.Size165dp @@ -374,13 +374,15 @@ data class MediaItemData( val artworkUri: String? = null, ) -class MediaItemCache() : GenericBaseCache(20) { - override suspend fun compute(key: MediaItemData): MediaItem { - return MediaItem.Builder() +class MediaItemCache : GenericBaseCache(20) { + override suspend fun compute(key: MediaItemData): MediaItem = + MediaItem + .Builder() .setMediaId(key.videoUri) .setUri(key.videoUri) .setMediaMetadata( - MediaMetadata.Builder() + MediaMetadata + .Builder() .setArtist(key.authorName?.ifBlank { null }) .setTitle(key.title?.ifBlank { null } ?: key.videoUri) .setArtworkUri( @@ -394,11 +396,8 @@ class MediaItemCache() : GenericBaseCache(20) { if (e is CancellationException) throw e null }, - ) - .build(), - ) - .build() - } + ).build(), + ).build() } @Composable @@ -619,7 +618,7 @@ var keepPlayingMutex: MediaController? = null val trackingVideos = mutableListOf() @Stable -class VisibilityData() { +class VisibilityData { var distanceToCenter: Float? = null } @@ -645,8 +644,7 @@ fun VideoPlayerActiveMutex( val myModifier = remember(videoUri) { - Modifier.fillMaxWidth().defaultMinSize(minHeight = 70.dp).onVisiblePositionChanges { - distanceToCenter -> + Modifier.fillMaxWidth().defaultMinSize(minHeight = 70.dp).onVisiblePositionChanges { distanceToCenter -> myCache.distanceToCenter = distanceToCenter if (distanceToCenter != null) { @@ -815,8 +813,7 @@ private fun pollCurrentDuration(controller: MediaController) = emit(controller.currentPosition / controller.duration.toFloat()) delay(100) } - } - .conflate() + }.conflate() @Composable fun Waveform( @@ -1000,7 +997,8 @@ private fun MuteButton( ) { Box(modifier = VolumeBottomIconSize) { Box( - Modifier.clip(CircleShape) + Modifier + .clip(CircleShape) .fillMaxSize(0.6f) .align(Alignment.Center) .background(MaterialTheme.colorScheme.background), @@ -1040,7 +1038,8 @@ private fun KeepPlayingButton( ) { Box(modifier = PinBottomIconSize) { Box( - Modifier.clip(CircleShape) + Modifier + .clip(CircleShape) .fillMaxSize(0.6f) .align(Alignment.Center) .background(MaterialTheme.colorScheme.background), @@ -1099,7 +1098,8 @@ fun AnimatedShareButton( fun ShareButton(innerAction: @Composable (MutableState, () -> Unit) -> Unit) { Box(modifier = PinBottomIconSize) { Box( - Modifier.clip(CircleShape) + Modifier + .clip(CircleShape) .fillMaxSize(0.6f) .align(Alignment.Center) .background(MaterialTheme.colorScheme.background), @@ -1116,7 +1116,7 @@ fun ShareButton(innerAction: @Composable (MutableState, () -> Unit) -> Icon( imageVector = Icons.Default.Share, modifier = Size20Modifier, - contentDescription = stringResource(R.string.share_or_save), + contentDescription = stringRes(R.string.share_or_save), ) innerAction(popupExpanded) { popupExpanded.value = false } @@ -1129,7 +1129,8 @@ fun ShareButton(innerAction: @Composable (MutableState, () -> Unit) -> fun SaveButton(onSaveClick: (localContext: Context) -> Unit) { Box(modifier = PinBottomIconSize) { Box( - Modifier.clip(CircleShape) + Modifier + .clip(CircleShape) .fillMaxSize(0.6f) .align(Alignment.Center) .background(MaterialTheme.colorScheme.background), @@ -1160,7 +1161,7 @@ fun SaveButton(onSaveClick: (localContext: Context) -> Unit) { Icon( imageVector = Icons.Default.Download, modifier = Size20Modifier, - contentDescription = stringResource(R.string.save_to_gallery), + contentDescription = stringRes(R.string.save_to_gallery), ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt index b721070230..a8346df302 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZapRaiserRequest.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp @@ -43,6 +42,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.hashtags.Lightning import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -67,7 +67,7 @@ fun ZapRaiserRequest( ) Text( - text = titleText ?: stringResource(R.string.zapraiser), + text = titleText ?: stringRes(R.string.zapraiser), fontSize = 20.sp, fontWeight = FontWeight.W500, modifier = Modifier.padding(start = 10.dp), @@ -77,13 +77,13 @@ fun ZapRaiserRequest( HorizontalDivider(thickness = DividerThickness) Text( - text = stringResource(R.string.zapraiser_explainer), + text = stringRes(R.string.zapraiser_explainer), color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.padding(vertical = 10.dp), ) OutlinedTextField( - label = { Text(text = stringResource(R.string.zapraiser_target_amount_in_sats)) }, + label = { Text(text = stringRes(R.string.zapraiser_target_amount_in_sats)) }, modifier = Modifier.fillMaxWidth(), value = if (newPostViewModel.zapRaiserAmount != null) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt index 3025f957ef..d028c9ce8b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt @@ -31,7 +31,6 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box @@ -67,7 +66,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.res.stringResource import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.core.net.toUri @@ -86,6 +84,7 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.ui.actions.ImageSaver import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size15dp import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -234,7 +233,12 @@ private fun DialogContent( exit = remember { fadeOut() }, ) { Row( - modifier = Modifier.padding(horizontal = Size15dp, vertical = Size10dp).statusBarsPadding().systemBarsPadding().fillMaxWidth(), + modifier = + Modifier + .padding(horizontal = Size15dp, vertical = Size10dp) + .statusBarsPadding() + .systemBarsPadding() + .fillMaxWidth(), horizontalArrangement = spacedBy(Size10dp), verticalAlignment = Alignment.CenterVertically, ) { @@ -245,7 +249,7 @@ private fun DialogContent( ) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.back), + contentDescription = stringRes(R.string.back), ) } @@ -262,7 +266,7 @@ private fun DialogContent( Icon( imageVector = Icons.Default.Share, modifier = Size20Modifier, - contentDescription = stringResource(R.string.quick_action_share), + contentDescription = stringRes(R.string.quick_action_share), ) ShareImageAction(popupExpanded = popupExpanded, myContent, onDismiss = { popupExpanded.value = false }) @@ -294,7 +298,7 @@ private fun DialogContent( Icon( imageVector = Icons.Default.Download, modifier = Size20Modifier, - contentDescription = stringResource(R.string.save_to_gallery), + contentDescription = stringRes(R.string.save_to_gallery), ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 00f0f5651b..74b2295ca7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -28,7 +28,6 @@ import android.view.Window import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio @@ -56,7 +55,6 @@ import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign @@ -64,7 +62,6 @@ import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.window.DialogWindowProvider -import androidx.core.net.toFile import androidx.core.net.toUri import coil.annotation.ExperimentalCoilApi import coil.compose.AsyncImage @@ -89,6 +86,7 @@ import com.vitorpamplona.amethyst.ui.note.DownloadForOfflineIcon import com.vitorpamplona.amethyst.ui.note.HashCheckFailedIcon import com.vitorpamplona.amethyst.ui.note.HashCheckIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Font17SP import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size24dp @@ -99,7 +97,7 @@ import com.vitorpamplona.amethyst.ui.theme.imageModifier import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.encoders.toHexKey import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -109,21 +107,20 @@ import kotlinx.coroutines.withContext @Composable fun ZoomableContentView( content: BaseMediaContent, - images: ImmutableList = remember(content) { listOf(content).toImmutableList() }, + images: ImmutableList = remember(content) { persistentListOf(content) }, roundedCorner: Boolean, isFiniteHeight: Boolean, accountViewModel: AccountViewModel, ) { - // store the dialog open or close state var dialogOpen by remember(content) { mutableStateOf(false) } - val mainImageModifier = Modifier.fillMaxWidth().clickable { dialogOpen = true } - val loadedImageModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier.fillMaxWidth() - when (content) { is MediaUrlImage -> SensitivityWarning(content.contentWarning != null, accountViewModel) { TwoSecondController(content) { controllerVisible -> + val mainImageModifier = Modifier.fillMaxWidth().clickable { dialogOpen = true } + val loadedImageModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier.fillMaxWidth() + UrlImageView(content, mainImageModifier, loadedImageModifier, isFiniteHeight, controllerVisible, accountViewModel = accountViewModel) } } @@ -148,6 +145,9 @@ fun ZoomableContentView( } is MediaLocalImage -> TwoSecondController(content) { controllerVisible -> + val mainImageModifier = Modifier.fillMaxWidth().clickable { dialogOpen = true } + val loadedImageModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier.fillMaxWidth() + LocalImageView(content, mainImageModifier, loadedImageModifier, isFiniteHeight, controllerVisible, accountViewModel = accountViewModel) } is MediaLocalVideo -> @@ -315,15 +315,13 @@ fun UrlImageView( ) } - val contentScale = if (isFiniteHeight) ContentScale.Fit else ContentScale.FillWidth - val ratio = remember(content) { aspectRatio(content.dim) } if (showImage.value) { SubcomposeAsyncImage( model = content.url, contentDescription = content.description, - contentScale = contentScale, + contentScale = if (isFiniteHeight) ContentScale.Fit else ContentScale.FillWidth, modifier = mainImageModifier, ) { when (painter.state) { @@ -635,7 +633,7 @@ fun ShareImageAction( if (videoUri != null && !videoUri.startsWith("file")) { DropdownMenuItem( - text = { Text(stringResource(R.string.copy_url_to_clipboard)) }, + text = { Text(stringRes(R.string.copy_url_to_clipboard)) }, onClick = { clipboardManager.setText(AnnotatedString(videoUri)) onDismiss() @@ -645,7 +643,7 @@ fun ShareImageAction( postNostrUri?.let { DropdownMenuItem( - text = { Text(stringResource(R.string.copy_the_note_id_to_the_clipboard)) }, + text = { Text(stringRes(R.string.copy_the_note_id_to_the_clipboard)) }, onClick = { clipboardManager.setText(AnnotatedString(it)) onDismiss() @@ -677,7 +675,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) { openDialogMsg.value?.let { InformationDialog( - title = localContext.getString(R.string.hash_verification_info_title), + title = stringRes(localContext, R.string.hash_verification_info_title), textContent = it, ) { openDialogMsg.value = null @@ -688,7 +686,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) { IconButton( modifier = hashVerifierMark, onClick = { - openDialogMsg.value = localContext.getString(R.string.hash_verification_passed) + openDialogMsg.value = stringRes(localContext, R.string.hash_verification_passed) }, ) { HashCheckIcon(Size30dp) @@ -697,7 +695,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) { IconButton( modifier = hashVerifierMark, onClick = { - openDialogMsg.value = localContext.getString(R.string.hash_verification_failed) + openDialogMsg.value = stringRes(localContext, R.string.hash_verification_failed) }, ) { HashCheckFailedIcon(Size30dp) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt index c0db96fd8d..a7d4f5566a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt @@ -37,11 +37,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.note.NewItemsBubble import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ChatHeadlineBorders import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer @@ -57,7 +57,7 @@ fun ChannelNamePreview() { channelPicture = { Image( painter = painterResource(R.drawable.github), - contentDescription = stringResource(id = R.string.profile_banner), + contentDescription = stringRes(id = R.string.profile_banner), contentScale = ContentScale.FillWidth, ) }, @@ -90,7 +90,7 @@ fun ChannelNamePreview() { leadingContent = { Image( painter = painterResource(R.drawable.github), - contentDescription = stringResource(id = R.string.profile_banner), + contentDescription = stringRes(id = R.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Size55Modifier, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt index 03c64c9a3a..d9b23f2ae9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt @@ -37,7 +37,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -46,6 +45,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.note.LikeIcon import com.vitorpamplona.amethyst.ui.note.TextCount import com.vitorpamplona.amethyst.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size16Modifier @@ -66,7 +66,7 @@ fun LeftPictureLayoutPreviewCard() { onImage = { Image( painter = painterResource(R.drawable.github), - contentDescription = stringResource(id = R.string.profile_banner), + contentDescription = stringRes(id = R.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Modifier.fillMaxSize().clip(QuoteBorder), ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt index b8d251b462..7df7d06188 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt @@ -55,7 +55,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -74,6 +73,7 @@ import com.vitorpamplona.amethyst.ui.note.toShortenHex import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginOrSignupScreen +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.AccountPictureModifier import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size55dp @@ -101,7 +101,7 @@ fun AccountSwitchBottomSheet( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { - Text(stringResource(R.string.account_switch_select_account), fontWeight = FontWeight.Bold) + Text(stringRes(R.string.account_switch_select_account), fontWeight = FontWeight.Bold) } accounts.forEach { acc -> DisplayAccount(acc, accountViewModel, accountStateViewModel) } Row( @@ -113,7 +113,7 @@ fun AccountSwitchBottomSheet( verticalAlignment = Alignment.CenterVertically, ) { TextButton(onClick = { popupExpanded = true }) { - Text(stringResource(R.string.account_switch_add_account_btn)) + Text(stringRes(R.string.account_switch_add_account_btn)) } } } @@ -128,7 +128,7 @@ fun AccountSwitchBottomSheet( LoginOrSignupScreen(accountStateViewModel, isFirstLogin = false) TopAppBar( title = { - Text(text = stringResource(R.string.account_switch_add_account_dialog_title)) + Text(text = stringRes(R.string.account_switch_add_account_dialog_title)) }, navigationIcon = { IconButton(onClick = { popupExpanded = false }) { ArrowBackIcon() } @@ -222,7 +222,7 @@ private fun ActiveMarker( if (isCurrentUser) { Icon( imageVector = Icons.Default.RadioButtonChecked, - contentDescription = stringResource(R.string.account_switch_active_account), + contentDescription = stringRes(R.string.account_switch_active_account), tint = MaterialTheme.colorScheme.secondary, ) } @@ -239,7 +239,7 @@ private fun AccountPicture( RobohashFallbackAsyncImage( robot = user.pubkeyHex, model = profilePicture, - contentDescription = stringResource(R.string.profile_image), + contentDescription = stringRes(R.string.profile_image), modifier = AccountPictureModifier, loadProfilePicture = loadProfilePicture, loadRobohash = loadRobohash, @@ -277,8 +277,8 @@ private fun LogoutButton( var logoutDialog by remember { mutableStateOf(false) } if (logoutDialog) { AlertDialog( - title = { Text(text = stringResource(R.string.log_out)) }, - text = { Text(text = stringResource(R.string.are_you_sure_you_want_to_log_out)) }, + title = { Text(text = stringRes(R.string.log_out)) }, + text = { Text(text = stringRes(R.string.are_you_sure_you_want_to_log_out)) }, onDismissRequest = { logoutDialog = false }, confirmButton = { TextButton( @@ -287,14 +287,14 @@ private fun LogoutButton( accountStateViewModel.logOff(acc) }, ) { - Text(text = stringResource(R.string.log_out)) + Text(text = stringRes(R.string.log_out)) } }, dismissButton = { TextButton( onClick = { logoutDialog = false }, ) { - Text(text = stringResource(R.string.cancel)) + Text(text = stringRes(R.string.cancel)) } }, ) @@ -305,7 +305,7 @@ private fun LogoutButton( ) { Icon( imageVector = Icons.Default.Logout, - contentDescription = stringResource(R.string.log_out), + contentDescription = stringRes(R.string.log_out), tint = MaterialTheme.colorScheme.onSurface, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt index 4478dd9a66..c67ca00e0a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt @@ -43,10 +43,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavBackStackEntry import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BottomTopHeight import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size0dp @@ -176,7 +176,7 @@ private fun NotifiableIcon( Box(route.notifSize) { Icon( painter = painterResource(id = route.icon), - contentDescription = stringResource(route.contentDescriptor), + contentDescription = stringRes(route.contentDescriptor), modifier = route.iconSize, tint = if (selected) MaterialTheme.colorScheme.primary else Color.Unspecified, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index 48245d22c3..f8faac59ea 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -63,7 +63,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -128,6 +127,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.RoomNameOnlyDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.ShortChannelHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.SpinnerSelectionDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.observeAppDefinition +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BottomTopHeight import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer @@ -149,7 +149,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combineTransform -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest @@ -195,9 +194,9 @@ private fun RenderTopRouteBar( Route.Video.base -> StoriesTopBar(followLists, openDrawer, accountViewModel, nav) Route.Discover.base -> DiscoveryTopBar(followLists, openDrawer, accountViewModel, nav) Route.Notification.base -> NotificationTopBar(followLists, openDrawer, accountViewModel, nav) - Route.Settings.base -> TopBarWithBackButton(stringResource(id = R.string.application_preferences), navPopBack) - Route.Bookmarks.base -> TopBarWithBackButton(stringResource(id = R.string.bookmarks), navPopBack) - Route.Drafts.base -> TopBarWithBackButton(stringResource(id = R.string.drafts), navPopBack) + Route.Settings.base -> TopBarWithBackButton(stringRes(id = R.string.application_preferences), navPopBack) + Route.Bookmarks.base -> TopBarWithBackButton(stringRes(id = R.string.bookmarks), navPopBack) + Route.Drafts.base -> TopBarWithBackButton(stringRes(id = R.string.drafts), navPopBack) else -> { if (id != null) { @@ -226,7 +225,7 @@ private fun ThreadTopBar( navPopBack: () -> Unit, ) { FlexibleTopBarWithBackButton( - title = { Text(stringResource(id = R.string.thread_title)) }, + title = { Text(stringRes(id = R.string.thread_title)) }, popBack = navPopBack, ) } @@ -588,7 +587,7 @@ private fun LoggedInUserPictureDrawer( RobohashFallbackAsyncImage( robot = accountViewModel.userProfile().pubkeyHex, model = profilePicture, - contentDescription = stringResource(id = R.string.your_profile_image), + contentDescription = stringRes(id = R.string.your_profile_image), modifier = HeaderPictureModifier, contentScale = ContentScale.Crop, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, @@ -656,7 +655,7 @@ class ResourceName( ) : Name() { override fun name() = " $resourceId " // Space to make sure it goes first - override fun name(context: Context) = context.getString(resourceId) + override fun name(context: Context) = stringRes(context, resourceId) } class PeopleListName( @@ -797,7 +796,7 @@ fun SimpleTextSpinner( val context = LocalContext.current val selectAnOption = - stringResource( + stringRes( id = R.string.select_an_option, ) @@ -879,7 +878,7 @@ fun RenderOption(option: Name) { modifier = Modifier.fillMaxWidth(), ) { Text( - text = stringResource(id = option.resourceId), + text = stringRes(id = option.resourceId), color = MaterialTheme.colorScheme.onSurface, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 17a6c102be..4202294fc8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.navigation import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable @@ -44,7 +43,6 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.Delete -import androidx.compose.material.icons.filled.Send import androidx.compose.material3.AlertDialog import androidx.compose.material3.DrawerState import androidx.compose.material3.HorizontalDivider @@ -72,7 +70,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight @@ -99,6 +96,7 @@ import com.vitorpamplona.amethyst.ui.qrcode.ShowQRDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Font18SP @@ -214,14 +212,14 @@ fun ProfileContentTemplate( if (profileBanner != null) { AsyncImage( model = profileBanner, - contentDescription = stringResource(id = R.string.profile_image), + contentDescription = stringRes(id = R.string.profile_image), contentScale = ContentScale.FillWidth, modifier = bannerModifier, ) } else { Image( painter = painterResource(R.drawable.profile_banner), - contentDescription = stringResource(R.string.profile_banner), + contentDescription = stringRes(R.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = bannerModifier, ) @@ -231,7 +229,7 @@ fun ProfileContentTemplate( RobohashFallbackAsyncImage( robot = profilePubHex, model = profilePicture, - contentDescription = stringResource(id = R.string.profile_image), + contentDescription = stringRes(id = R.string.profile_image), modifier = Modifier .width(100.dp) @@ -293,11 +291,11 @@ fun StatusEditBar( OutlinedTextField( value = currentStatus.value, onValueChange = { currentStatus.value = it }, - label = { Text(text = stringResource(R.string.status_update)) }, + label = { Text(text = stringRes(R.string.status_update)) }, modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.status_update), + text = stringRes(R.string.status_update), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -399,7 +397,7 @@ private fun FollowingAndFollowerCounts( fontWeight = FontWeight.Bold, ) - Text(stringResource(R.string.following)) + Text(stringRes(R.string.following)) Spacer(modifier = DoubleHorzSpacer) @@ -408,7 +406,7 @@ private fun FollowingAndFollowerCounts( fontWeight = FontWeight.Bold, ) - Text(stringResource(R.string.followers)) + Text(stringRes(R.string.followers)) } } @@ -462,7 +460,7 @@ fun ListContent( Column(modifier) { NavigationRow( - title = stringResource(R.string.profile), + title = stringRes(R.string.profile), icon = Route.Profile.icon, tint = MaterialTheme.colorScheme.primary, nav = nav, @@ -471,7 +469,7 @@ fun ListContent( ) NavigationRow( - title = stringResource(R.string.bookmarks), + title = stringRes(R.string.bookmarks), icon = Route.Bookmarks.icon, tint = MaterialTheme.colorScheme.onBackground, nav = nav, @@ -480,7 +478,7 @@ fun ListContent( ) NavigationRow( - title = stringResource(R.string.drafts), + title = stringRes(R.string.drafts), icon = Route.Drafts.icon, tint = MaterialTheme.colorScheme.onBackground, nav = nav, @@ -497,7 +495,7 @@ fun ListContent( ) NavigationRow( - title = stringResource(R.string.security_filters), + title = stringRes(R.string.security_filters), icon = Route.BlockedUsers.icon, tint = MaterialTheme.colorScheme.onBackground, nav = nav, @@ -507,7 +505,7 @@ fun ListContent( accountViewModel.account.keyPair.privKey?.let { IconRow( - title = stringResource(R.string.backup_keys), + title = stringRes(R.string.backup_keys), icon = R.drawable.ic_key, tint = MaterialTheme.colorScheme.onBackground, onClick = { @@ -520,9 +518,9 @@ fun ListContent( IconRow( title = if (checked) { - stringResource(R.string.disconnect_from_your_orbot_setup) + stringRes(R.string.disconnect_from_your_orbot_setup) } else { - stringResource(R.string.connect_via_tor_short) + stringRes(R.string.connect_via_tor_short) }, icon = R.drawable.ic_tor, tint = MaterialTheme.colorScheme.onBackground, @@ -541,7 +539,7 @@ fun ListContent( ) NavigationRow( - title = stringResource(R.string.settings), + title = stringRes(R.string.settings), icon = Route.Settings.icon, tint = MaterialTheme.colorScheme.onBackground, nav = nav, @@ -552,7 +550,7 @@ fun ListContent( Spacer(modifier = Modifier.weight(1f)) IconRow( - title = stringResource(R.string.drawer_accounts), + title = stringRes(R.string.drawer_accounts), icon = R.drawable.manage_accounts, tint = MaterialTheme.colorScheme.onBackground, onClick = openSheet, @@ -576,7 +574,7 @@ fun ListContent( }, onError = { accountViewModel.toast( - context.getString(R.string.could_not_connect_to_tor), + stringRes(context, R.string.could_not_connect_to_tor), it, ) }, @@ -586,8 +584,8 @@ fun ListContent( if (disconnectTorDialog) { AlertDialog( - title = { Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) }, - text = { Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_text)) }, + title = { Text(text = stringRes(R.string.do_you_really_want_to_disable_tor_title)) }, + text = { Text(text = stringRes(R.string.do_you_really_want_to_disable_tor_text)) }, onDismissRequest = { disconnectTorDialog = false }, confirmButton = { TextButton( @@ -597,14 +595,14 @@ fun ListContent( accountViewModel.enableTor(false, proxyPort) }, ) { - Text(text = stringResource(R.string.yes)) + Text(text = stringRes(R.string.yes)) } }, dismissButton = { TextButton( onClick = { disconnectTorDialog = false }, ) { - Text(text = stringResource(R.string.no)) + Text(text = stringRes(R.string.no)) } }, ) @@ -728,7 +726,7 @@ fun IconRowRelays( Text( modifier = Modifier.padding(start = 16.dp), - text = stringResource(id = R.string.relay_setup), + text = stringRes(id = R.string.relay_setup), fontSize = 18.sp, ) @@ -791,7 +789,7 @@ fun BottomContent( ) { Icon( painter = painterResource(R.drawable.ic_qrcode), - contentDescription = stringResource(id = R.string.show_npub_as_a_qr_code), + contentDescription = stringRes(id = R.string.show_npub_as_a_qr_code), modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index fce43bfe80..6097177a2a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -24,7 +24,6 @@ import android.os.Bundle import androidx.compose.foundation.layout.size import androidx.compose.runtime.Immutable import androidx.compose.runtime.State -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.navigation.NamedNavArgument import androidx.navigation.NavBackStackEntry diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index 05824a15a7..584216f417 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -45,7 +45,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R @@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay import com.vitorpamplona.amethyst.ui.screen.BadgeCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.coroutines.launch @@ -67,7 +67,10 @@ fun BadgeCompose( accountViewModel: AccountViewModel, nav: (String) -> Unit, ) { - val noteState by likeSetCard.note.live().metadata.observeAsState() + val noteState by likeSetCard.note + .live() + .metadata + .observeAsState() val note = noteState?.note val context = LocalContext.current.applicationContext @@ -89,15 +92,15 @@ fun BadgeCompose( Column( modifier = - Modifier.background(backgroundColor.value) + Modifier + .background(backgroundColor.value) .combinedClickable( onClick = { scope.launch { routeFor( note, accountViewModel.userProfile(), - ) - ?.let { nav(it) } + )?.let { nav(it) } } }, onLongClick = enablePopup, @@ -128,7 +131,7 @@ fun BadgeCompose( Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) { Row { Text( - stringResource(R.string.new_badge_award_notif), + stringRes(R.string.new_badge_award_notif), fontWeight = FontWeight.Bold, modifier = Modifier.padding(bottom = 5.dp).weight(1f), ) @@ -145,7 +148,7 @@ fun BadgeCompose( ) { Icon( imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(id = R.string.more_options), + contentDescription = stringRes(id = R.string.more_options), modifier = Size15Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt index ea3716edd0..75af3272ed 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -42,6 +41,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.Size35dp @@ -75,7 +75,7 @@ fun BlankNote( horizontalArrangement = Arrangement.Center, ) { Text( - text = stringResource(R.string.post_not_found) + if (idHex != null) ": $idHex" else "", + text = stringRes(R.string.post_not_found) + if (idHex != null) ": $idHex" else "", modifier = Modifier.padding(30.dp), color = Color.Gray, textAlign = TextAlign.Center, @@ -125,7 +125,7 @@ fun HiddenNote( modifier = Modifier.padding(30.dp), ) { Text( - text = stringResource(R.string.post_was_flagged_as_inappropriate_by), + text = stringRes(R.string.post_was_flagged_as_inappropriate_by), color = Color.Gray, ) FlowRow(modifier = Modifier.padding(top = 10.dp)) { @@ -157,7 +157,7 @@ fun HiddenNote( ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.show_anyway), color = Color.White) + Text(text = stringRes(R.string.show_anyway), color = Color.White) } } } @@ -188,7 +188,7 @@ fun HiddenNoteByMe( modifier = Modifier.padding(30.dp), ) { Text( - text = stringResource(R.string.post_was_hidden), + text = stringRes(R.string.post_was_hidden), color = Color.Gray, textAlign = TextAlign.Center, ) @@ -203,7 +203,7 @@ fun HiddenNoteByMe( ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.show_anyway), color = Color.White) + Text(text = stringRes(R.string.show_anyway), color = Color.White) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt index 4a89b303c8..69343f910e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt @@ -24,7 +24,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.model.Note diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt index 5e736214fa..af245f9ec4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomHeaderCompose.kt @@ -45,7 +45,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight @@ -68,6 +67,7 @@ import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.layouts.ChatHeaderLayout import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.AccountPictureModifier import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.grayText @@ -183,9 +183,9 @@ private fun ChannelRoomCompose( val description = if (noteEvent is ChannelCreateEvent) { - stringResource(R.string.channel_created) + stringRes(R.string.channel_created) } else if (noteEvent is ChannelMetadataEvent) { - "${stringResource(R.string.channel_information_changed_to)} " + "${stringRes(R.string.channel_information_changed_to)} " } else { noteEvent?.content() } @@ -216,7 +216,7 @@ private fun ChannelTitleWithLabelInfo( channelName: String, modifier: Modifier, ) { - val label = stringResource(id = R.string.public_chat) + val label = stringRes(id = R.string.public_chat) val placeHolderColor = MaterialTheme.colorScheme.placeholderText val channelNameAndBoostInfo = remember(channelName) { @@ -465,7 +465,7 @@ fun ChannelName( RobohashFallbackAsyncImage( robot = channelIdHex, model = channelPicture, - contentDescription = stringResource(R.string.channel_image), + contentDescription = stringRes(R.string.channel_image), modifier = AccountPictureModifier, loadProfilePicture = loadProfilePicture, loadRobohash = loadRobohash, @@ -506,7 +506,7 @@ fun ChannelName( ) } else { Text( - stringResource(R.string.referenced_event_not_found), + stringRes(R.string.referenced_event_not_found), color = MaterialTheme.colorScheme.grayText, maxLines = 1, overflow = TextOverflow.Ellipsis, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index d508327e8d..fc41eb0222 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -46,7 +46,6 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -54,7 +53,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.R @@ -65,6 +63,7 @@ import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ChatBubbleMaxSizeModifier import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeMe import com.vitorpamplona.amethyst.ui.theme.ChatBubbleShapeThem @@ -623,10 +622,8 @@ fun IncognitoBadge(baseNote: Note) { @Composable fun ChatTimeAgo(baseNote: Note) { - val nowStr = stringResource(id = R.string.now) - - val time by - remember(baseNote) { derivedStateOf { timeAgoShort(baseNote.createdAt() ?: 0, nowStr) } } + val nowStr = stringRes(id = R.string.now) + val time = remember(baseNote) { timeAgoShort(baseNote.createdAt() ?: 0, nowStr) } Text( text = time, @@ -668,7 +665,7 @@ private fun RenderRegularTextNote( } } else { TranslatableRichTextViewer( - content = stringResource(id = R.string.could_not_decrypt_the_message), + content = stringRes(id = R.string.could_not_decrypt_the_message), canPreview = true, quotesLeft = 0, modifier = HalfTopPadding, @@ -690,11 +687,11 @@ private fun RenderChangeChannelMetadataNote(note: Note) { val channelInfo = noteEvent.channelInfo() val text = note.author?.toBestDisplayName().toString() + - " ${stringResource(R.string.changed_chat_name_to)} '" + + " ${stringRes(R.string.changed_chat_name_to)} '" + (channelInfo.name ?: "") + - "', ${stringResource(R.string.description_to)} '" + + "', ${stringRes(R.string.description_to)} '" + (channelInfo.about ?: "") + - "', ${stringResource(R.string.and_picture_to)} '" + + "', ${stringRes(R.string.and_picture_to)} '" + (channelInfo.picture ?: "") + "'" @@ -711,11 +708,11 @@ private fun RenderCreateChannelNote(note: Note) { val text = note.author?.toBestDisplayName().toString() + - " ${stringResource(R.string.created)} " + + " ${stringRes(R.string.created)} " + (channelInfo.name ?: "") + - " ${stringResource(R.string.with_description_of)} '" + + " ${stringRes(R.string.with_description_of)} '" + (channelInfo.about ?: "") + - "', ${stringResource(R.string.and_picture)} '" + + "', ${stringRes(R.string.and_picture)} '" + (channelInfo.picture ?: "") + "'" diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index f35750f112..a980f0e33f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -29,7 +29,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.OpenInNew -import androidx.compose.material.icons.automirrored.filled.Reply import androidx.compose.material.icons.automirrored.filled.VolumeOff import androidx.compose.material.icons.automirrored.filled.VolumeUp import androidx.compose.material.icons.filled.Bolt @@ -56,7 +55,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -73,6 +71,7 @@ import com.vitorpamplona.amethyst.commons.icons.Reposted import com.vitorpamplona.amethyst.commons.icons.Search import com.vitorpamplona.amethyst.commons.icons.Zap import com.vitorpamplona.amethyst.commons.icons.ZapSplit +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -85,7 +84,7 @@ import com.vitorpamplona.amethyst.ui.theme.subtleButton fun AmethystIcon(iconSize: Dp) { Icon( imageVector = CustomHashTagIcons.Amethyst, - contentDescription = stringResource(id = R.string.app_logo), + contentDescription = stringRes(id = R.string.app_logo), modifier = Modifier.size(iconSize), tint = Color.Unspecified, ) @@ -100,7 +99,7 @@ fun FollowingIcon(iconSize: Dp) { fun FollowingIcon(modifier: Modifier) { Icon( imageVector = Following, - contentDescription = stringResource(id = R.string.following), + contentDescription = stringRes(id = R.string.following), modifier = modifier, tint = Color.Unspecified, ) @@ -110,7 +109,7 @@ fun FollowingIcon(modifier: Modifier) { fun ArrowBackIcon() { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.back), + contentDescription = stringRes(R.string.back), tint = MaterialTheme.colorScheme.grayText, ) } @@ -132,7 +131,7 @@ fun DownloadForOfflineIcon( ) { Icon( imageVector = Icons.Default.DownloadForOffline, - contentDescription = stringResource(id = R.string.accessibility_download_for_offline), + contentDescription = stringRes(id = R.string.accessibility_download_for_offline), modifier = remember(iconSize) { Modifier.size(iconSize) }, tint = tint, ) @@ -142,7 +141,7 @@ fun DownloadForOfflineIcon( fun HashCheckIcon(iconSize: Dp) { Icon( painter = painterResource(R.drawable.original), - contentDescription = stringResource(id = R.string.hash_verification_passed), + contentDescription = stringRes(id = R.string.hash_verification_passed), modifier = remember(iconSize) { Modifier.size(iconSize) }, tint = Color.Unspecified, ) @@ -152,7 +151,7 @@ fun HashCheckIcon(iconSize: Dp) { fun HashCheckFailedIcon(iconSize: Dp) { Icon( imageVector = Icons.Default.Report, - contentDescription = stringResource(id = R.string.hash_verification_failed), + contentDescription = stringRes(id = R.string.hash_verification_failed), modifier = remember(iconSize) { Modifier.size(iconSize) }, tint = Color.Red, ) @@ -165,7 +164,7 @@ fun LikedIcon( ) { Icon( imageVector = Liked, - stringResource(id = R.string.like_description), + stringRes(id = R.string.like_description), modifier = modifier, tint = tint, ) @@ -178,7 +177,7 @@ fun LikeIcon( ) { Icon( imageVector = Like, - contentDescription = stringResource(id = R.string.like_description), + contentDescription = stringRes(id = R.string.like_description), modifier = iconSizeModifier, tint = grayTint, ) @@ -191,7 +190,7 @@ fun RepostIcon( ) { Icon( imageVector = Repost, - contentDescription = stringResource(id = R.string.boost_or_quote_description), + contentDescription = stringRes(id = R.string.boost_or_quote_description), modifier = modifier, tint = tint, ) @@ -204,7 +203,7 @@ fun RepostedIcon( ) { Icon( imageVector = Reposted, - contentDescription = stringResource(id = R.string.boost_or_quote_description), + contentDescription = stringRes(id = R.string.boost_or_quote_description), modifier = modifier, tint = tint, ) @@ -217,7 +216,7 @@ fun LightningAddressIcon( ) { Icon( imageVector = Icons.Default.Bolt, - contentDescription = stringResource(R.string.lightning_address), + contentDescription = stringRes(R.string.lightning_address), tint = tint, modifier = modifier, ) @@ -255,7 +254,7 @@ fun ZapIcon( ) { Icon( imageVector = Icons.Default.Bolt, - contentDescription = stringResource(contentDescriptor), + contentDescription = stringRes(contentDescriptor), tint = tint, modifier = modifier, ) @@ -269,7 +268,7 @@ fun OutlinedZapIcon( ) { Icon( imageVector = Zap, - contentDescription = stringResource(contentDescriptor), + contentDescription = stringRes(contentDescriptor), tint = tint, modifier = modifier, ) @@ -283,7 +282,7 @@ fun ShareIcon( Icon( imageVector = Icons.Default.Share, modifier = modifier, - contentDescription = stringResource(R.string.share_or_save), + contentDescription = stringRes(R.string.share_or_save), tint = tint, ) } @@ -292,7 +291,7 @@ fun ShareIcon( fun CashuIcon(modifier: Modifier) { Icon( imageVector = CustomHashTagIcons.Cashu, - "Cashu", + stringRes(R.string.cashu), tint = Color.Unspecified, modifier = modifier, ) @@ -305,7 +304,7 @@ fun CopyIcon( ) { Icon( imageVector = Icons.Default.ContentCopy, - stringResource(id = R.string.copy_to_clipboard), + stringRes(id = R.string.copy_to_clipboard), tint = tint, modifier = modifier, ) @@ -318,7 +317,7 @@ fun OpenInNewIcon( ) { Icon( imageVector = Icons.AutoMirrored.Filled.OpenInNew, - stringResource(id = R.string.copy_to_clipboard), + stringRes(id = R.string.copy_to_clipboard), tint = tint, modifier = modifier, ) @@ -331,7 +330,7 @@ fun ExpandLessIcon( ) { Icon( imageVector = Icons.Default.ExpandLess, - contentDescription = stringResource(id = contentDescriptor), + contentDescription = stringRes(id = contentDescriptor), modifier = modifier, tint = MaterialTheme.colorScheme.subtleButton, ) @@ -344,7 +343,7 @@ fun ExpandMoreIcon( ) { Icon( imageVector = Icons.Default.ExpandMore, - contentDescription = stringResource(id = contentDescriptor), + contentDescription = stringRes(id = contentDescriptor), modifier = modifier, tint = MaterialTheme.colorScheme.subtleButton, ) @@ -357,7 +356,7 @@ fun CommentIcon( ) { Icon( imageVector = Reply, - contentDescription = stringResource(id = R.string.reply_description), + contentDescription = stringRes(id = R.string.reply_description), modifier = iconSizeModifier, tint = tint, ) @@ -367,7 +366,7 @@ fun CommentIcon( fun PollIcon() { Icon( painter = painterResource(R.drawable.ic_poll), - contentDescription = stringResource(id = R.string.poll), + contentDescription = stringRes(id = R.string.poll), modifier = Size20Modifier, tint = MaterialTheme.colorScheme.onBackground, ) @@ -377,7 +376,7 @@ fun PollIcon() { fun RegularPostIcon() { Icon( painter = painterResource(R.drawable.ic_lists), - contentDescription = stringResource(id = R.string.disable_poll), + contentDescription = stringRes(id = R.string.disable_poll), modifier = Size20Modifier, tint = MaterialTheme.colorScheme.onBackground, ) @@ -387,7 +386,7 @@ fun RegularPostIcon() { fun CancelIcon() { Icon( imageVector = Icons.Default.Cancel, - contentDescription = stringResource(id = R.string.cancel), + contentDescription = stringRes(id = R.string.cancel), modifier = Size30Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) @@ -397,7 +396,7 @@ fun CancelIcon() { fun CloseIcon() { Icon( painter = painterResource(id = R.drawable.ic_close), - contentDescription = stringResource(id = R.string.cancel), + contentDescription = stringRes(id = R.string.cancel), modifier = Size20Modifier, ) } @@ -406,7 +405,7 @@ fun CloseIcon() { fun MutedIcon() { Icon( imageVector = Icons.AutoMirrored.Filled.VolumeOff, - contentDescription = stringResource(id = R.string.muted_button), + contentDescription = stringRes(id = R.string.muted_button), tint = MaterialTheme.colorScheme.onBackground, modifier = Size30Modifier, ) @@ -416,7 +415,7 @@ fun MutedIcon() { fun MuteIcon() { Icon( imageVector = Icons.AutoMirrored.Filled.VolumeUp, - contentDescription = stringResource(id = R.string.mute_button), + contentDescription = stringRes(id = R.string.mute_button), tint = MaterialTheme.colorScheme.onBackground, modifier = Size30Modifier, ) @@ -429,7 +428,7 @@ fun SearchIcon( ) { Icon( imageVector = Search, - contentDescription = stringResource(id = R.string.search_button), + contentDescription = stringRes(id = R.string.search_button), modifier = modifier, tint = tint, ) @@ -442,7 +441,7 @@ fun PlayIcon( ) { Icon( imageVector = Icons.Outlined.PlayCircle, - contentDescription = stringResource(id = R.string.accessibility_play_username), + contentDescription = stringRes(id = R.string.accessibility_play_username), modifier = modifier, tint = tint, ) @@ -468,7 +467,7 @@ fun LyricsIcon( ) { Icon( painter = painterResource(id = R.drawable.lyrics_on), - contentDescription = stringResource(id = R.string.accessibility_lyrics_on), + contentDescription = stringRes(id = R.string.accessibility_lyrics_on), modifier = modifier, tint = tint, ) @@ -481,7 +480,7 @@ fun LyricsOffIcon( ) { Icon( painter = painterResource(id = R.drawable.lyrics_off), - contentDescription = stringResource(id = R.string.accessibility_lyrics_off), + contentDescription = stringRes(id = R.string.accessibility_lyrics_off), modifier = modifier, tint = tint, ) @@ -491,7 +490,7 @@ fun LyricsOffIcon( fun ClearTextIcon() { Icon( imageVector = Icons.Default.Clear, - contentDescription = stringResource(R.string.clear), + contentDescription = stringRes(R.string.clear), ) } @@ -502,7 +501,7 @@ fun LinkIcon( ) { Icon( imageVector = Icons.Default.Link, - contentDescription = stringResource(R.string.website), + contentDescription = stringRes(R.string.website), modifier = modifier, tint = tint, ) @@ -512,7 +511,7 @@ fun LinkIcon( fun VerticalDotsIcon(contentDescriptor: Int? = null) { Icon( imageVector = Icons.Default.MoreVert, - contentDescription = contentDescriptor?.let { stringResource(id = it) }, + contentDescription = contentDescriptor?.let { stringRes(id = it) }, modifier = Size18Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) @@ -522,7 +521,7 @@ fun VerticalDotsIcon(contentDescriptor: Int? = null) { fun NIP05CheckingIcon(modifier: Modifier) { Icon( imageVector = Icons.Default.Downloading, - contentDescription = stringResource(id = R.string.nip05_checking), + contentDescription = stringRes(id = R.string.nip05_checking), modifier = modifier, tint = Color.Yellow, ) @@ -532,7 +531,7 @@ fun NIP05CheckingIcon(modifier: Modifier) { fun NIP05VerifiedIcon(modifier: Modifier) { Icon( painter = painterResource(R.drawable.nip_05), - contentDescription = stringResource(id = R.string.nip05_verified), + contentDescription = stringRes(id = R.string.nip05_verified), modifier = modifier, tint = Color.Unspecified, ) @@ -542,7 +541,7 @@ fun NIP05VerifiedIcon(modifier: Modifier) { fun NIP05FailedVerification(modifier: Modifier) { Icon( imageVector = Icons.Default.Report, - contentDescription = stringResource(id = R.string.nip05_failed), + contentDescription = stringRes(id = R.string.nip05_failed), modifier = modifier, tint = Color.Red, ) @@ -555,7 +554,7 @@ fun IncognitoIconOn( ) { Icon( painter = painterResource(id = R.drawable.incognito), - contentDescription = stringResource(id = R.string.accessibility_turn_off_sealed_message), + contentDescription = stringRes(id = R.string.accessibility_turn_off_sealed_message), modifier = modifier, tint = tint, ) @@ -568,7 +567,7 @@ fun IncognitoIconOff( ) { Icon( painter = painterResource(id = R.drawable.incognito_off), - contentDescription = stringResource(id = R.string.accessibility_turn_on_sealed_message), + contentDescription = stringRes(id = R.string.accessibility_turn_on_sealed_message), modifier = modifier, tint = tint, ) @@ -581,7 +580,7 @@ fun ZapSplitIcon( ) { Icon( imageVector = ZapSplit, - contentDescription = stringResource(id = R.string.zap_split_title), + contentDescription = stringRes(id = R.string.zap_split_title), modifier = modifier, tint = tint, ) @@ -598,7 +597,7 @@ fun ZapSplitPreview() { ) { Icon( imageVector = Icons.Outlined.Bolt, - contentDescription = stringResource(id = R.string.zaps), + contentDescription = stringRes(id = R.string.zaps), modifier = Modifier .size(20.dp) @@ -607,7 +606,7 @@ fun ZapSplitPreview() { ) Icon( imageVector = Icons.Outlined.ArrowForwardIos, - contentDescription = stringResource(id = R.string.zaps), + contentDescription = stringRes(id = R.string.zaps), modifier = Modifier .size(13.dp) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index 958c5e525f..e6b52a50db 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -53,7 +53,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -72,6 +71,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.screen.CombinedZap import com.vitorpamplona.amethyst.ui.screen.MultiSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifier import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifierSmaller @@ -524,7 +524,7 @@ fun WatchUserMetadataAndFollowsAndRenderUserProfilePicture( RobohashFallbackAsyncImage( robot = author.pubkeyHex, model = baseUserPicture, - contentDescription = stringResource(id = R.string.profile_image), + contentDescription = stringRes(id = R.string.profile_image), modifier = MaterialTheme.colorScheme.profile35dpModifier, contentScale = ContentScale.Crop, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 6a483e2e74..d6d7cd777a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.compositeOver -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.distinctUntilChanged @@ -113,6 +112,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderWikiContent import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.RenderChannelHeader +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.Font12SP import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer @@ -1120,7 +1120,7 @@ private fun ChannelNotePicture( RobohashFallbackAsyncImage( robot = baseChannel.idHex, model = model, - contentDescription = stringResource(R.string.group_picture), + contentDescription = stringRes(R.string.group_picture), modifier = MaterialTheme.colorScheme.channelNotePictureModifier, loadProfilePicture = loadProfilePicture, loadRobohash = loadRobohash, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt index 94b058d579..159961c921 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt @@ -73,7 +73,6 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign @@ -89,6 +88,7 @@ import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.components.SelectTextDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.WarningColor import com.vitorpamplona.amethyst.ui.theme.isLight import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground @@ -260,12 +260,12 @@ private fun RenderMainPopup( MaterialTheme.colorScheme.secondaryButtonBackground } - val showToast = { stringResource: Int -> + val showToast = { stringRes: Int -> scope.launch { Toast .makeText( context, - context.getString(stringResource), + stringRes(context, stringRes), Toast.LENGTH_SHORT, ).show() } @@ -284,7 +284,7 @@ private fun RenderMainPopup( Row(modifier = Modifier.height(IntrinsicSize.Min)) { NoteQuickActionItem( icon = Icons.Default.ContentCopy, - label = stringResource(R.string.quick_action_copy_text), + label = stringRes(R.string.quick_action_copy_text), ) { accountViewModel.decrypt(note) { clipboardManager.setText(AnnotatedString(it)) @@ -296,7 +296,7 @@ private fun RenderMainPopup( VerticalDivider(color = primaryLight) NoteQuickActionItem( Icons.Default.AlternateEmail, - stringResource(R.string.quick_action_copy_user_id), + stringRes(R.string.quick_action_copy_user_id), ) { scope.launch(Dispatchers.IO) { clipboardManager.setText(AnnotatedString("nostr:${note.author?.pubkeyNpub()}")) @@ -307,7 +307,7 @@ private fun RenderMainPopup( VerticalDivider(color = primaryLight) NoteQuickActionItem( Icons.Default.FormatQuote, - stringResource(R.string.quick_action_copy_note_id), + stringRes(R.string.quick_action_copy_note_id), ) { scope.launch(Dispatchers.IO) { clipboardManager.setText(AnnotatedString("nostr:${note.toNEvent()}")) @@ -321,7 +321,7 @@ private fun RenderMainPopup( NoteQuickActionItem( Icons.Default.Block, - stringResource(R.string.quick_action_block), + stringRes(R.string.quick_action_block), ) { if (accountViewModel.hideBlockAlertDialog) { note.author?.let { accountViewModel.hide(it) } @@ -339,7 +339,7 @@ private fun RenderMainPopup( if (isOwnNote) { NoteQuickActionItem( Icons.Default.Delete, - stringResource(R.string.quick_action_delete), + stringRes(R.string.quick_action_delete), ) { if (accountViewModel.hideDeleteRequestDialog) { accountViewModel.delete(note) @@ -351,7 +351,7 @@ private fun RenderMainPopup( } else if (isFollowingUser) { NoteQuickActionItem( Icons.Default.PersonRemove, - stringResource(R.string.quick_action_unfollow), + stringRes(R.string.quick_action_unfollow), ) { accountViewModel.unfollow(note.author!!) onDismiss() @@ -359,7 +359,7 @@ private fun RenderMainPopup( } else { NoteQuickActionItem( Icons.Default.PersonAdd, - stringResource(R.string.quick_action_follow), + stringRes(R.string.quick_action_follow), ) { accountViewModel.follow(note.author!!) onDismiss() @@ -369,7 +369,7 @@ private fun RenderMainPopup( VerticalDivider(color = primaryLight) NoteQuickActionItem( icon = ImageVector.vectorResource(id = R.drawable.relays), - label = stringResource(R.string.broadcast), + label = stringRes(R.string.broadcast), ) { accountViewModel.broadcast(note) // showSelectTextDialog = true @@ -379,7 +379,7 @@ private fun RenderMainPopup( if (isOwnNote && note.isDraft()) { NoteQuickActionItem( Icons.Default.Edit, - stringResource(R.string.edit_draft), + stringRes(R.string.edit_draft), ) { onDismiss() onWantsToEditDraft() @@ -387,7 +387,7 @@ private fun RenderMainPopup( } else { NoteQuickActionItem( icon = Icons.Default.Share, - label = stringResource(R.string.quick_action_share), + label = stringRes(R.string.quick_action_share), ) { val sendIntent = Intent().apply { @@ -399,14 +399,14 @@ private fun RenderMainPopup( ) putExtra( Intent.EXTRA_TITLE, - context.getString(R.string.quick_action_share_browser_link), + stringRes(context, R.string.quick_action_share_browser_link), ) } val shareIntent = Intent.createChooser( sendIntent, - context.getString(R.string.quick_action_share), + stringRes(context, R.string.quick_action_share), ) ContextCompat.startActivity(context, shareIntent, null) onDismiss() @@ -418,7 +418,7 @@ private fun RenderMainPopup( NoteQuickActionItem( Icons.Default.Report, - stringResource(R.string.quick_action_report), + stringRes(R.string.quick_action_report), ) { showReportDialog.value = true } @@ -463,10 +463,10 @@ fun DeleteAlertDialog( onDismiss: () -> Unit, ) { QuickActionAlertDialog( - title = stringResource(R.string.quick_action_request_deletion_alert_title), - textContent = stringResource(R.string.quick_action_request_deletion_alert_body), + title = stringRes(R.string.quick_action_request_deletion_alert_title), + textContent = stringRes(R.string.quick_action_request_deletion_alert_body), buttonIcon = Icons.Default.Delete, - buttonText = stringResource(R.string.quick_action_delete_dialog_btn), + buttonText = stringRes(R.string.quick_action_delete_dialog_btn), onClickDoOnce = { accountViewModel.delete(note) onDismiss() @@ -486,10 +486,10 @@ private fun BlockAlertDialog( accountViewModel: AccountViewModel, onDismiss: () -> Unit, ) = QuickActionAlertDialog( - title = stringResource(R.string.report_dialog_block_hide_user_btn), - textContent = stringResource(R.string.report_dialog_blocking_a_user), + title = stringRes(R.string.report_dialog_block_hide_user_btn), + textContent = stringRes(R.string.report_dialog_blocking_a_user), buttonIcon = Icons.Default.Block, - buttonText = stringResource(R.string.quick_action_block_dialog_btn), + buttonText = stringRes(R.string.quick_action_block_dialog_btn), buttonColors = ButtonDefaults.buttonColors( containerColor = WarningColor, @@ -587,7 +587,7 @@ fun QuickActionAlertDialog( horizontalArrangement = Arrangement.SpaceBetween, ) { TextButton(onClick = onClickDontShowAgain) { - Text(stringResource(R.string.quick_action_dont_show_again_button)) + Text(stringRes(R.string.quick_action_dont_show_again_button)) } Button( onClick = onClickDoOnce, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index d973d91855..b4e689a521 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -61,7 +61,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -76,6 +75,7 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.navigation.routeToMessage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.StringToastMsg +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BigPadding import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.ButtonBorder @@ -437,7 +437,7 @@ fun ZapVote( zappingProgress = 0f showErrorMessageDialog = StringToastMsg( - context.getString(R.string.error_dialog_zap_error), + stringRes(context, R.string.error_dialog_zap_error), it, ) } @@ -446,7 +446,7 @@ fun ZapVote( scope.launch { showErrorMessageDialog = StringToastMsg( - context.getString(R.string.error_dialog_zap_error), + stringRes(context, R.string.error_dialog_zap_error), it, ) } @@ -471,7 +471,7 @@ fun ZapVote( zappingProgress = 1f Icon( imageVector = Icons.Default.Bolt, - contentDescription = stringResource(R.string.zaps), + contentDescription = stringRes(R.string.zaps), modifier = Modifier.size(20.dp), tint = BitcoinOrange, ) @@ -479,7 +479,7 @@ fun ZapVote( if (zappingProgress < 0.1 || zappingProgress > 0.99) { Icon( imageVector = Icons.Outlined.Bolt, - contentDescription = stringResource(id = R.string.zaps), + contentDescription = stringRes(id = R.string.zaps), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.placeholderText, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 7ba6115247..ea0f3dd537 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -77,7 +77,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.style.TextAlign @@ -103,6 +102,7 @@ import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer import com.vitorpamplona.amethyst.ui.navigation.routeToMessage import com.vitorpamplona.amethyst.ui.note.types.EditState import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DarkerGreen import com.vitorpamplona.amethyst.ui.theme.Font14SP @@ -228,14 +228,14 @@ fun ShareReaction( ) putExtra( Intent.EXTRA_TITLE, - context.getString(R.string.quick_action_share_browser_link), + stringRes(context, R.string.quick_action_share_browser_link), ) } val shareIntent = Intent.createChooser( sendIntent, - context.getString(R.string.quick_action_share), + stringRes(context, R.string.quick_action_share), ) ContextCompat.startActivity(context, shareIntent, null) }, @@ -355,7 +355,7 @@ fun RenderZapRaiser( Text( text = - stringResource(id = R.string.sats_to_complete, totalPercentage, zapraiserStatus.left), + stringRes(id = R.string.sats_to_complete, totalPercentage, zapraiserStatus.left), modifier = NoSoTinyBorders, color = MaterialTheme.colorScheme.placeholderText, fontSize = Font14SP, @@ -1050,7 +1050,7 @@ fun ZapReaction( if (showErrorMessageDialog.isNotEmpty()) { val msg = showErrorMessageDialog.joinToString("\n") ErrorMessageDialog( - title = stringResource(id = R.string.error_dialog_zap_error), + title = stringRes(id = R.string.error_dialog_zap_error), textContent = msg, onClickStartMessage = { baseNote.author?.let { @@ -1160,13 +1160,13 @@ fun zapClick( if (accountViewModel.account.zapAmountChoices.isEmpty()) { accountViewModel.toast( - context.getString(R.string.error_dialog_zap_error), - context.getString(R.string.no_zap_amount_setup_long_press_to_change), + R.string.error_dialog_zap_error, + R.string.no_zap_amount_setup_long_press_to_change, ) } else if (!accountViewModel.isWriteable()) { accountViewModel.toast( - context.getString(R.string.error_dialog_zap_error), - context.getString(R.string.login_with_a_private_key_to_be_able_to_send_zaps), + R.string.error_dialog_zap_error, + R.string.login_with_a_private_key_to_be_able_to_send_zaps, ) } else if (accountViewModel.account.zapAmountChoices.size == 1) { accountViewModel.zap( @@ -1272,7 +1272,7 @@ private fun BoostTypeChoicePopup( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(stringResource(R.string.boost), color = Color.White, textAlign = TextAlign.Center) + Text(stringRes(R.string.boost), color = Color.White, textAlign = TextAlign.Center) } Button( @@ -1284,7 +1284,7 @@ private fun BoostTypeChoicePopup( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(stringResource(R.string.quote), color = Color.White, textAlign = TextAlign.Center) + Text(stringRes(R.string.quote), color = Color.White, textAlign = TextAlign.Center) } Button( @@ -1296,7 +1296,7 @@ private fun BoostTypeChoicePopup( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(stringResource(R.string.fork), color = Color.White, textAlign = TextAlign.Center) + Text(stringRes(R.string.fork), color = Color.White, textAlign = TextAlign.Center) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt index 15a8503a4f..8756f7ad10 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt @@ -38,13 +38,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.RelayInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.StdPadding @@ -90,7 +90,7 @@ fun RelayCompose( } Text( - "${relay.counter} ${stringResource(R.string.posts_received)}", + "${relay.counter} ${stringRes(R.string.posts_received)}", color = MaterialTheme.colorScheme.placeholderText, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -114,7 +114,8 @@ private fun RelayOptions( val isNotUsingRelay = remember(userState) { - accountViewModel.account.connectToRelays.value.none { it.url == relay.url } + accountViewModel.account.connectToRelays.value + .none { it.url == relay.url } } if (isNotUsingRelay) { @@ -136,7 +137,7 @@ fun AddRelayButton(onClick: () -> Unit) { ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(id = R.string.add), color = Color.White) + Text(text = stringRes(id = R.string.add), color = Color.White) } } @@ -152,12 +153,12 @@ fun RemoveRelayButton(onClick: () -> Unit) { ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.remove), color = Color.White) + Text(text = stringRes(R.string.remove), color = Color.White) } } -fun formattedDateTime(timestamp: Long): String { - return Instant.ofEpochSecond(timestamp) +fun formattedDateTime(timestamp: Long): String = + Instant + .ofEpochSecond(timestamp) .atZone(ZoneId.systemDefault()) .format(DateTimeFormatter.ofPattern("MMM d, uuuu hh:mm a")) -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt index 7f182de168..5cd95e3a55 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ShowMoreRelaysButtonBoxModifer import com.vitorpamplona.amethyst.ui.theme.Size17Modifier import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -239,7 +239,7 @@ private fun ShowMoreRelaysButton(onClick: () -> Unit) { ) { Icon( imageVector = Icons.Default.ExpandMore, - contentDescription = stringResource(id = R.string.expand_relay_list), + contentDescription = stringRes(id = R.string.expand_relay_list), tint = MaterialTheme.colorScheme.placeholderText, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt index 9050224366..39a5b3dd6a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt @@ -36,7 +36,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.FeatureSetType @@ -48,6 +47,7 @@ import com.vitorpamplona.amethyst.ui.actions.relays.RelayInformationDialog import com.vitorpamplona.amethyst.ui.components.ClickableBox import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.Size17dp @@ -94,7 +94,7 @@ fun ChatRelayExpandButton(onClick: () -> Unit) { ) { Icon( imageVector = Icons.Default.ChevronRight, - contentDescription = stringResource(id = R.string.expand_relay_list), + contentDescription = stringRes(id = R.string.expand_relay_list), modifier = Size15Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) @@ -195,7 +195,7 @@ fun RenderRelayIcon( RobohashFallbackAsyncImage( robot = displayUrl, model = iconUrl, - contentDescription = stringResource(id = R.string.relay_info, displayUrl), + contentDescription = stringRes(id = R.string.relay_info, displayUrl), colorFilter = RelayIconFilter, modifier = iconModifier, loadProfilePicture = loadProfilePicture, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt index fce63082d1..f57ce96ada 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt @@ -33,13 +33,13 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -85,7 +85,7 @@ fun ReplyInformationChannel( if (mentions != null && mentions.isNotEmpty()) { if (replyTo != null && replyTo.isNotEmpty()) { Text( - stringResource(id = R.string.replying_to), + stringRes(id = R.string.replying_to), fontSize = 13.sp, color = MaterialTheme.colorScheme.placeholderText, ) @@ -101,7 +101,7 @@ fun ReplyInformationChannel( ) } else if (idx < mentions.size - 1) { Text( - " ${stringResource(id = R.string.and)} ", + " ${stringRes(id = R.string.and)} ", fontSize = 13.sp, color = MaterialTheme.colorScheme.placeholderText, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt index d2040b21a1..4cc691cfe1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.note import android.content.Context import android.text.format.DateUtils import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.utils.TimeUtils import java.text.SimpleDateFormat import java.util.Locale @@ -36,7 +37,7 @@ fun timeAgo( context: Context, ): String { if (time == null) return " " - if (time == 0L) return " • ${context.getString(R.string.never)}" + if (time == 0L) return " • ${stringRes(context, R.string.never)}" val timeDifference = TimeUtils.now() - time @@ -61,13 +62,13 @@ fun timeAgo( monthFormatter.format(time * 1000) } else if (timeDifference > TimeUtils.ONE_DAY) { // 2 days - " • " + (timeDifference / TimeUtils.ONE_DAY).toString() + context.getString(R.string.d) + " • " + (timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, R.string.d) } else if (timeDifference > TimeUtils.ONE_HOUR) { - " • " + (timeDifference / TimeUtils.ONE_HOUR).toString() + context.getString(R.string.h) + " • " + (timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, R.string.h) } else if (timeDifference > TimeUtils.ONE_MINUTE) { - " • " + (timeDifference / TimeUtils.ONE_MINUTE).toString() + context.getString(R.string.m) + " • " + (timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, R.string.m) } else { - " • " + context.getString(R.string.now) + " • " + stringRes(context, R.string.now) } } @@ -76,7 +77,7 @@ fun timeAgoNoDot( context: Context, ): String { if (time == null) return " " - if (time == 0L) return " ${context.getString(R.string.never)}" + if (time == 0L) return " ${stringRes(context, R.string.never)}" val timeDifference = TimeUtils.now() - time @@ -101,13 +102,13 @@ fun timeAgoNoDot( monthFormatter.format(time * 1000) } else if (timeDifference > TimeUtils.ONE_DAY) { // 2 days - (timeDifference / TimeUtils.ONE_DAY).toString() + context.getString(R.string.d) + (timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, R.string.d) } else if (timeDifference > TimeUtils.ONE_HOUR) { - (timeDifference / TimeUtils.ONE_HOUR).toString() + context.getString(R.string.h) + (timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, R.string.h) } else if (timeDifference > TimeUtils.ONE_MINUTE) { - (timeDifference / TimeUtils.ONE_MINUTE).toString() + context.getString(R.string.m) + (timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, R.string.m) } else { - context.getString(R.string.now) + stringRes(context, R.string.now) } } @@ -118,13 +119,13 @@ fun timeAgoShort( if (mills == null) return " " var humanReadable = - DateUtils.getRelativeTimeSpanString( - mills * 1000, - System.currentTimeMillis(), - DateUtils.MINUTE_IN_MILLIS, - DateUtils.FORMAT_ABBREV_ALL, - ) - .toString() + DateUtils + .getRelativeTimeSpanString( + mills * 1000, + System.currentTimeMillis(), + DateUtils.MINUTE_IN_MILLIS, + DateUtils.FORMAT_ABBREV_ALL, + ).toString() if (humanReadable.startsWith("In") || humanReadable.startsWith("0")) { humanReadable = stringForNow } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt index bc00950ff7..dda328e884 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt @@ -58,7 +58,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -82,6 +81,7 @@ import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.types.RenderEmojiPack import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.encoders.ATag @@ -217,7 +217,7 @@ fun UpdateReactionTypeDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.new_reaction_symbol)) }, + label = { Text(text = stringRes(R.string.new_reaction_symbol)) }, value = postViewModel.nextChoice, onValueChange = { postViewModel.nextChoice = it }, keyboardOptions = @@ -243,7 +243,7 @@ fun UpdateReactionTypeDialog( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(text = stringResource(R.string.add), color = Color.White) + Text(text = stringRes(R.string.add), color = Color.White) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt index 9c27ff91dd..c41dedb185 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt @@ -72,7 +72,6 @@ import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -95,6 +94,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer import com.vitorpamplona.amethyst.ui.screen.loggedIn.getFragmentActivity +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Font14SP @@ -108,7 +108,9 @@ import com.vitorpamplona.quartz.events.LnZapEvent import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CancellationException -class UpdateZapAmountViewModel(val account: Account) : ViewModel() { +class UpdateZapAmountViewModel( + val account: Account, +) : ViewModel() { var nextAmount by mutableStateOf(TextFieldValue("")) var amountSet by mutableStateOf(listOf()) var walletConnectRelay by mutableStateOf(TextFieldValue("")) @@ -134,9 +136,7 @@ class UpdateZapAmountViewModel(val account: Account) : ViewModel() { this.selectedZapType = account.defaultZapType } - fun toListOfAmounts(commaSeparatedAmounts: String): List { - return commaSeparatedAmounts.split(",").map { it.trim().toLongOrNull() ?: 0 } - } + fun toListOfAmounts(commaSeparatedAmounts: String): List = commaSeparatedAmounts.split(",").map { it.trim().toLongOrNull() ?: 0 } fun addAmount() { val newValue = nextAmount.text.trim().toLongOrNull() @@ -193,15 +193,14 @@ class UpdateZapAmountViewModel(val account: Account) : ViewModel() { nextAmount = TextFieldValue("") } - fun hasChanged(): Boolean { - return ( + fun hasChanged(): Boolean = + ( selectedZapType != account?.defaultZapType || amountSet != account?.zapAmountChoices || walletConnectPubkey.text != (account?.zapPaymentRequest?.pubKeyHex ?: "") || walletConnectRelay.text != (account?.zapPaymentRequest?.relayUri ?: "") || walletConnectSecret.text != (account?.zapPaymentRequest?.secret ?: "") ) - } fun updateNIP47(uri: String) { val contact = Nip47WalletConnect.parse(uri) @@ -212,10 +211,10 @@ class UpdateZapAmountViewModel(val account: Account) : ViewModel() { } } - class Factory(val account: Account) : ViewModelProvider.Factory { - override fun create(modelClass: Class): UpdateZapAmountViewModel { - return UpdateZapAmountViewModel(account) as UpdateZapAmountViewModel - } + class Factory( + val account: Account, + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): UpdateZapAmountViewModel = UpdateZapAmountViewModel(account) as UpdateZapAmountViewModel } } @@ -241,23 +240,23 @@ fun UpdateZapAmountDialog( listOf( Triple( LnZapEvent.ZapType.PUBLIC, - stringResource(id = R.string.zap_type_public), - stringResource(id = R.string.zap_type_public_explainer), + stringRes(id = R.string.zap_type_public), + stringRes(id = R.string.zap_type_public_explainer), ), Triple( LnZapEvent.ZapType.PRIVATE, - stringResource(id = R.string.zap_type_private), - stringResource(id = R.string.zap_type_private_explainer), + stringRes(id = R.string.zap_type_private), + stringRes(id = R.string.zap_type_private_explainer), ), Triple( LnZapEvent.ZapType.ANONYMOUS, - stringResource(id = R.string.zap_type_anonymous), - stringResource(id = R.string.zap_type_anonymous_explainer), + stringRes(id = R.string.zap_type_anonymous), + stringRes(id = R.string.zap_type_anonymous_explainer), ), Triple( LnZapEvent.ZapType.NONZAP, - stringResource(id = R.string.zap_type_nonzap), - stringResource(id = R.string.zap_type_nonzap_explainer), + stringRes(id = R.string.zap_type_nonzap), + stringRes(id = R.string.zap_type_nonzap_explainer), ), ) @@ -274,13 +273,13 @@ fun UpdateZapAmountDialog( } catch (e: IllegalArgumentException) { if (e.message != null) { accountViewModel.toast( - context.getString(R.string.error_parsing_nip47_title), - context.getString(R.string.error_parsing_nip47, nip47uri, e.message!!), + stringRes(context, R.string.error_parsing_nip47_title), + stringRes(context, R.string.error_parsing_nip47, nip47uri, e.message!!), ) } else { accountViewModel.toast( - context.getString(R.string.error_parsing_nip47_title), - context.getString(R.string.error_parsing_nip47_no_error, nip47uri), + stringRes(context, R.string.error_parsing_nip47_title), + stringRes(context, R.string.error_parsing_nip47_no_error, nip47uri), ) } } @@ -367,7 +366,7 @@ fun UpdateZapAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.new_amount_in_sats)) }, + label = { Text(text = stringRes(R.string.new_amount_in_sats)) }, value = postViewModel.nextAmount, onValueChange = { postViewModel.nextAmount = it }, keyboardOptions = @@ -393,7 +392,7 @@ fun UpdateZapAmountDialog( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(text = stringResource(R.string.add), color = Color.White) + Text(text = stringRes(R.string.add), color = Color.White) } } @@ -402,7 +401,7 @@ fun UpdateZapAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { TextSpinner( - label = stringResource(id = R.string.zap_type_explainer), + label = stringRes(id = R.string.zap_type_explainer), placeholder = zapTypes.filter { it.first == accountViewModel.defaultZapType() }.first().second, options = zapOptions, @@ -423,7 +422,7 @@ fun UpdateZapAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { Text( - stringResource(id = R.string.wallet_connect_service), + stringRes(id = R.string.wallet_connect_service), Modifier.weight(1f), ) @@ -447,7 +446,7 @@ fun UpdateZapAmountDialog( ) { Icon( painter = painterResource(R.drawable.alby), - contentDescription = stringResource(id = R.string.accessibility_navigate_to_alby), + contentDescription = stringRes(id = R.string.accessibility_navigate_to_alby), modifier = Modifier.size(24.dp), tint = Color.Unspecified, ) @@ -460,7 +459,7 @@ fun UpdateZapAmountDialog( ) { Icon( Icons.Default.ContentPaste, - contentDescription = stringResource(id = R.string.paste_from_clipboard), + contentDescription = stringRes(id = R.string.paste_from_clipboard), modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary, ) @@ -469,7 +468,7 @@ fun UpdateZapAmountDialog( IconButton(onClick = { qrScanning = true }) { Icon( painter = painterResource(R.drawable.ic_qrcode), - contentDescription = stringResource(id = R.string.accessibility_scan_qr_code), + contentDescription = stringRes(id = R.string.accessibility_scan_qr_code), modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary, ) @@ -481,7 +480,7 @@ fun UpdateZapAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { Text( - stringResource(id = R.string.wallet_connect_service_explainer), + stringRes(id = R.string.wallet_connect_service_explainer), Modifier.weight(1f), color = MaterialTheme.colorScheme.placeholderText, fontSize = Font14SP, @@ -497,13 +496,13 @@ fun UpdateZapAmountDialog( } catch (e: IllegalArgumentException) { if (e.message != null) { accountViewModel.toast( - context.getString(R.string.error_parsing_nip47_title), - context.getString(R.string.error_parsing_nip47, it, e.message!!), + stringRes(context, R.string.error_parsing_nip47_title), + stringRes(context, R.string.error_parsing_nip47, it, e.message!!), ) } else { accountViewModel.toast( - context.getString(R.string.error_parsing_nip47_title), - context.getString(R.string.error_parsing_nip47_no_error, it), + stringRes(context, R.string.error_parsing_nip47_title), + stringRes(context, R.string.error_parsing_nip47_no_error, it), ) } } @@ -516,7 +515,7 @@ fun UpdateZapAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.wallet_connect_service_pubkey)) }, + label = { Text(text = stringRes(R.string.wallet_connect_service_pubkey)) }, value = postViewModel.walletConnectPubkey, onValueChange = { postViewModel.walletConnectPubkey = it }, keyboardOptions = @@ -539,7 +538,7 @@ fun UpdateZapAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.wallet_connect_service_relay)) }, + label = { Text(text = stringRes(R.string.wallet_connect_service_relay)) }, modifier = Modifier.weight(1f), value = postViewModel.walletConnectRelay, onValueChange = { postViewModel.walletConnectRelay = it }, @@ -559,21 +558,20 @@ fun UpdateZapAmountDialog( val context = LocalContext.current val keyguardLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { - result: ActivityResult -> + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Activity.RESULT_OK) { showPassword = true } } - val authTitle = stringResource(id = R.string.wallet_connect_service_show_secret) + val authTitle = stringRes(id = R.string.wallet_connect_service_show_secret) Row( modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.wallet_connect_service_secret)) }, + label = { Text(text = stringRes(R.string.wallet_connect_service_secret)) }, modifier = Modifier.weight(1f), value = postViewModel.walletConnectSecret, onValueChange = { postViewModel.walletConnectSecret = it }, @@ -585,7 +583,7 @@ fun UpdateZapAmountDialog( ), placeholder = { Text( - text = stringResource(R.string.wallet_connect_service_secret_placeholder), + text = stringRes(R.string.wallet_connect_service_secret_placeholder), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -614,9 +612,9 @@ fun UpdateZapAmountDialog( }, contentDescription = if (showPassword) { - stringResource(R.string.show_password) + stringRes(R.string.show_password) } else { - stringResource( + stringRes( R.string.hide_password, ) }, @@ -654,7 +652,7 @@ fun authenticate( fun keyguardPrompt() { val intent = keyguardManager.createConfirmDeviceCredentialIntent( - context.getString(R.string.app_name_release), + stringRes(context, R.string.app_name_release), title, ) @@ -672,8 +670,9 @@ fun authenticate( BiometricManager.Authenticators.DEVICE_CREDENTIAL val promptInfo = - BiometricPrompt.PromptInfo.Builder() - .setTitle(context.getString(R.string.app_name_release)) + BiometricPrompt.PromptInfo + .Builder() + .setTitle(stringRes(context, R.string.app_name_release)) .setSubtitle(title) .setAllowedAuthenticators(authenticators) .build() @@ -693,8 +692,9 @@ fun authenticate( BiometricPrompt.ERROR_LOCKOUT -> keyguardPrompt() else -> onError( - context.getString(R.string.biometric_authentication_failed), - context.getString( + stringRes(context, R.string.biometric_authentication_failed), + stringRes( + context, R.string.biometric_authentication_failed_explainer_with_error, errString, ), @@ -705,8 +705,8 @@ fun authenticate( override fun onAuthenticationFailed() { super.onAuthenticationFailed() onError( - context.getString(R.string.biometric_authentication_failed), - context.getString(R.string.biometric_authentication_failed_explainer), + stringRes(context, R.string.biometric_authentication_failed), + stringRes(context, R.string.biometric_authentication_failed_explainer), ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt index 5b20bf188a..8d21675809 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt @@ -30,12 +30,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map @@ -46,6 +44,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.events.ChatroomKey @Composable @@ -91,7 +90,7 @@ fun DisplayBlankAuthor( RobohashAsyncImage( robot = "authornotfound", - contentDescription = stringResource(R.string.unknown_author), + contentDescription = stringRes(R.string.unknown_author), modifier = nullModifier, loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE, ) @@ -347,9 +346,9 @@ fun InnerUserPicture( model = userPicture, contentDescription = if (userName != null) { - stringResource(id = R.string.profile_image_of_user, userName) + stringRes(id = R.string.profile_image_of_user, userName) } else { - stringResource(id = R.string.profile_image) + stringRes(id = R.string.profile_image) }, modifier = myImageModifier, contentScale = ContentScale.Crop, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt index 81961994cf..4d07867c41 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt @@ -39,7 +39,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -60,6 +59,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.BundledInsert import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.RoyalBlue import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -99,7 +99,7 @@ fun UserReactionsRow( ) { Row(verticalAlignment = CenterVertically, modifier = Modifier.width(68.dp)) { Text( - text = stringResource(id = R.string.today), + text = stringRes(id = R.string.today), fontWeight = FontWeight.Bold, ) @@ -133,7 +133,7 @@ fun UserReactionsRow( private fun UserZapModel(model: UserReactionsViewModel) { Icon( imageVector = Icons.Default.Bolt, - contentDescription = stringResource(R.string.zaps), + contentDescription = stringRes(R.string.zaps), modifier = Size24Modifier, tint = BitcoinOrange, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt index cca7e1b874..cb2a9d40a8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt @@ -57,7 +57,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -78,6 +77,7 @@ import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer @@ -127,23 +127,23 @@ fun ZapCustomDialog( listOf( Triple( LnZapEvent.ZapType.PUBLIC, - stringResource(id = R.string.zap_type_public), - stringResource(id = R.string.zap_type_public_explainer), + stringRes(id = R.string.zap_type_public), + stringRes(id = R.string.zap_type_public_explainer), ), Triple( LnZapEvent.ZapType.PRIVATE, - stringResource(id = R.string.zap_type_private), - stringResource(id = R.string.zap_type_private_explainer), + stringRes(id = R.string.zap_type_private), + stringRes(id = R.string.zap_type_private_explainer), ), Triple( LnZapEvent.ZapType.ANONYMOUS, - stringResource(id = R.string.zap_type_anonymous), - stringResource(id = R.string.zap_type_anonymous_explainer), + stringRes(id = R.string.zap_type_anonymous), + stringRes(id = R.string.zap_type_anonymous_explainer), ), Triple( LnZapEvent.ZapType.NONZAP, - stringResource(id = R.string.zap_type_nonzap), - stringResource(id = R.string.zap_type_nonzap_explainer), + stringRes(id = R.string.zap_type_nonzap), + stringRes(id = R.string.zap_type_nonzap_explainer), ), ) @@ -200,8 +200,8 @@ fun ZapCustomDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - // stringResource(R.string.new_amount_in_sats - label = { Text(text = stringResource(id = R.string.amount_in_sats)) }, + // stringRes(R.string.new_amount_in_sats + label = { Text(text = stringRes(id = R.string.amount_in_sats)) }, value = postViewModel.customAmount, onValueChange = { postViewModel.customAmount = it }, keyboardOptions = @@ -220,7 +220,7 @@ fun ZapCustomDialog( ) TextSpinner( - label = stringResource(id = R.string.zap_type), + label = stringRes(id = R.string.zap_type), placeholder = zapTypes .filter { it.first == accountViewModel.account.defaultZapType } @@ -237,17 +237,17 @@ fun ZapCustomDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - // stringResource(R.string.new_amount_in_sats + // stringRes(R.string.new_amount_in_sats label = { if ( selectedZapType == LnZapEvent.ZapType.PUBLIC || selectedZapType == LnZapEvent.ZapType.ANONYMOUS ) { - Text(text = stringResource(id = R.string.custom_zaps_add_a_message)) + Text(text = stringRes(id = R.string.custom_zaps_add_a_message)) } else if (selectedZapType == LnZapEvent.ZapType.PRIVATE) { - Text(text = stringResource(id = R.string.custom_zaps_add_a_message_private)) + Text(text = stringRes(id = R.string.custom_zaps_add_a_message_private)) } else if (selectedZapType == LnZapEvent.ZapType.NONZAP) { - Text(text = stringResource(id = R.string.custom_zaps_add_a_message_nonzap)) + Text(text = stringRes(id = R.string.custom_zaps_add_a_message_nonzap)) } }, value = postViewModel.customMessage, @@ -259,7 +259,7 @@ fun ZapCustomDialog( ), placeholder = { Text( - text = stringResource(id = R.string.custom_zaps_add_a_message_example), + text = stringRes(id = R.string.custom_zaps_add_a_message_example), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -313,7 +313,7 @@ fun ErrorMessageDialog( contentDescription = null, ) Spacer(StdHorzSpacer) - Text(stringResource(R.string.error_dialog_talk_to_user)) + Text(stringRes(R.string.error_dialog_talk_to_user)) } } Button( @@ -329,7 +329,7 @@ fun ErrorMessageDialog( contentDescription = null, ) Spacer(StdHorzSpacer) - Text(stringResource(R.string.error_dialog_button_ok)) + Text(stringRes(R.string.error_dialog_button_ok)) } } } @@ -389,7 +389,7 @@ fun PayViaIntentDialog( UsernameDisplay(it.user, accountViewModel = accountViewModel) } else { Text( - text = stringResource(id = R.string.wallet_number, index + 1), + text = stringRes(id = R.string.wallet_number, index + 1), maxLines = 1, overflow = TextOverflow.Ellipsis, fontWeight = FontWeight.Bold, @@ -406,7 +406,7 @@ fun PayViaIntentDialog( ) Spacer(modifier = StdHorzSpacer) Text( - text = stringResource(id = R.string.sats), + text = stringRes(id = R.string.sats), maxLines = 1, overflow = TextOverflow.Ellipsis, fontWeight = FontWeight.Bold, @@ -444,9 +444,9 @@ fun payViaIntent( if (e is CancellationException) throw e // don't display ugly error messages // if (e.message != null) { - // onError(context.getString(R.string.no_wallet_found_with_error, e.message!!)) + // onError(stringRes(context, R.string.no_wallet_found_with_error, e.message!!)) // } else { - onError(context.getString(R.string.no_wallet_found)) + onError(stringRes(context, R.string.no_wallet_found)) // } } } @@ -468,9 +468,9 @@ fun PayButton( contentPadding = ZeroPadding, ) { if (isActive) { - Text(text = stringResource(R.string.pay), color = Color.White) + Text(text = stringRes(R.string.pay), color = Color.White) } else { - Text(text = stringResource(R.string.paid), color = Color.White) + Text(text = stringRes(R.string.paid), color = Color.White) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt index 6a99919529..5d12dabfae 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -47,6 +46,7 @@ import com.vitorpamplona.amethyst.ui.actions.relays.AddDMRelayListDialog import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BigPadding import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -159,7 +159,7 @@ fun AddInboxRelayForDMCard( ) { // Title Text( - text = stringResource(id = R.string.dm_relays_not_found), + text = stringRes(id = R.string.dm_relays_not_found), style = TextStyle( fontSize = 20.sp, @@ -170,13 +170,13 @@ fun AddInboxRelayForDMCard( Spacer(modifier = StdVertSpacer) Text( - text = stringResource(id = R.string.dm_relays_not_found_description), + text = stringRes(id = R.string.dm_relays_not_found_description), ) Spacer(modifier = StdVertSpacer) Text( - text = stringResource(id = R.string.dm_relays_not_found_examples), + text = stringRes(id = R.string.dm_relays_not_found_examples), ) Spacer(modifier = StdVertSpacer) @@ -192,7 +192,7 @@ fun AddInboxRelayForDMCard( }, modifier = Modifier.fillMaxWidth(), ) { - Text(text = stringResource(id = R.string.dm_relays_not_found_create_now)) + Text(text = stringRes(id = R.string.dm_relays_not_found_create_now)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt index e04249676c..42edc49ebb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForSearchCard.kt @@ -34,7 +34,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -47,6 +46,7 @@ import com.vitorpamplona.amethyst.ui.actions.relays.AddSearchRelayListDialog import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BigPadding import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -159,7 +159,7 @@ fun AddInboxRelayForSearchCard( ) { // Title Text( - text = stringResource(id = R.string.search_relays_not_found), + text = stringRes(id = R.string.search_relays_not_found), style = TextStyle( fontSize = 20.sp, @@ -170,7 +170,7 @@ fun AddInboxRelayForSearchCard( Spacer(modifier = StdVertSpacer) Text( - text = stringResource(id = R.string.search_relays_not_found_description), + text = stringRes(id = R.string.search_relays_not_found_description), ) Spacer(modifier = StdVertSpacer) @@ -186,7 +186,7 @@ fun AddInboxRelayForSearchCard( }, modifier = Modifier.fillMaxWidth(), ) { - Text(text = stringResource(id = R.string.dm_relays_not_found_create_now)) + Text(text = stringRes(id = R.string.dm_relays_not_found_create_now)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt index e926d6421e..d996c57f63 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddRemoveButtons.kt @@ -29,11 +29,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn @@ -73,7 +73,7 @@ fun AddButton( enabled = isActive, contentPadding = PaddingValues(vertical = 0.dp, horizontal = 16.dp), ) { - Text(text = stringResource(text), color = Color.White, textAlign = TextAlign.Center) + Text(text = stringRes(text), color = Color.White, textAlign = TextAlign.Center) } } @@ -93,6 +93,6 @@ fun RemoveButton( enabled = isActive, contentPadding = PaddingValues(vertical = 0.dp, horizontal = 16.dp), ) { - Text(text = stringResource(R.string.remove), color = Color.White) + Text(text = stringRes(R.string.remove), color = Color.White) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt index acb98798c6..47bd833952 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/BoostedMark.kt @@ -23,16 +23,16 @@ package com.vitorpamplona.amethyst.ui.note.elements import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.HalfStartPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText @Composable fun BoostedMark() { Text( - stringResource(id = R.string.boosted), + stringRes(id = R.string.boosted), fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.placeholderText, maxLines = 1, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt index 3e62441f70..340750b595 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt @@ -31,7 +31,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R @@ -40,6 +39,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.note.WatchAuthor import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.authorNotePictureForImageHeader @@ -69,7 +69,7 @@ fun BannerImage( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), @@ -80,7 +80,7 @@ fun BannerImage( } ?: run { Image( painter = painterResource(R.drawable.profile_banner), - contentDescription = stringResource(R.string.profile_banner), + contentDescription = stringRes(R.string.profile_banner), contentScale = ContentScale.Crop, modifier = imageModifier, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt index 0981fc8468..73df0737a3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt @@ -24,11 +24,11 @@ import androidx.compose.foundation.text.ClickableText import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.note.types.EditState +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.HalfStartPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -38,11 +38,11 @@ fun DisplayEditStatus(editState: EditState) { text = buildAnnotatedString { if (editState.showingVersion.value == editState.originalVersionId()) { - append(stringResource(id = R.string.original)) + append(stringRes(id = R.string.original)) } else if (editState.showingVersion.value == editState.lastVersionId()) { - append(stringResource(id = R.string.edited)) + append(stringRes(id = R.string.edited)) } else { - append(stringResource(id = R.string.edited_number, editState.versionId())) + append(stringRes(id = R.string.edited_number, editState.versionId())) } }, onClick = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt index 4c3488c646..0187257137 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import com.vitorpamplona.amethyst.R @@ -37,6 +36,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.note.LoadOts import com.vitorpamplona.amethyst.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import java.text.SimpleDateFormat @@ -65,7 +65,7 @@ fun DisplayOts( text = buildAnnotatedString { append( - stringResource( + stringRes( id = R.string.existed_since, timeStr, ), @@ -76,8 +76,9 @@ fun DisplayOts( SimpleDateFormat.getDateTimeInstance().format(Date(unixtimestamp * 1000)) accountViewModel.toast( - context.getString(R.string.ots_info_title), - context.getString(R.string.ots_info_description, fullDateTime), + R.string.ots_info_title, + R.string.ots_info_description, + fullDateTime, ) }, style = @@ -91,7 +92,7 @@ fun DisplayOts( }, whenPending = { Text( - stringResource(id = R.string.timestamp_pending_short), + stringRes(id = R.string.timestamp_pending_short), color = MaterialTheme.colorScheme.lessImportantLink, fontSize = Font14SP, fontWeight = FontWeight.Bold, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt index e3720abd46..e64b198223 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt @@ -48,7 +48,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -68,13 +67,16 @@ import com.vitorpamplona.amethyst.ui.note.ZapIcon import com.vitorpamplona.amethyst.ui.note.ZappedIcon import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.placeholderText import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.math.BigDecimal -@Stable data class Reward(val amount: BigDecimal) +@Stable data class Reward( + val amount: BigDecimal, +) @Composable fun DisplayReward( @@ -199,9 +201,7 @@ class AddBountyAmountViewModel : ViewModel() { nextAmount = TextFieldValue("") } - fun hasChanged(): Boolean { - return nextAmount.text.trim().toLongOrNull() != null - } + fun hasChanged(): Boolean = nextAmount.text.trim().toLongOrNull() != null } @Composable @@ -254,7 +254,7 @@ fun AddBountyAmountDialog( verticalAlignment = Alignment.CenterVertically, ) { OutlinedTextField( - label = { Text(text = stringResource(R.string.pledge_amount_in_sats)) }, + label = { Text(text = stringRes(R.string.pledge_amount_in_sats)) }, value = postViewModel.nextAmount, onValueChange = { postViewModel.nextAmount = it }, keyboardOptions = diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt index f674417375..74aafc6618 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayZapSplits.kt @@ -24,12 +24,10 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.ClickableText import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.text.AnnotatedString diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt index 9559ab5750..12006581be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt @@ -38,7 +38,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.core.content.ContextCompat import com.vitorpamplona.amethyst.R @@ -52,6 +51,7 @@ import com.vitorpamplona.amethyst.ui.note.externalLinkForNote import com.vitorpamplona.amethyst.ui.note.types.EditState import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size24Modifier import com.vitorpamplona.quartz.events.TextNoteEvent @@ -177,7 +177,7 @@ fun NoteDropDownMenu( if (!state.isFollowingAuthor) { DropdownMenuItem( - text = { Text(stringResource(R.string.follow)) }, + text = { Text(stringRes(R.string.follow)) }, onClick = { val author = note.author ?: return@DropdownMenuItem accountViewModel.follow(author) @@ -187,7 +187,7 @@ fun NoteDropDownMenu( HorizontalDivider(thickness = DividerThickness) } DropdownMenuItem( - text = { Text(stringResource(R.string.copy_text)) }, + text = { Text(stringRes(R.string.copy_text)) }, onClick = { scope.launch(Dispatchers.IO) { accountViewModel.decrypt(note) { clipboardManager.setText(AnnotatedString(it)) } @@ -196,7 +196,7 @@ fun NoteDropDownMenu( }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.copy_user_pubkey)) }, + text = { Text(stringRes(R.string.copy_user_pubkey)) }, onClick = { scope.launch(Dispatchers.IO) { clipboardManager.setText(AnnotatedString("nostr:${note.author?.pubkeyNpub()}")) @@ -205,7 +205,7 @@ fun NoteDropDownMenu( }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.copy_note_id)) }, + text = { Text(stringRes(R.string.copy_note_id)) }, onClick = { scope.launch(Dispatchers.IO) { clipboardManager.setText(AnnotatedString("nostr:" + note.toNEvent())) @@ -214,7 +214,7 @@ fun NoteDropDownMenu( }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.quick_action_share)) }, + text = { Text(stringRes(R.string.quick_action_share)) }, onClick = { val sendIntent = Intent().apply { @@ -226,12 +226,12 @@ fun NoteDropDownMenu( ) putExtra( Intent.EXTRA_TITLE, - actContext.getString(R.string.quick_action_share_browser_link), + stringRes(actContext, R.string.quick_action_share_browser_link), ) } val shareIntent = - Intent.createChooser(sendIntent, appContext.getString(R.string.quick_action_share)) + Intent.createChooser(sendIntent, stringRes(actContext, R.string.quick_action_share)) ContextCompat.startActivity(actContext, shareIntent, null) onDismiss() }, @@ -239,7 +239,7 @@ fun NoteDropDownMenu( HorizontalDivider(thickness = DividerThickness) if (state.isLoggedUser && note.isDraft()) { DropdownMenuItem( - text = { Text(stringResource(R.string.edit_draft)) }, + text = { Text(stringRes(R.string.edit_draft)) }, onClick = { wantsToEditDraft.value = true }, @@ -248,14 +248,14 @@ fun NoteDropDownMenu( if (note.event is TextNoteEvent && !note.isDraft()) { if (state.isLoggedUser) { DropdownMenuItem( - text = { Text(stringResource(R.string.edit_post)) }, + text = { Text(stringRes(R.string.edit_post)) }, onClick = { wantsToEditPost.value = true }, ) } else { DropdownMenuItem( - text = { Text(stringResource(R.string.propose_an_edit)) }, + text = { Text(stringRes(R.string.propose_an_edit)) }, onClick = { wantsToEditPost.value = true }, @@ -263,7 +263,7 @@ fun NoteDropDownMenu( } } DropdownMenuItem( - text = { Text(stringResource(R.string.broadcast)) }, + text = { Text(stringRes(R.string.broadcast)) }, onClick = { accountViewModel.broadcast(note) onDismiss() @@ -272,14 +272,14 @@ fun NoteDropDownMenu( HorizontalDivider(thickness = DividerThickness) if (accountViewModel.account.hasPendingAttestations(note)) { DropdownMenuItem( - text = { Text(stringResource(R.string.timestamp_pending)) }, + text = { Text(stringRes(R.string.timestamp_pending)) }, onClick = { onDismiss() }, ) } else { DropdownMenuItem( - text = { Text(stringResource(R.string.timestamp_it)) }, + text = { Text(stringRes(R.string.timestamp_it)) }, onClick = { accountViewModel.timestamp(note) onDismiss() @@ -289,7 +289,7 @@ fun NoteDropDownMenu( HorizontalDivider(thickness = DividerThickness) if (state.isPrivateBookmarkNote) { DropdownMenuItem( - text = { Text(stringResource(R.string.remove_from_private_bookmarks)) }, + text = { Text(stringRes(R.string.remove_from_private_bookmarks)) }, onClick = { accountViewModel.removePrivateBookmark(note) onDismiss() @@ -297,7 +297,7 @@ fun NoteDropDownMenu( ) } else { DropdownMenuItem( - text = { Text(stringResource(R.string.add_to_private_bookmarks)) }, + text = { Text(stringRes(R.string.add_to_private_bookmarks)) }, onClick = { accountViewModel.addPrivateBookmark(note) onDismiss() @@ -306,7 +306,7 @@ fun NoteDropDownMenu( } if (state.isPublicBookmarkNote) { DropdownMenuItem( - text = { Text(stringResource(R.string.remove_from_public_bookmarks)) }, + text = { Text(stringRes(R.string.remove_from_public_bookmarks)) }, onClick = { accountViewModel.removePublicBookmark(note) onDismiss() @@ -314,7 +314,7 @@ fun NoteDropDownMenu( ) } else { DropdownMenuItem( - text = { Text(stringResource(R.string.add_to_public_bookmarks)) }, + text = { Text(stringRes(R.string.add_to_public_bookmarks)) }, onClick = { accountViewModel.addPublicBookmark(note) onDismiss() @@ -324,7 +324,7 @@ fun NoteDropDownMenu( HorizontalDivider(thickness = DividerThickness) if (state.showSensitiveContent == null || state.showSensitiveContent == true) { DropdownMenuItem( - text = { Text(stringResource(R.string.content_warning_hide_all_sensitive_content)) }, + text = { Text(stringRes(R.string.content_warning_hide_all_sensitive_content)) }, onClick = { scope.launch(Dispatchers.IO) { accountViewModel.hideSensitiveContent() @@ -335,7 +335,7 @@ fun NoteDropDownMenu( } if (state.showSensitiveContent == null || state.showSensitiveContent == false) { DropdownMenuItem( - text = { Text(stringResource(R.string.content_warning_show_all_sensitive_content)) }, + text = { Text(stringRes(R.string.content_warning_show_all_sensitive_content)) }, onClick = { scope.launch(Dispatchers.IO) { accountViewModel.disableContentWarnings() @@ -346,7 +346,7 @@ fun NoteDropDownMenu( } if (state.showSensitiveContent != null) { DropdownMenuItem( - text = { Text(stringResource(R.string.content_warning_see_warnings)) }, + text = { Text(stringRes(R.string.content_warning_see_warnings)) }, onClick = { scope.launch(Dispatchers.IO) { accountViewModel.seeContentWarnings() @@ -358,7 +358,7 @@ fun NoteDropDownMenu( HorizontalDivider(thickness = DividerThickness) if (state.isLoggedUser) { DropdownMenuItem( - text = { Text(stringResource(R.string.request_deletion)) }, + text = { Text(stringRes(R.string.request_deletion)) }, onClick = { scope.launch(Dispatchers.IO) { accountViewModel.delete(note) @@ -368,7 +368,7 @@ fun NoteDropDownMenu( ) } else { DropdownMenuItem( - text = { Text(stringResource(R.string.block_report)) }, + text = { Text(stringRes(R.string.block_report)) }, onClick = { reportDialogShowing = true }, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt index dd536c4f97..de50e9a977 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt @@ -31,7 +31,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.R @@ -41,6 +40,7 @@ import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.nip05 @@ -90,7 +90,7 @@ fun ForkInformationRowLightColor( ClickableText( text = buildAnnotatedString { - append(stringResource(id = R.string.forked_from)) + append(stringRes(id = R.string.forked_from)) append(" ") }, onClick = { nav(route) }, @@ -139,7 +139,7 @@ fun ForkInformationRow( val author = note.author ?: return val meta by author.live().userMetadataInfo.observeAsState(author.info) - Text(stringResource(id = R.string.forked_from)) + Text(stringRes(id = R.string.forked_from)) Spacer(modifier = StdHorzSpacer) val userMetadata by author.live().userMetadataInfo.observeAsState() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt index 59e1b88038..7bbf84b532 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ZapTheDevsCard.kt @@ -49,7 +49,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.buildAnnotatedString @@ -81,6 +80,7 @@ import com.vitorpamplona.amethyst.ui.note.ZapIcon import com.vitorpamplona.amethyst.ui.note.ZappedIcon import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -226,7 +226,7 @@ fun ZapTheDevsCard( horizontalArrangement = Arrangement.SpaceBetween, ) { Text( - text = stringResource(id = R.string.zap_the_devs_title), + text = stringRes(id = R.string.zap_the_devs_title), style = TextStyle( fontSize = 20.sp, @@ -247,7 +247,7 @@ fun ZapTheDevsCard( ClickableText( text = buildAnnotatedString { - append(stringResource(id = R.string.zap_the_devs_description, BuildConfig.VERSION_NAME)) + append(stringRes(id = R.string.zap_the_devs_description, BuildConfig.VERSION_NAME)) append(" ") withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) { append("#value4value") @@ -270,14 +270,14 @@ fun ZapTheDevsCard( text = buildAnnotatedString { withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) { - append(stringResource(id = R.string.version_name, BuildConfig.VERSION_NAME.substringBefore("-"))) + append(stringRes(id = R.string.version_name, BuildConfig.VERSION_NAME.substringBefore("-"))) } - append(" " + stringResource(id = R.string.brought_to_you_by)) + append(" " + stringRes(id = R.string.brought_to_you_by)) }, onClick = { nav(route) }, ) } else { - Text(stringResource(id = R.string.this_version_brought_to_you_by)) + Text(stringRes(id = R.string.this_version_brought_to_you_by)) } Spacer(modifier = StdVertSpacer) @@ -377,7 +377,7 @@ fun ZapDonationButton( if (showErrorMessageDialog != null) { ErrorMessageDialog( - title = stringResource(id = R.string.error_dialog_zap_error), + title = stringRes(id = R.string.error_dialog_zap_error), textContent = showErrorMessageDialog ?: "", onClickStartMessage = { baseNote.author?.let { @@ -424,8 +424,7 @@ fun ZapDonationButton( targetValue = zappingProgress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec, label = "ZapIconIndicator", - ) - .value, + ).value, modifier = remember { Modifier.size(animationSize) }, strokeWidth = 2.dp, color = grayTint, @@ -455,9 +454,9 @@ fun ZapDonationButton( } if (hasZapped) { - Text(text = stringResource(id = R.string.thank_you)) + Text(text = stringRes(id = R.string.thank_you)) } else { - Text(text = stringResource(id = R.string.donate_now)) + Text(text = stringRes(id = R.string.donate_now)) } } } @@ -481,13 +480,13 @@ fun customZapClick( if (accountViewModel.account.zapAmountChoices.isEmpty()) { accountViewModel.toast( - context.getString(R.string.error_dialog_zap_error), - context.getString(R.string.no_zap_amount_setup_long_press_to_change), + stringRes(context, R.string.error_dialog_zap_error), + stringRes(context, R.string.no_zap_amount_setup_long_press_to_change), ) } else if (!accountViewModel.isWriteable()) { accountViewModel.toast( - context.getString(R.string.error_dialog_zap_error), - context.getString(R.string.login_with_a_private_key_to_be_able_to_send_zaps), + stringRes(context, R.string.error_dialog_zap_error), + stringRes(context, R.string.login_with_a_private_key_to_be_able_to_send_zaps), ) } else if (accountViewModel.account.zapAmountChoices.size == 1) { val amount = accountViewModel.account.zapAmountChoices.first() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt index 770275404d..b0b1bd6f5b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt @@ -52,7 +52,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -66,6 +65,7 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog import com.vitorpamplona.amethyst.ui.note.LinkIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -101,7 +101,7 @@ fun RenderAppDefinition( AsyncImage( model = it.banner, - contentDescription = stringResource(id = R.string.profile_image), + contentDescription = stringRes(id = R.string.profile_image), contentScale = ContentScale.FillWidth, modifier = Modifier @@ -123,7 +123,7 @@ fun RenderAppDefinition( } else { Image( painter = painterResource(R.drawable.profile_banner), - contentDescription = stringResource(id = R.string.profile_banner), + contentDescription = stringRes(id = R.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Modifier @@ -157,8 +157,7 @@ fun RenderAppDefinition( 3.dp, MaterialTheme.colorScheme.background, CircleShape, - ) - .clip(shape = CircleShape) + ).clip(shape = CircleShape) .fillMaxSize() .background(MaterialTheme.colorScheme.background) .combinedClickable( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt index 1d48419f10..ad50282b91 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt @@ -49,7 +49,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.luminance import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -63,6 +62,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink import com.vitorpamplona.quartz.events.BadgeAwardEvent @@ -86,7 +86,10 @@ fun BadgeDisplay(baseNote: Note) { launch(Dispatchers.IO) { imageResult?.let { val backgroundColor = - it.drawable.toBitmap(200, 200).copy(Bitmap.Config.ARGB_8888, false).get(0, 199) + it.drawable + .toBitmap(200, 200) + .copy(Bitmap.Config.ARGB_8888, false) + .get(0, 199) val colorFromImage = Color(backgroundColor) val textBackground = if (colorFromImage.luminance() > 0.5) { @@ -109,8 +112,7 @@ fun BadgeDisplay(baseNote: Note) { 5.dp, MaterialTheme.colorScheme.mediumImportanceLink, CutCornerShape(20), - ) - .background(backgroundFromImage.first), + ).background(backgroundFromImage.first), ) { RenderBadge( image, @@ -138,7 +140,7 @@ private fun RenderBadge( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.badge_award_image_for, name ?: "", ), @@ -191,7 +193,7 @@ fun RenderBadgeAward( val noteEvent = note.event as? BadgeAwardEvent ?: return var awardees by remember { mutableStateOf>(listOf()) } - Text(text = stringResource(R.string.award_granted_to)) + Text(text = stringRes(R.string.award_granted_to)) LaunchedEffect(key1 = note) { accountViewModel.loadUsers(noteEvent.awardees()) { awardees = it } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt index 48e6f76262..63eacda3ff 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt @@ -26,7 +26,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.State -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt index 905dd8283e..81e944f37b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt @@ -35,7 +35,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -45,6 +44,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.SmallBorder @@ -81,7 +81,7 @@ fun RenderClassifieds( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index 5b1cf183c7..99c355e377 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.distinctUntilChanged @@ -66,6 +65,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.JoinCommunityButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.LeaveCommunityButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.NormalTimeAgo +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.HeaderPictureModifier import com.vitorpamplona.amethyst.ui.theme.RowColSpacing @@ -118,7 +118,7 @@ fun LongCommunityHeader( Row( lineModifier, ) { - val rulesLabel = stringResource(id = R.string.rules) + val rulesLabel = stringRes(id = R.string.rules) val summary = remember(noteState) { val subject = noteEvent.subject()?.ifEmpty { null } @@ -148,7 +148,7 @@ fun LongCommunityHeader( val background = remember { mutableStateOf(defaultBackground) } TranslatableRichTextViewer( - content = summary ?: stringResource(id = R.string.community_no_descriptor), + content = summary ?: stringRes(id = R.string.community_no_descriptor), canPreview = false, quotesLeft = 1, tags = EmptyTagList, @@ -181,7 +181,7 @@ fun LongCommunityHeader( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(id = R.string.owner), + text = stringRes(id = R.string.owner), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.width(75.dp), @@ -238,7 +238,7 @@ fun LongCommunityHeader( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(id = R.string.created_at), + text = stringRes(id = R.string.created_at), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.width(75.dp), @@ -264,7 +264,7 @@ fun ShortCommunityHeader( RobohashFallbackAsyncImage( robot = baseNote.idHex, model = it, - contentDescription = stringResource(R.string.profile_image), + contentDescription = stringRes(R.string.profile_image), contentScale = ContentScale.Crop, modifier = HeaderPictureModifier, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt index e4a0a6b62b..53d701fd1c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt @@ -38,7 +38,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R @@ -51,6 +50,7 @@ import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.QuoteBorder @@ -105,7 +105,7 @@ private fun RenderShortRepositoryHeader( ) { val title = remember(noteEvent) { noteEvent.name() ?: noteEvent.dTag() } Text( - text = stringResource(id = R.string.git_repository, title), + text = stringRes(id = R.string.git_repository, title), style = MaterialTheme.typography.titleLarge, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -338,7 +338,7 @@ private fun RenderGitRepositoryEvent( ) { Column { Text( - text = stringResource(id = R.string.git_repository, title), + text = stringRes(id = R.string.git_repository, title), style = MaterialTheme.typography.titleMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -359,7 +359,7 @@ private fun RenderGitRepositoryEvent( web?.let { Row(Modifier.fillMaxWidth().padding(top = Size5dp)) { Text( - text = stringResource(id = R.string.git_web_address), + text = stringRes(id = R.string.git_web_address), maxLines = 1, overflow = TextOverflow.Ellipsis, ) @@ -374,7 +374,7 @@ private fun RenderGitRepositoryEvent( clone?.let { Row(Modifier.fillMaxWidth().padding(top = Size5dp)) { Text( - text = stringResource(id = R.string.git_clone_address), + text = stringRes(id = R.string.git_clone_address), maxLines = 1, overflow = TextOverflow.Ellipsis, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt index eb379995cf..6d0a16f351 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt @@ -38,7 +38,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -55,6 +54,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.CheckIfUrlIsOnline import com.vitorpamplona.amethyst.ui.screen.loggedIn.CrossfadeCheckIfUrlIsOnline import com.vitorpamplona.amethyst.ui.screen.loggedIn.LiveFlag import com.vitorpamplona.amethyst.ui.screen.loggedIn.ScheduledFlag +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.LiveActivitiesEvent @@ -171,7 +171,7 @@ fun RenderLiveActivityEventInner( .height(100.dp), ) { Text( - text = stringResource(id = R.string.live_stream_is_offline), + text = stringRes(id = R.string.live_stream_is_offline), color = MaterialTheme.colorScheme.onBackground, fontWeight = FontWeight.Bold, ) @@ -187,7 +187,7 @@ fun RenderLiveActivityEventInner( .height(100.dp), ) { Text( - text = stringResource(id = R.string.live_stream_has_ended), + text = stringRes(id = R.string.live_stream_has_ended), color = MaterialTheme.colorScheme.onBackground, fontWeight = FontWeight.Bold, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt index e0f3eceac4..414b201036 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt @@ -26,7 +26,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.State -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt index df493c64c7..b62266f97a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil.compose.AsyncImage @@ -41,6 +40,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -90,7 +90,7 @@ private fun LongFormHeader( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt index 69cf512f77..a9b660371c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt @@ -32,7 +32,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R @@ -44,6 +43,7 @@ import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomHeader +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.replyModifier @@ -128,7 +128,7 @@ fun RenderPrivateMessage( val recipient = noteEvent.recipientPubKeyBytes()?.toNpub() ?: "Someone" TranslatableRichTextViewer( - stringResource( + stringRes( id = R.string.private_conversation_notification, "@${note.author?.pubkeyNpub()}", "@$recipient", diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt index c3bc3621b3..79bf456d7b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -39,6 +38,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.replyModifier import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent @@ -68,7 +68,7 @@ fun RenderPostApproval( } Text( - text = stringResource(id = R.string.community_approved_posts), + text = stringRes(id = R.string.community_approved_posts), fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt index 1de1b59f60..01b0f1beb5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt @@ -26,12 +26,12 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.replyModifier import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.ReportEvent @@ -52,21 +52,25 @@ fun RenderReport( base .map { when (it.reportType) { - ReportEvent.ReportType.EXPLICIT -> stringResource(R.string.explicit_content) - ReportEvent.ReportType.NUDITY -> stringResource(R.string.nudity) - ReportEvent.ReportType.PROFANITY -> stringResource(R.string.profanity_hateful_speech) - ReportEvent.ReportType.SPAM -> stringResource(R.string.spam) - ReportEvent.ReportType.IMPERSONATION -> stringResource(R.string.impersonation) - ReportEvent.ReportType.ILLEGAL -> stringResource(R.string.illegal_behavior) - ReportEvent.ReportType.OTHER -> stringResource(R.string.other) + ReportEvent.ReportType.EXPLICIT -> stringRes(R.string.explicit_content) + ReportEvent.ReportType.NUDITY -> stringRes(R.string.nudity) + ReportEvent.ReportType.PROFANITY -> stringRes(R.string.profanity_hateful_speech) + ReportEvent.ReportType.SPAM -> stringRes(R.string.spam) + ReportEvent.ReportType.IMPERSONATION -> stringRes(R.string.impersonation) + ReportEvent.ReportType.ILLEGAL -> stringRes(R.string.illegal_behavior) + ReportEvent.ReportType.OTHER -> stringRes(R.string.other) } - } - .toSet() + }.toSet() .joinToString(", ") val content = remember { - reportType + (note.event?.content()?.ifBlank { null }?.let { ": $it" } ?: "") + reportType + ( + note.event + ?.content() + ?.ifBlank { null } + ?.let { ": $it" } ?: "" + ) } TranslatableRichTextViewer( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt index b231681116..a83e6e20a9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp @@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.NoteBody import com.vitorpamplona.amethyst.ui.note.observeEdits import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.imageModifier @@ -100,7 +100,7 @@ fun RenderTextModificationEvent( ) { Column(Modifier.fillMaxWidth().padding(Size10dp)) { Text( - text = stringResource(id = R.string.proposal_to_edit), + text = stringRes(id = R.string.proposal_to_edit), style = TextStyle( fontSize = 18.sp, @@ -170,7 +170,8 @@ fun RenderTextModificationEvent( Column( modifier = - MaterialTheme.colorScheme.innerPostModifier.padding(Size10dp) + MaterialTheme.colorScheme.innerPostModifier + .padding(Size10dp) .clickable { routeFor( baseNote, @@ -215,7 +216,7 @@ fun RenderTextModificationEvent( onClick = { wantsToEditPost.value = true }, modifier = Modifier.fillMaxWidth(), ) { - Text(text = stringResource(id = R.string.accept_the_suggestion)) + Text(text = stringRes(id = R.string.accept_the_suggestion)) } } } @@ -223,7 +224,7 @@ fun RenderTextModificationEvent( } @Stable -class EditState() { +class EditState { private var modificationsList: List = persistentListOf() private var modificationToShowIndex: Int = -1 diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt index 79f1ef6963..080aca811b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt @@ -37,7 +37,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.imageModifier import com.vitorpamplona.quartz.events.EmptyTagList import com.vitorpamplona.quartz.events.VideoEvent @@ -131,7 +131,7 @@ fun VideoDisplay( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt index b40c18193b..fc462e94f6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil.compose.AsyncImage @@ -42,6 +41,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -93,7 +93,7 @@ private fun WikiNoteHeader( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt index f79e090995..8f18de38c7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/QrCodeScanner.kt @@ -24,11 +24,11 @@ import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.ui.res.stringResource import com.google.zxing.client.android.Intents import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.uriToRoute import kotlinx.coroutines.CancellationException @@ -60,7 +60,7 @@ fun SimpleQrCodeScanner(onScan: (String?) -> Unit) { val scanOptions = ScanOptions().apply { setDesiredBarcodeFormats(ScanOptions.QR_CODE) - setPrompt(stringResource(id = R.string.point_to_the_qr_code)) + setPrompt(stringRes(id = R.string.point_to_the_qr_code)) setBeepEnabled(false) setOrientationLocked(false) addExtra(Intents.Scan.SCAN_TYPE, Intents.Scan.MIXED_SCAN) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt index 3b02eadde0..981efabe25 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/qrcode/ShowQRDialog.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.qrcode -import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -45,7 +44,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -57,6 +55,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.quartz.events.UserMetadata @@ -120,7 +119,7 @@ fun ShowQRDialog( RobohashFallbackAsyncImage( robot = user.pubkeyHex, model = user.profilePicture(), - contentDescription = stringResource(R.string.profile_image), + contentDescription = stringRes(R.string.profile_image), modifier = Modifier .width(100.dp) @@ -161,7 +160,7 @@ fun ShowQRDialog( containerColor = MaterialTheme.colorScheme.primary, ), ) { - Text(text = stringResource(R.string.scan_qr)) + Text(text = stringRes(R.string.scan_qr)) } } } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt index 7a9dd2bc67..0d1aa111b7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt @@ -41,7 +41,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.ViewModelStore @@ -57,6 +56,7 @@ import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.MainScreen import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginOrSignupScreen +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.signers.NostrSignerExternal import kotlinx.coroutines.CancellationException @@ -149,7 +149,10 @@ fun LoggedInPage( ) } else { result.data?.let { - accountViewModel.runOnIO { accountViewModel.account.signer.launcher.newResult(it) } + accountViewModel.runOnIO { + accountViewModel.account.signer.launcher + .newResult(it) + } } } }, @@ -196,7 +199,8 @@ fun LoggedInPage( contentResolver = { Amethyst.instance.contentResolver }, ) onDispose { - accountViewModel.account.signer.launcher.clearLauncher() + accountViewModel.account.signer.launcher + .clearLauncher() lifeCycleOwner.lifecycle.removeObserver(observer) } } @@ -205,7 +209,9 @@ fun LoggedInPage( MainScreen(accountViewModel, accountStateViewModel, sharedPreferencesViewModel) } -class AccountCentricViewModelStore(val account: Account) : ViewModelStoreOwner { +class AccountCentricViewModelStore( + val account: Account, +) : ViewModelStoreOwner { override val viewModelStore = ViewModelStore() } @@ -216,6 +222,6 @@ fun LoadingAccounts() { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text(stringResource(R.string.loading_account)) + Text(stringRes(R.string.loading_account)) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt index 200ba6a4fd..fba5655849 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt @@ -51,12 +51,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer @@ -259,7 +259,7 @@ fun LoadingFeed() { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text(stringResource(R.string.loading_feed)) + Text(stringRes(R.string.loading_feed)) } } @@ -273,13 +273,13 @@ fun FeedError( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text("${stringResource(R.string.error_loading_replies)} $errorMessage") + Text("${stringRes(R.string.error_loading_replies)} $errorMessage") Spacer(modifier = StdVertSpacer) Button( modifier = Modifier.align(Alignment.CenterHorizontally), onClick = onRefresh, ) { - Text(text = stringResource(R.string.try_again)) + Text(text = stringRes(R.string.try_again)) } } } @@ -291,8 +291,8 @@ fun FeedEmpty(onRefresh: () -> Unit) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text(stringResource(R.string.feed_is_empty)) + Text(stringRes(R.string.feed_is_empty)) Spacer(modifier = StdVertSpacer) - OutlinedButton(onClick = onRefresh) { Text(text = stringResource(R.string.refresh)) } + OutlinedButton(onClick = onRefresh) { Text(text = stringRes(R.string.refresh)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt index 931352ac67..d35ba75c4b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/StringFeedView.kt @@ -34,11 +34,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding @@ -84,8 +84,8 @@ fun StringFeedEmpty( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text(stringResource(R.string.feed_is_empty)) - OutlinedButton(onClick = onRefresh) { Text(text = stringResource(R.string.refresh)) } + Text(stringRes(R.string.feed_is_empty)) + OutlinedButton(onClick = onRefresh) { Text(text = stringRes(R.string.refresh)) } } post?.let { it() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index c0e5fe1cf8..f63b2fcdff 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -59,7 +59,6 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization @@ -136,6 +135,7 @@ import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.ThinSendButton +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.EditFieldBorder @@ -734,14 +734,14 @@ private fun RenderClassifiedsReaderForThread( ) { Icon( painter = painterResource(R.drawable.ic_dm), - stringResource(R.string.send_a_direct_message), + stringRes(R.string.send_a_direct_message), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.primary, ) Spacer(modifier = StdHorzSpacer) - Text(stringResource(id = R.string.send_the_seller_a_message)) + Text(stringRes(id = R.string.send_the_seller_a_message)) } Row( @@ -756,12 +756,12 @@ private fun RenderClassifiedsReaderForThread( val msg = if (sellerName != null) { - stringResource( + stringRes( id = R.string.hi_seller_is_this_still_available, sellerName, ) } else { - stringResource(id = R.string.hi_there_is_this_still_available) + stringRes(id = R.string.hi_there_is_this_still_available) } var message by remember { mutableStateOf(TextFieldValue(msg)) } @@ -778,7 +778,7 @@ private fun RenderClassifiedsReaderForThread( modifier = Modifier.weight(1f, true), placeholder = { Text( - text = stringResource(R.string.reply_here), + text = stringRes(R.string.reply_here), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -813,7 +813,7 @@ private fun RenderLongFormHeaderForThread(noteEvent: LongTextNoteEvent) { AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), @@ -904,7 +904,7 @@ private fun RenderWikiHeaderForThread( AsyncImage( model = it, contentDescription = - stringResource( + stringRes( R.string.preview_card_image_for, it, ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt index 8e3b745651..8021d6965b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountBackupDialog.kt @@ -72,7 +72,6 @@ import androidx.compose.ui.platform.LocalAutofill import androidx.compose.ui.platform.LocalAutofillTree import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType @@ -93,6 +92,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.note.authenticate +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -143,7 +143,7 @@ fun AccountBackupDialog( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - val content1 = stringResource(R.string.account_backup_tips2_md) + val content1 = stringRes(R.string.account_backup_tips2_md) val astNode1 = remember { @@ -163,7 +163,7 @@ fun AccountBackupDialog( Spacer(modifier = Modifier.height(30.dp)) - val content = stringResource(R.string.account_backup_tips3_md) + val content = stringRes(R.string.account_backup_tips3_md) val astNode = remember { @@ -196,8 +196,7 @@ fun AccountBackupDialog( Modifier .onGloballyPositioned { coordinates -> autofillNode.boundingBox = coordinates.boundsInWindow() - } - .onFocusChanged { focusState -> + }.onFocusChanged { focusState -> autofill?.run { if (focusState.isFocused) { requestAutofillForNode(autofillNode) @@ -221,7 +220,7 @@ fun AccountBackupDialog( ), placeholder = { Text( - text = stringResource(R.string.ncryptsec_password), + text = stringRes(R.string.ncryptsec_password), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -233,9 +232,9 @@ fun AccountBackupDialog( if (showCharsPassword) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility, contentDescription = if (showCharsPassword) { - stringResource(R.string.show_password) + stringRes(R.string.show_password) } else { - stringResource( + stringRes( R.string.hide_password, ) }, @@ -271,8 +270,7 @@ private fun NSecCopyButton(accountViewModel: AccountViewModel) { val scope = rememberCoroutineScope() val keyguardLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { - result: ActivityResult -> + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Activity.RESULT_OK) { copyNSec(context, scope, accountViewModel.account, clipboardManager) } @@ -282,7 +280,7 @@ private fun NSecCopyButton(accountViewModel: AccountViewModel) { modifier = Modifier.padding(horizontal = 3.dp), onClick = { authenticate( - title = context.getString(R.string.copy_my_secret_key), + title = stringRes(context, R.string.copy_my_secret_key), context = context, keyguardLauncher = keyguardLauncher, onApproved = { copyNSec(context, scope, accountViewModel.account, clipboardManager) }, @@ -300,11 +298,11 @@ private fun NSecCopyButton(accountViewModel: AccountViewModel) { tint = MaterialTheme.colorScheme.onPrimary, imageVector = Icons.Default.Key, contentDescription = - stringResource(R.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup), + stringRes(R.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup), modifier = Modifier.padding(end = 5.dp), ) Text( - stringResource(id = R.string.copy_my_secret_key), + stringRes(id = R.string.copy_my_secret_key), color = MaterialTheme.colorScheme.onPrimary, ) } @@ -320,8 +318,7 @@ private fun EncryptNSecCopyButton( val scope = rememberCoroutineScope() val keyguardLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { - result: ActivityResult -> + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Activity.RESULT_OK) { encryptCopyNSec(password, context, scope, accountViewModel, clipboardManager) } @@ -331,7 +328,7 @@ private fun EncryptNSecCopyButton( modifier = Modifier.padding(horizontal = 3.dp), onClick = { authenticate( - title = context.getString(R.string.copy_my_secret_key), + title = stringRes(context, R.string.copy_my_secret_key), context = context, keyguardLauncher = keyguardLauncher, onApproved = { encryptCopyNSec(password, context, scope, accountViewModel, clipboardManager) }, @@ -345,11 +342,11 @@ private fun EncryptNSecCopyButton( Icon( imageVector = Icons.Default.Key, contentDescription = - stringResource(R.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup), + stringRes(R.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup), modifier = Modifier.padding(end = 5.dp), ) Text( - stringResource(id = R.string.encrypt_and_copy_my_secret_key), + stringRes(id = R.string.encrypt_and_copy_my_secret_key), ) } } @@ -374,12 +371,12 @@ private fun copyNSec( account.keyPair.privKey?.let { clipboardManager.setText(AnnotatedString(it.toNsec())) scope.launch { - Toast.makeText( - context, - context.getString(R.string.secret_key_copied_to_clipboard), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + stringRes(context, R.string.secret_key_copied_to_clipboard), + Toast.LENGTH_SHORT, + ).show() } } } @@ -393,12 +390,12 @@ private fun encryptCopyNSec( ) { if (password.value.text.isBlank()) { scope.launch { - Toast.makeText( - context, - context.getString(R.string.password_is_required), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + stringRes(context, R.string.password_is_required), + Toast.LENGTH_SHORT, + ).show() } } else { accountViewModel.account.keyPair.privKey?.let { @@ -406,21 +403,21 @@ private fun encryptCopyNSec( if (key != null) { clipboardManager.setText(AnnotatedString(key)) scope.launch { - Toast.makeText( - context, - context.getString(R.string.secret_key_copied_to_clipboard), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + stringRes(context, R.string.secret_key_copied_to_clipboard), + Toast.LENGTH_SHORT, + ).show() } } else { scope.launch { - Toast.makeText( - context, - context.getString(R.string.failed_to_encrypt_key), - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + context, + stringRes(context, R.string.failed_to_encrypt_key), + Toast.LENGTH_SHORT, + ).show() } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 294300cf0d..23371bf3c1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -69,6 +69,7 @@ import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.amethyst.ui.screen.CombinedZap import com.vitorpamplona.amethyst.ui.screen.SettingsState +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.Nip11RelayInformation @@ -110,7 +111,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combineTransform -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.joinAll @@ -1303,8 +1303,9 @@ class AccountViewModel( } } else { onDone( - context.getString(R.string.no_lightning_address_set), - context.getString( + stringRes(context, R.string.no_lightning_address_set), + stringRes( + context, R.string.user_x_does_not_have_a_lightning_address_setup_to_receive_sats, account.userProfile().toBestDisplayName(), ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt index cfdda33048..824a17ba6e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BookmarkListScreen.kt @@ -36,12 +36,12 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.NostrBookmarkPrivateFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrBookmarkPublicFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.TabRowHeight import kotlinx.coroutines.launch @@ -93,12 +93,12 @@ private fun RenderBookmarkScreen( Tab( selected = pagerState.currentPage == 0, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } }, - text = { Text(text = stringResource(R.string.private_bookmarks)) }, + text = { Text(text = stringRes(R.string.private_bookmarks)) }, ) Tab( selected = pagerState.currentPage == 1, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } }, - text = { Text(text = stringResource(R.string.public_bookmarks)) }, + text = { Text(text = stringRes(R.string.public_bookmarks)) }, ) } HorizontalPager(state = pagerState) { page -> diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 4fc7151aa0..2052fe115b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -84,7 +84,6 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight @@ -138,6 +137,7 @@ import com.vitorpamplona.amethyst.ui.note.timeAgoShort import com.vitorpamplona.amethyst.ui.screen.NostrChannelFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer @@ -453,7 +453,7 @@ fun EditFieldRow( modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.reply_here), + text = stringRes(R.string.reply_here), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -779,7 +779,7 @@ fun ShortChannelHeader( RobohashFallbackAsyncImage( robot = channel.idHex, model = it, - contentDescription = stringResource(R.string.profile_image), + contentDescription = stringRes(R.string.profile_image), contentScale = ContentScale.Crop, modifier = HeaderPictureModifier, loadProfilePicture = accountViewModel.settings.showProfilePictures.value, @@ -854,7 +854,7 @@ fun LongChannelHeader( } TranslatableRichTextViewer( - content = summary ?: stringResource(id = R.string.groups_no_descriptor), + content = summary ?: stringRes(id = R.string.groups_no_descriptor), canPreview = false, quotesLeft = 1, tags = tags, @@ -891,7 +891,7 @@ fun LongChannelHeader( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(id = R.string.owner), + text = stringRes(id = R.string.owner), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.width(75.dp), @@ -907,7 +907,7 @@ fun LongChannelHeader( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(id = R.string.created_at), + text = stringRes(id = R.string.created_at), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.width(75.dp), @@ -971,7 +971,7 @@ fun NormalTimeAgo( baseNote: Note, modifier: Modifier, ) { - val nowStr = stringResource(id = R.string.now) + val nowStr = stringRes(id = R.string.now) val time by remember(baseNote) { derivedStateOf { timeAgoShort(baseNote.createdAt() ?: 0, nowStr) } } @@ -1100,7 +1100,7 @@ private fun LiveChannelActionOptions( @Composable fun LiveFlag() { Text( - text = stringResource(id = R.string.live_stream_live_tag), + text = stringRes(id = R.string.live_stream_live_tag), color = Color.White, fontWeight = FontWeight.Bold, fontSize = 16.sp, @@ -1117,7 +1117,7 @@ fun LiveFlag() { @Composable fun EndedFlag() { Text( - text = stringResource(id = R.string.live_stream_ended_tag), + text = stringRes(id = R.string.live_stream_ended_tag), color = Color.White, fontWeight = FontWeight.Bold, modifier = @@ -1133,7 +1133,7 @@ fun EndedFlag() { @Composable fun OfflineFlag() { Text( - text = stringResource(id = R.string.live_stream_offline_tag), + text = stringRes(id = R.string.live_stream_offline_tag), color = Color.White, fontWeight = FontWeight.Bold, modifier = @@ -1158,7 +1158,7 @@ fun ScheduledFlag(starts: Long?) { } Text( - text = startsIn ?: stringResource(id = R.string.live_stream_planned_tag), + text = startsIn ?: stringRes(id = R.string.live_stream_planned_tag), color = Color.White, fontWeight = FontWeight.Bold, modifier = liveStreamTag, @@ -1184,7 +1184,7 @@ private fun NoteCopyButton(note: Channel) { Icon( tint = Color.White, imageVector = Icons.Default.Share, - contentDescription = stringResource(R.string.copies_the_note_id_to_the_clipboard_for_sharing), + contentDescription = stringRes(R.string.copies_the_note_id_to_the_clipboard_for_sharing), ) DropdownMenu( @@ -1194,7 +1194,7 @@ private fun NoteCopyButton(note: Channel) { val clipboardManager = LocalClipboardManager.current DropdownMenuItem( - text = { Text(stringResource(R.string.copy_channel_id_note_to_the_clipboard)) }, + text = { Text(stringRes(R.string.copy_channel_id_note_to_the_clipboard)) }, onClick = { clipboardManager.setText(AnnotatedString("nostr:" + note.idNote())) popupExpanded = false @@ -1226,7 +1226,7 @@ private fun EditButton( Icon( tint = Color.White, imageVector = Icons.Default.EditNote, - contentDescription = stringResource(R.string.edits_the_channel_metadata), + contentDescription = stringRes(R.string.edits_the_channel_metadata), ) } } @@ -1244,7 +1244,7 @@ fun JoinChatButton( onClick = { scope.launch(Dispatchers.IO) { accountViewModel.account.follow(channel) } }, contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.join), color = Color.White) + Text(text = stringRes(R.string.join), color = Color.White) } } @@ -1261,7 +1261,7 @@ fun LeaveChatButton( onClick = { scope.launch(Dispatchers.IO) { accountViewModel.account.unfollow(channel) } }, contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.leave), color = Color.White) + Text(text = stringRes(R.string.leave), color = Color.White) } } @@ -1283,7 +1283,7 @@ fun JoinCommunityButton( ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.join), color = Color.White) + Text(text = stringRes(R.string.join), color = Color.White) } } @@ -1305,6 +1305,6 @@ fun LeaveCommunityButton( ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.leave), color = Color.White) + Text(text = stringRes(R.string.leave), color = Color.White) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt index 8b010ec6e4..290f9b8c1c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt @@ -58,7 +58,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver @@ -72,6 +71,7 @@ import com.vitorpamplona.amethyst.ui.screen.ChatroomListFeedView import com.vitorpamplona.amethyst.ui.screen.FeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.TabRowHeight @@ -118,7 +118,10 @@ fun ChatroomListScreen( } } -data class RouteId(val route: String, val id: String) +data class RouteId( + val route: String, + val id: String, +) @Composable fun ChatroomListTwoPane( @@ -171,7 +174,8 @@ fun ChatroomListTwoPane( } HorizontalDivider( modifier = - Modifier.fillMaxHeight() // fill the max height + Modifier + .fillMaxHeight() // fill the max height .width(DividerThickness), ) } @@ -256,7 +260,7 @@ fun ChatroomListScreenOnlyList( tabs.forEachIndexed { index, tab -> Tab( selected = pagerState.currentPage == index, - text = { Text(text = stringResource(tab.resource)) }, + text = { Text(text = stringRes(tab.resource)) }, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } }, ) } @@ -268,7 +272,7 @@ fun ChatroomListScreenOnlyList( ) { Icon( imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(id = R.string.more_options), + contentDescription = stringRes(id = R.string.more_options), tint = MaterialTheme.colorScheme.placeholderText, ) @@ -327,21 +331,21 @@ fun ChatroomTabMenu( ) { DropdownMenu(expanded = expanded, onDismissRequest = onDismiss) { DropdownMenuItem( - text = { Text(stringResource(R.string.mark_all_known_as_read)) }, + text = { Text(stringRes(R.string.mark_all_known_as_read)) }, onClick = { onMarkKnownAsRead() onDismiss() }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.mark_all_new_as_read)) }, + text = { Text(stringRes(R.string.mark_all_new_as_read)) }, onClick = { onMarkNewAsRead() onDismiss() }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.mark_all_as_read)) }, + text = { Text(stringRes(R.string.mark_all_as_read)) }, onClick = { onMarkKnownAsRead() onMarkNewAsRead() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index c8df0f6525..8ebe5a13d0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -68,7 +68,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.TextFieldValue @@ -108,6 +107,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.ObserveRelayListForDMs import com.vitorpamplona.amethyst.ui.note.elements.ObserveRelayListForDMsAndDisplayIfNotFound import com.vitorpamplona.amethyst.ui.screen.NostrChatroomFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefreshingChatroomFeedView +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.EditFieldBorder import com.vitorpamplona.amethyst.ui.theme.EditFieldModifier @@ -118,7 +118,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size34dp import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.ZeroPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import com.vitorpamplona.quartz.events.ChatMessageEvent import com.vitorpamplona.quartz.events.ChatroomKey import com.vitorpamplona.quartz.events.findURLs @@ -426,7 +425,7 @@ fun PrivateMessageEditFieldRow( modifier = Modifier.fillMaxWidth(), placeholder = { Text( - text = stringResource(R.string.reply_here), + text = stringRes(R.string.reply_here), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -553,10 +552,10 @@ fun NewFeatureNIP17AlertDialog( val scope = rememberCoroutineScope() QuickActionAlertDialog( - title = stringResource(R.string.new_feature_nip17_might_not_be_available_title), - textContent = stringResource(R.string.new_feature_nip17_might_not_be_available_description), + title = stringRes(R.string.new_feature_nip17_might_not_be_available_title), + textContent = stringRes(R.string.new_feature_nip17_might_not_be_available_description), buttonIconResource = R.drawable.incognito, - buttonText = stringResource(R.string.new_feature_nip17_activate), + buttonText = stringRes(R.string.new_feature_nip17_activate), onClickDoOnce = { scope.launch(Dispatchers.IO) { onConfirm() } onDismiss() @@ -585,7 +584,7 @@ fun ThinSendButton( ) { Icon( imageVector = Icons.Default.Send, - contentDescription = stringResource(id = R.string.accessibility_send), + contentDescription = stringRes(id = R.string.accessibility_send), modifier = Size20Modifier, ) } @@ -708,7 +707,7 @@ private fun EditRoomSubjectButton( Icon( tint = Color.White, imageVector = Icons.Default.EditNote, - contentDescription = stringResource(R.string.edits_the_channel_metadata), + contentDescription = stringRes(R.string.edits_the_channel_metadata), ) } } @@ -769,13 +768,13 @@ fun NewSubjectView( Spacer(modifier = Modifier.height(15.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.messages_new_message_subject)) }, + label = { Text(text = stringRes(R.string.messages_new_message_subject)) }, modifier = Modifier.fillMaxWidth(), value = groupName.value, onValueChange = { groupName.value = it }, placeholder = { Text( - text = stringResource(R.string.messages_new_message_subject_caption), + text = stringRes(R.string.messages_new_message_subject_caption), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -789,7 +788,7 @@ fun NewSubjectView( Spacer(modifier = Modifier.height(15.dp)) OutlinedTextField( - label = { Text(text = stringResource(R.string.messages_new_subject_message)) }, + label = { Text(text = stringRes(R.string.messages_new_subject_message)) }, modifier = Modifier .fillMaxWidth() @@ -798,7 +797,7 @@ fun NewSubjectView( onValueChange = { message.value = it }, placeholder = { Text( - text = stringResource(R.string.messages_new_subject_message_placeholder), + text = stringRes(R.string.messages_new_subject_message_placeholder), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -829,7 +828,7 @@ fun LongRoomHeader( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(id = R.string.messages_group_descriptor), + text = stringRes(id = R.string.messages_group_descriptor), fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -862,31 +861,6 @@ fun LongRoomHeader( } } -@Composable -fun DMRelayLine( - baseUser: User, - accountViewModel: AccountViewModel, -) { - ObserveRelayListForDMs(pubkey = baseUser.pubkeyHex, accountViewModel = accountViewModel) { - val relayList = it?.relays() - if (relayList.isNullOrEmpty()) { - Text( - text = stringResource(id = R.string.dm_relays_regular), - color = MaterialTheme.colorScheme.placeholderText, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } else { - Text( - text = stringResource(id = R.string.dm_relays_through, relayList.joinToString(", ") { RelayUrlFormatter.displayUrl(it) }), - color = MaterialTheme.colorScheme.placeholderText, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } - } -} - @Composable fun RoomNameOnlyDisplay( room: ChatroomKey, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt index 0aa0ebf056..9f57100379 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt @@ -40,7 +40,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -54,6 +53,7 @@ import com.halilibo.richtext.markdown.BasicMarkdown import com.halilibo.richtext.ui.material3.RichText import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.actions.CloseButton +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.RichTextDefaults import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -81,7 +81,7 @@ fun ConnectOrbotDialog( ) { CloseButton(onPress = { onClose() }) - val toastMessage = stringResource(R.string.invalid_port_number) + val toastMessage = stringRes(R.string.invalid_port_number) UseOrbotButton( onPost = { @@ -115,7 +115,7 @@ fun ConnectOrbotDialog( ) Row { - val content1 = stringResource(R.string.connect_through_your_orbot_setup_markdown) + val content1 = stringRes(R.string.connect_through_your_orbot_setup_markdown) val astNode1 = remember { @@ -144,7 +144,7 @@ fun ConnectOrbotDialog( capitalization = KeyboardCapitalization.None, keyboardType = KeyboardType.Number, ), - label = { Text(text = stringResource(R.string.orbot_socks_port)) }, + label = { Text(text = stringRes(R.string.orbot_socks_port)) }, placeholder = { Text( text = "9050", @@ -178,6 +178,6 @@ fun UseOrbotButton( containerColor = if (isActive) MaterialTheme.colorScheme.primary else Color.Gray, ), ) { - Text(text = stringResource(R.string.use_orbot), color = Color.White) + Text(text = stringRes(R.string.use_orbot), color = Color.White) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt index cbe5c710da..250eca54f2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DiscoverScreen.kt @@ -51,7 +51,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver @@ -77,6 +76,7 @@ import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState import com.vitorpamplona.amethyst.ui.screen.SaveableGridFeedState import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.TabRowHeight @@ -203,7 +203,7 @@ private fun DiscoverPages( tabs.forEachIndexed { index, tab -> Tab( selected = pagerState.currentPage == index, - text = { Text(text = stringResource(tab.resource)) }, + text = { Text(text = stringRes(tab.resource)) }, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } }, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt index 492ec612e2..0a502c6665 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DraftListScreen.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt index 725154bbdc..4063ceef19 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt @@ -35,7 +35,6 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner @@ -182,7 +181,11 @@ fun GeoHashActionOptions( tag: String, accountViewModel: AccountViewModel, ) { - val userState by accountViewModel.userProfile().live().follows.observeAsState() + val userState by accountViewModel + .userProfile() + .live() + .follows + .observeAsState() val isFollowingTag by remember(userState) { derivedStateOf { userState?.user?.isFollowingGeohashCached(tag) ?: false } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt index 929ddbbd5e..d6392e561c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HiddenUsersScreen.kt @@ -55,7 +55,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardCapitalization @@ -75,6 +74,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrSpammerAccountsFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableBox import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView import com.vitorpamplona.amethyst.ui.screen.StringFeedView +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.DividerThickness @@ -162,7 +162,7 @@ fun HiddenUsersScreen( }, ) - Text(stringResource(R.string.warn_when_posts_have_reports_from_your_follows)) + Text(stringRes(R.string.warn_when_posts_have_reports_from_your_follows)) } Row(verticalAlignment = Alignment.CenterVertically) { @@ -174,7 +174,7 @@ fun HiddenUsersScreen( }, ) - Text(stringResource(R.string.filter_spam_from_strangers)) + Text(stringRes(R.string.filter_spam_from_strangers)) } ScrollableTabRow( @@ -188,17 +188,17 @@ fun HiddenUsersScreen( Tab( selected = pagerState.currentPage == 0, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } }, - text = { Text(text = stringResource(R.string.blocked_users)) }, + text = { Text(text = stringRes(R.string.blocked_users)) }, ) Tab( selected = pagerState.currentPage == 1, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } }, - text = { Text(text = stringResource(R.string.spamming_users)) }, + text = { Text(text = stringRes(R.string.spamming_users)) }, ) Tab( selected = pagerState.currentPage == 2, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(2) } }, - text = { Text(text = stringResource(R.string.hidden_words)) }, + text = { Text(text = stringRes(R.string.hidden_words)) }, ) } HorizontalPager(state = pagerState) { page -> @@ -236,11 +236,11 @@ private fun AddMuteWordTextField(accountViewModel: AccountViewModel) { OutlinedTextField( value = currentWordToAdd.value, onValueChange = { currentWordToAdd.value = it }, - label = { Text(text = stringResource(R.string.hide_new_word_label)) }, + label = { Text(text = stringRes(R.string.hide_new_word_label)) }, modifier = Modifier.fillMaxWidth().padding(10.dp), placeholder = { Text( - text = stringResource(R.string.hide_new_word_label), + text = stringRes(R.string.hide_new_word_label), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -354,7 +354,7 @@ fun HideWordButton(onClick: () -> Unit) { ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.block_only), color = Color.White) + Text(text = stringRes(R.string.block_only), color = Color.White) } } @@ -373,7 +373,7 @@ fun ShowWordButton( ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(text), color = Color.White, textAlign = TextAlign.Center) + Text(text = stringRes(text), color = Color.White, textAlign = TextAlign.Center) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt index 4578a27fd0..a1017655e1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver @@ -66,6 +65,7 @@ import com.vitorpamplona.amethyst.ui.screen.RenderFeedState import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow @@ -118,8 +118,7 @@ private fun AssembleHomeTabs( Route.Home.base + "FollowsReplies", ScrollStateKeys.HOME_REPLIES, ), - ) - .toImmutableList(), + ).toImmutableList(), ) } @@ -185,7 +184,7 @@ private fun HomePages( tabs.forEachIndexed { index, tab -> Tab( selected = pagerState.currentPage == index, - text = { Text(text = stringResource(tab.resource)) }, + text = { Text(text = stringRes(tab.resource)) }, onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } }, ) } @@ -240,9 +239,9 @@ fun HomeFeedEmpty(onRefresh: () -> Unit) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text(stringResource(R.string.feed_is_empty)) + Text(stringRes(R.string.feed_is_empty)) Spacer(modifier = StdVertSpacer) - OutlinedButton(onClick = onRefresh) { Text(text = stringResource(R.string.refresh)) } + OutlinedButton(onClick = onRefresh) { Text(text = stringRes(R.string.refresh)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt index 51143cfc32..3ef9c16504 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoadRedirectScreen.kt @@ -36,13 +36,13 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.navigation.Route +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.events.ChannelCreateEvent import com.vitorpamplona.quartz.events.ChatroomKeyable import com.vitorpamplona.quartz.events.EventInterface @@ -113,7 +113,7 @@ fun LoadRedirectScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Text(stringResource(R.string.looking_for_event, baseNote.idHex)) + Text(stringRes(R.string.looking_for_event, baseNote.idHex)) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt index 3b4b2ae6a5..e1deea68b3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt @@ -64,10 +64,8 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver @@ -109,6 +107,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.encoders.RelayUrlFormatter import kotlinx.coroutines.launch import kotlin.math.abs @@ -529,7 +528,6 @@ val bottomBarAnimation: ContentTransform = @Composable private fun DisplayErrorMessages(accountViewModel: AccountViewModel) { - val context = LocalContext.current val openDialogMsg = accountViewModel.toasts.collectAsStateWithLifecycle(null) openDialogMsg.value?.let { obj -> @@ -537,15 +535,15 @@ private fun DisplayErrorMessages(accountViewModel: AccountViewModel) { is ResourceToastMsg -> if (obj.params != null) { InformationDialog( - context.getString(obj.titleResId), - context.getString(obj.resourceId, *obj.params), + stringRes(obj.titleResId), + stringRes(obj.resourceId, *obj.params), ) { accountViewModel.clearToasts() } } else { InformationDialog( - context.getString(obj.titleResId), - context.getString(obj.resourceId), + stringRes(obj.titleResId), + stringRes(obj.resourceId), ) { accountViewModel.clearToasts() } @@ -573,7 +571,7 @@ private fun DisplayNotifyMessages( openDialogMsg.value?.firstOrNull()?.let { request -> NotifyRequestDialog( title = - stringResource( + stringRes( id = R.string.payment_required_title, RelayUrlFormatter.displayUrl(request.relayUrl), ), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt index e4927c220e..f5f1e09d3e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt @@ -50,7 +50,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -84,6 +83,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrNIP90ContentDiscoveryFeedViewMo import com.vitorpamplona.amethyst.ui.screen.RefresheableBox import com.vitorpamplona.amethyst.ui.screen.RenderFeedState import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp import com.vitorpamplona.amethyst.ui.theme.QuoteBorder @@ -115,7 +115,7 @@ fun NIP90ContentDiscoveryScreen( NIP90ContentDiscoveryScreen(baseNote, accountViewModel, nav) }, onBlank = { - FeedEmptyWithStatus(baseNote, stringResource(R.string.dvm_looking_for_app), accountViewModel, nav) + FeedEmptyWithStatus(baseNote, stringRes(R.string.dvm_looking_for_app), accountViewModel, nav) }, accountViewModel, ) @@ -166,7 +166,7 @@ fun NIP90ContentDiscoveryScreen( } else { // TODO: Make a good splash screen with loading animation for this DVM. // FeedDVM(appDefinition, null, accountViewModel, nav) - FeedEmptyWithStatus(appDefinition, stringResource(R.string.dvm_requesting_job), accountViewModel, nav) + FeedEmptyWithStatus(appDefinition, stringRes(R.string.dvm_requesting_job), accountViewModel, nav) } } } @@ -228,7 +228,7 @@ fun ObserverDvmStatusResponse( } } else { // TODO: Make a good splash screen with loading animation for this DVM. - FeedEmptyWithStatus(appDefinition, stringResource(R.string.dvm_waiting_status), accountViewModel, nav) + FeedEmptyWithStatus(appDefinition, stringRes(R.string.dvm_waiting_status), accountViewModel, nav) } } @@ -331,8 +331,8 @@ fun FeedDVM( val invoice = amountTag?.lnInvoice - val thankYou = stringResource(id = R.string.dvm_waiting_to_confirm_payment) - val nwcPaymentRequest = stringResource(id = R.string.nwc_payment_request) + val thankYou = stringRes(id = R.string.dvm_waiting_to_confirm_payment) + val nwcPaymentRequest = stringRes(id = R.string.nwc_payment_request) if (invoice != null) { val context = LocalContext.current @@ -347,7 +347,8 @@ fun FeedDVM( onResponse = { response -> currentStatus = if (response is PayInvoiceErrorResponse) { - context.getString( + stringRes( + context, R.string.wallet_connect_pay_invoice_error_error, response.error?.message ?: response.error?.code?.toString() ?: "Error parsing error message", @@ -484,7 +485,7 @@ fun ZapDVMButton( if (showErrorMessageDialog != null) { ErrorMessageDialog( - title = stringResource(id = R.string.error_dialog_zap_error), + title = stringRes(id = R.string.error_dialog_zap_error), textContent = showErrorMessageDialog ?: "", onClickStartMessage = { baseNote.author?.let { @@ -561,9 +562,9 @@ fun ZapDVMButton( } if (hasZapped) { - Text(text = stringResource(id = R.string.thank_you)) + Text(text = stringRes(id = R.string.thank_you)) } else { - Text(text = "Zap " + (amount / 1000).toString() + " sats to the DVM") // stringResource(id = R.string.donate_now)) + Text(text = "Zap " + (amount / 1000).toString() + " sats to the DVM") // stringRes(id = R.string.donate_now)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 9e42c3332d..7761117580 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.scrollBy @@ -96,7 +95,6 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -155,6 +153,7 @@ import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView import com.vitorpamplona.amethyst.ui.screen.RelayFeedView import com.vitorpamplona.amethyst.ui.screen.RelayFeedViewModel import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding @@ -569,8 +568,8 @@ private fun CreateAndRenderTabs( val tabs = listOf<@Composable (() -> Unit)?>( - { Text(text = stringResource(R.string.notes)) }, - { Text(text = stringResource(R.string.replies)) }, + { Text(text = stringRes(R.string.notes)) }, + { Text(text = stringRes(R.string.replies)) }, { FollowTabHeader(baseUser) }, { FollowersTabHeader(baseUser) }, { ZapTabHeader(baseUser) }, @@ -604,7 +603,7 @@ private fun RelaysTabHeader(baseUser: User) { ?.size ?: "--" } - Text(text = "$userRelaysBeingUsed / $userRelays ${stringResource(R.string.relays)}") + Text(text = "$userRelaysBeingUsed / $userRelays ${stringRes(R.string.relays)}") } @Composable @@ -622,7 +621,7 @@ private fun ReportsTabHeader(baseUser: User) { } } - Text(text = "$userReports ${stringResource(R.string.reports)}") + Text(text = "$userReports ${stringRes(R.string.reports)}") } @Composable @@ -635,7 +634,7 @@ private fun FollowedTagsTabHeader(baseUser: User) { } } - Text(text = "$usertags ${stringResource(R.string.followed_tags)}") + Text(text = "$usertags ${stringRes(R.string.followed_tags)}") } @Composable @@ -660,7 +659,7 @@ private fun BookmarkTabHeader(baseUser: User) { } } - Text(text = "$userBookmarks ${stringResource(R.string.bookmarks)}") + Text(text = "$userBookmarks ${stringRes(R.string.bookmarks)}") } @Composable @@ -677,7 +676,7 @@ private fun ZapTabHeader(baseUser: User) { } } - Text(text = "${showAmountAxis(zapAmount)} ${stringResource(id = R.string.zaps)}") + Text(text = "${showAmountAxis(zapAmount)} ${stringRes(id = R.string.zaps)}") } @Composable @@ -685,7 +684,7 @@ private fun FollowersTabHeader(baseUser: User) { val userState by baseUser.live().followers.observeAsState() var followerCount by remember { mutableStateOf("--") } - val text = stringResource(R.string.followers) + val text = stringRes(R.string.followers) LaunchedEffect(key1 = userState) { launch(Dispatchers.IO) { @@ -705,7 +704,7 @@ private fun FollowTabHeader(baseUser: User) { val userState by baseUser.live().follows.observeAsState() var followCount by remember { mutableStateOf("--") } - val text = stringResource(R.string.follows) + val text = stringRes(R.string.follows) LaunchedEffect(key1 = userState) { launch(Dispatchers.IO) { @@ -756,7 +755,7 @@ private fun ProfileHeader( Icon( tint = MaterialTheme.colorScheme.placeholderText, imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(R.string.more_options), + contentDescription = stringRes(R.string.more_options), ) UserProfileDropDownMenu( @@ -987,7 +986,7 @@ private fun DrawAdditionalInfo( ) { Icon( imageVector = Icons.Default.ContentCopy, - contentDescription = stringResource(id = R.string.copy_npub_to_clipboard), + contentDescription = stringRes(id = R.string.copy_npub_to_clipboard), modifier = Size15Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) @@ -1014,7 +1013,7 @@ private fun DrawAdditionalInfo( ) { Icon( painter = painterResource(R.drawable.ic_qrcode), - contentDescription = stringResource(id = R.string.show_npub_as_a_qr_code), + contentDescription = stringRes(id = R.string.show_npub_as_a_qr_code), modifier = Size15Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) @@ -1031,7 +1030,7 @@ private fun DrawAdditionalInfo( Icon( tint = MaterialTheme.colorScheme.placeholderText, imageVector = Icons.Default.Link, - contentDescription = stringResource(R.string.website), + contentDescription = stringRes(R.string.website), modifier = Modifier.size(16.dp), ) @@ -1065,7 +1064,7 @@ private fun DrawAdditionalInfo( Icon( tint = Color.Unspecified, painter = painterResource(id = getIdentityClaimIcon(identity)), - contentDescription = stringResource(getIdentityClaimDescription(identity)), + contentDescription = stringRes(getIdentityClaimDescription(identity)), modifier = Modifier.size(16.dp), ) @@ -1120,7 +1119,7 @@ fun DisplayLNAddress( if (showErrorMessageDialog != null) { ErrorMessageDialog( - title = stringResource(id = R.string.error_dialog_zap_error), + title = stringRes(id = R.string.error_dialog_zap_error), textContent = showErrorMessageDialog ?: "", onClickStartMessage = { scope.launch(Dispatchers.IO) { @@ -1135,7 +1134,7 @@ fun DisplayLNAddress( var showInfoMessageDialog by remember { mutableStateOf(null) } if (showInfoMessageDialog != null) { InformationDialog( - title = context.getString(R.string.payment_successful), + title = stringRes(context, R.string.payment_successful), textContent = showInfoMessageDialog ?: "", ) { showInfoMessageDialog = null @@ -1172,12 +1171,12 @@ fun DisplayLNAddress( if (accountViewModel.account.hasWalletConnectSetup()) { accountViewModel.account.sendZapPaymentRequestFor(it, null, onSent = {}) { response -> if (response is PayInvoiceSuccessResponse) { - showInfoMessageDialog = context.getString(R.string.payment_successful) + showInfoMessageDialog = stringRes(context, R.string.payment_successful) } else if (response is PayInvoiceErrorResponse) { showErrorMessageDialog = response.error?.message ?: response.error?.code?.toString() - ?: context.getString(R.string.error_parsing_error_message) + ?: stringRes(context, R.string.error_parsing_error_message) } } } else { @@ -1211,7 +1210,7 @@ private fun DisplayAppRecommendations( when (state) { is FeedState.Loaded -> { Column { - Text(stringResource(id = R.string.recommended_apps)) + Text(stringRes(id = R.string.recommended_apps)) FlowRow( verticalArrangement = Arrangement.Center, @@ -1410,7 +1409,7 @@ private fun WatchAndRenderBadgeImage( if (image == null) { RobohashAsyncImage( robot = "authornotfound", - contentDescription = stringResource(R.string.unknown_author), + contentDescription = stringRes(R.string.unknown_author), modifier = remember { pictureModifier @@ -1423,7 +1422,7 @@ private fun WatchAndRenderBadgeImage( RobohashFallbackAsyncImage( robot = eventId, model = image!!, - contentDescription = stringResource(id = R.string.profile_image), + contentDescription = stringRes(id = R.string.profile_image), modifier = remember { pictureModifier @@ -1459,7 +1458,7 @@ fun DrawBanner( if (!banner.isNullOrBlank()) { AsyncImage( model = banner, - contentDescription = stringResource(id = R.string.profile_image), + contentDescription = stringRes(id = R.string.profile_image), contentScale = ContentScale.FillWidth, modifier = Modifier @@ -1481,7 +1480,7 @@ fun DrawBanner( } else { Image( painter = painterResource(R.drawable.profile_banner), - contentDescription = stringResource(id = R.string.profile_banner), + contentDescription = stringRes(id = R.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Modifier @@ -1757,7 +1756,7 @@ private fun MessageButton( ) { Icon( painter = painterResource(R.drawable.ic_dm), - stringResource(R.string.send_a_direct_message), + stringRes(R.string.send_a_direct_message), modifier = Modifier.size(20.dp), tint = Color.White, ) @@ -1794,7 +1793,7 @@ private fun InnerEditButton(onClick: () -> Unit) { Icon( tint = Color.White, imageVector = Icons.Default.EditNote, - contentDescription = stringResource(R.string.edits_the_user_s_metadata), + contentDescription = stringRes(R.string.edits_the_user_s_metadata), ) } } @@ -1811,7 +1810,7 @@ fun UnfollowButton(onClick: () -> Unit) { ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.unfollow), color = Color.White) + Text(text = stringRes(R.string.unfollow), color = Color.White) } } @@ -1830,7 +1829,7 @@ fun FollowButton( ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(text), color = Color.White, textAlign = TextAlign.Center) + Text(text = stringRes(text), color = Color.White, textAlign = TextAlign.Center) } } @@ -1846,7 +1845,7 @@ fun ShowUserButton(onClick: () -> Unit) { ), contentPadding = ButtonPadding, ) { - Text(text = stringResource(R.string.unblock), color = Color.White) + Text(text = stringRes(R.string.unblock), color = Color.White) } } @@ -1864,7 +1863,7 @@ fun UserProfileDropDownMenu( val clipboardManager = LocalClipboardManager.current DropdownMenuItem( - text = { Text(stringResource(R.string.copy_user_id)) }, + text = { Text(stringRes(R.string.copy_user_id)) }, onClick = { clipboardManager.setText(AnnotatedString(user.pubkeyNpub())) onDismiss() @@ -1875,7 +1874,7 @@ fun UserProfileDropDownMenu( HorizontalDivider(thickness = DividerThickness) if (accountViewModel.account.isHidden(user)) { DropdownMenuItem( - text = { Text(stringResource(R.string.unblock_user)) }, + text = { Text(stringRes(R.string.unblock_user)) }, onClick = { accountViewModel.show(user) onDismiss() @@ -1883,7 +1882,7 @@ fun UserProfileDropDownMenu( ) } else { DropdownMenuItem( - text = { Text(stringResource(id = R.string.block_hide_user)) }, + text = { Text(stringRes(id = R.string.block_hide_user)) }, onClick = { accountViewModel.hide(user) onDismiss() @@ -1892,35 +1891,35 @@ fun UserProfileDropDownMenu( } HorizontalDivider(thickness = DividerThickness) DropdownMenuItem( - text = { Text(stringResource(id = R.string.report_spam_scam)) }, + text = { Text(stringRes(id = R.string.report_spam_scam)) }, onClick = { accountViewModel.report(user, ReportEvent.ReportType.SPAM) onDismiss() }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.report_hateful_speech)) }, + text = { Text(stringRes(R.string.report_hateful_speech)) }, onClick = { accountViewModel.report(user, ReportEvent.ReportType.PROFANITY) onDismiss() }, ) DropdownMenuItem( - text = { Text(stringResource(id = R.string.report_impersonation)) }, + text = { Text(stringRes(id = R.string.report_impersonation)) }, onClick = { accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION) onDismiss() }, ) DropdownMenuItem( - text = { Text(stringResource(R.string.report_nudity_porn)) }, + text = { Text(stringRes(R.string.report_nudity_porn)) }, onClick = { accountViewModel.report(user, ReportEvent.ReportType.NUDITY) onDismiss() }, ) DropdownMenuItem( - text = { Text(stringResource(id = R.string.report_illegal_behaviour)) }, + text = { Text(stringRes(id = R.string.report_illegal_behaviour)) }, onClick = { accountViewModel.report(user, ReportEvent.ReportType.ILLEGAL) onDismiss() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt index 4186d07203..03121a3609 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt @@ -52,7 +52,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -61,6 +60,7 @@ import androidx.compose.ui.window.DialogProperties import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.WarningColor import com.vitorpamplona.quartz.events.ReportEvent @@ -75,14 +75,14 @@ fun ReportNoteDialog( ) { val reportTypes = listOf( - Pair(ReportEvent.ReportType.SPAM, stringResource(R.string.report_dialog_spam)), - Pair(ReportEvent.ReportType.PROFANITY, stringResource(R.string.report_dialog_profanity)), + Pair(ReportEvent.ReportType.SPAM, stringRes(R.string.report_dialog_spam)), + Pair(ReportEvent.ReportType.PROFANITY, stringRes(R.string.report_dialog_profanity)), Pair( ReportEvent.ReportType.IMPERSONATION, - stringResource(R.string.report_dialog_impersonation), + stringRes(R.string.report_dialog_impersonation), ), - Pair(ReportEvent.ReportType.NUDITY, stringResource(R.string.report_dialog_nudity)), - Pair(ReportEvent.ReportType.ILLEGAL, stringResource(R.string.report_dialog_illegal)), + Pair(ReportEvent.ReportType.NUDITY, stringRes(R.string.report_dialog_nudity)), + Pair(ReportEvent.ReportType.ILLEGAL, stringRes(R.string.report_dialog_illegal)), ) val reasonOptions = remember { reportTypes.map { TitleExplainer(it.second) }.toImmutableList() } @@ -96,7 +96,7 @@ fun ReportNoteDialog( Scaffold( topBar = { TopAppBar( - title = { Text(text = stringResource(id = R.string.report_dialog_title)) }, + title = { Text(text = stringRes(id = R.string.report_dialog_title)) }, navigationIcon = { IconButton(onClick = onDismiss) { ArrowBackIcon() } }, colors = TopAppBarDefaults.topAppBarColors( @@ -111,14 +111,14 @@ fun ReportNoteDialog( verticalArrangement = Arrangement.SpaceAround, ) { SpacerH16() - SectionHeader(text = stringResource(id = R.string.block_only)) + SectionHeader(text = stringRes(id = R.string.block_only)) SpacerH16() Text( - text = stringResource(R.string.report_dialog_blocking_a_user), + text = stringRes(R.string.report_dialog_blocking_a_user), ) SpacerH16() ActionButton( - text = stringResource(R.string.report_dialog_block_hide_user_btn), + text = stringRes(R.string.report_dialog_block_hide_user_btn), icon = Icons.Default.Block, onClick = { note.author?.let { accountViewModel.hide(it) } @@ -130,13 +130,13 @@ fun ReportNoteDialog( HorizontalDivider(color = MaterialTheme.colorScheme.onSurface, thickness = DividerThickness) SpacerH16() - SectionHeader(text = stringResource(R.string.report_dialog_report_btn)) + SectionHeader(text = stringRes(R.string.report_dialog_report_btn)) SpacerH16() - Text(stringResource(R.string.report_dialog_reminder_public)) + Text(stringRes(R.string.report_dialog_reminder_public)) SpacerH16() TextSpinner( - label = stringResource(R.string.report_dialog_select_reason_label), - placeholder = stringResource(R.string.report_dialog_select_reason_placeholder), + label = stringRes(R.string.report_dialog_select_reason_label), + placeholder = stringRes(R.string.report_dialog_select_reason_placeholder), options = reasonOptions, onSelect = { selectedReason = it }, modifier = Modifier.fillMaxWidth(), @@ -146,15 +146,15 @@ fun ReportNoteDialog( value = additionalReason, onValueChange = { additionalReason = it }, placeholder = { - Text(text = stringResource(R.string.report_dialog_additional_reason_placeholder)) + Text(text = stringRes(R.string.report_dialog_additional_reason_placeholder)) }, - label = { Text(stringResource(R.string.report_dialog_additional_reason_label)) }, + label = { Text(stringRes(R.string.report_dialog_additional_reason_label)) }, modifier = Modifier.fillMaxWidth(), ) SpacerH16() ActionButton( - text = stringResource(R.string.report_dialog_post_report_btn), + text = stringRes(R.string.report_dialog_post_report_btn), icon = Icons.Default.Report, enabled = selectedReason in 0..reportTypes.lastIndex, onClick = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt index 29deb85c3e..04587f1089 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SearchScreen.kt @@ -58,7 +58,6 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp @@ -87,6 +86,7 @@ import com.vitorpamplona.amethyst.ui.note.SearchIcon import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.elements.ObserveRelayListForSearchAndDisplayIfNotFound +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.Size20Modifier @@ -338,7 +338,7 @@ private fun SearchTextField( .focusRequester(focusRequester), placeholder = { Text( - text = stringResource(R.string.npub_hex_username), + text = stringRes(R.string.npub_hex_username), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt index 98e798ff97..d550af6eb9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt @@ -40,7 +40,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -53,8 +52,10 @@ import com.vitorpamplona.amethyst.model.parseBooleanType import com.vitorpamplona.amethyst.model.parseConnectivityType import com.vitorpamplona.amethyst.model.parseFeatureSetType import com.vitorpamplona.amethyst.model.parseThemeType +import com.vitorpamplona.amethyst.ui.checkLanguage import com.vitorpamplona.amethyst.ui.components.PushNotificationSettingsRow import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.HalfVertSpacer import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size20dp @@ -125,29 +126,29 @@ fun getLanguageIndex( fun SettingsScreen(sharedPreferencesViewModel: SharedPreferencesViewModel) { val selectedItens = persistentListOf( - TitleExplainer(stringResource(ConnectivityType.ALWAYS.resourceId)), - TitleExplainer(stringResource(ConnectivityType.WIFI_ONLY.resourceId)), - TitleExplainer(stringResource(ConnectivityType.NEVER.resourceId)), + TitleExplainer(stringRes(ConnectivityType.ALWAYS.resourceId)), + TitleExplainer(stringRes(ConnectivityType.WIFI_ONLY.resourceId)), + TitleExplainer(stringRes(ConnectivityType.NEVER.resourceId)), ) val themeItens = persistentListOf( - TitleExplainer(stringResource(ThemeType.SYSTEM.resourceId)), - TitleExplainer(stringResource(ThemeType.LIGHT.resourceId)), - TitleExplainer(stringResource(ThemeType.DARK.resourceId)), + TitleExplainer(stringRes(ThemeType.SYSTEM.resourceId)), + TitleExplainer(stringRes(ThemeType.LIGHT.resourceId)), + TitleExplainer(stringRes(ThemeType.DARK.resourceId)), ) val booleanItems = persistentListOf( - TitleExplainer(stringResource(ConnectivityType.ALWAYS.resourceId)), - TitleExplainer(stringResource(ConnectivityType.NEVER.resourceId)), + TitleExplainer(stringRes(ConnectivityType.ALWAYS.resourceId)), + TitleExplainer(stringRes(ConnectivityType.NEVER.resourceId)), ) val featureItems = persistentListOf( - TitleExplainer(stringResource(FeatureSetType.COMPLETE.resourceId)), - TitleExplainer(stringResource(FeatureSetType.SIMPLIFIED.resourceId)), - TitleExplainer(stringResource(FeatureSetType.PERFORMANCE.resourceId)), + TitleExplainer(stringRes(FeatureSetType.COMPLETE.resourceId)), + TitleExplainer(stringRes(FeatureSetType.SIMPLIFIED.resourceId)), + TitleExplainer(stringRes(FeatureSetType.PERFORMANCE.resourceId)), ) val showImagesIndex = sharedPreferencesViewModel.sharedPrefs.automaticallyShowImages.screenCode @@ -182,6 +183,9 @@ fun SettingsScreen(sharedPreferencesViewModel: SharedPreferencesViewModel) { languageIndex, ) { sharedPreferencesViewModel.updateLanguage(languageEntries[languageList[it].title]) + languageEntries[languageList[it].title]?.let { + checkLanguage(it) + } } Spacer(modifier = HalfVertSpacer) @@ -282,12 +286,12 @@ fun SettingsRow( verticalArrangement = Arrangement.spacedBy(3.dp), ) { Text( - text = stringResource(name), + text = stringRes(name), maxLines = 1, overflow = TextOverflow.Ellipsis, ) Text( - text = stringResource(description), + text = stringRes(description), style = MaterialTheme.typography.bodySmall, color = Color.Gray, maxLines = 2, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index d88d5de76c..f270bba93f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -52,7 +52,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.Lifecycle @@ -87,6 +86,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableBox import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.AuthorInfoVideoFeed import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size35Modifier @@ -351,7 +351,7 @@ private fun VideoUserOptionAction( ) { Icon( imageVector = Icons.Default.MoreVert, - contentDescription = stringResource(id = R.string.more_options), + contentDescription = stringRes(id = R.string.more_options), modifier = remember { Modifier.size(20.dp) }, tint = MaterialTheme.colorScheme.placeholderText, ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index de25e75d49..ad9e64492d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -75,7 +75,6 @@ import androidx.compose.ui.platform.LocalAutofillTree import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.ImeAction @@ -98,6 +97,7 @@ import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size35dp @@ -164,12 +164,12 @@ fun LoginPage( onResult = { result -> if (result.resultCode != Activity.RESULT_OK) { scope.launch(Dispatchers.Main) { - Toast.makeText( - Amethyst.instance, - "Sign request rejected", - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + Amethyst.instance, + "Sign request rejected", + Toast.LENGTH_SHORT, + ).show() } } else { result.data?.let { externalSignerLauncher.newResult(it) } @@ -189,12 +189,12 @@ fun LoginPage( if (e is CancellationException) throw e Log.e("Signer", "Error opening Signer app", e) scope.launch(Dispatchers.Main) { - Toast.makeText( - Amethyst.instance, - R.string.error_opening_external_signer, - Toast.LENGTH_SHORT, - ) - .show() + Toast + .makeText( + Amethyst.instance, + R.string.error_opening_external_signer, + Toast.LENGTH_SHORT, + ).show() } } }, @@ -215,11 +215,11 @@ fun LoginPage( val packageName = if (split.size > 1) split[1] else "" key.value = TextFieldValue(pubkey) if (!acceptedTerms.value) { - termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) + termsAcceptanceIsRequired = stringRes(context, R.string.acceptance_of_terms_is_required) } if (key.value.text.isBlank()) { - errorMessage = context.getString(R.string.key_is_required) + errorMessage = stringRes(context, R.string.key_is_required) } if (acceptedTerms.value && key.value.text.isNotBlank()) { @@ -230,7 +230,7 @@ fun LoginPage( true, packageName, ) { - errorMessage = context.getString(R.string.invalid_key) + errorMessage = stringRes(context, R.string.invalid_key) } } } @@ -248,7 +248,7 @@ fun LoginPage( ) { Image( imageVector = CustomHashTagIcons.Amethyst, - contentDescription = stringResource(R.string.app_logo), + contentDescription = stringRes(R.string.app_logo), modifier = Modifier.size(150.dp), contentScale = ContentScale.Inside, ) @@ -279,8 +279,7 @@ fun LoginPage( Modifier .onGloballyPositioned { coordinates -> autofillNodeKey.boundingBox = coordinates.boundsInWindow() - } - .onFocusChanged { focusState -> + }.onFocusChanged { focusState -> autofill?.run { if (focusState.isFocused) { requestAutofillForNode(autofillNodeKey) @@ -304,7 +303,7 @@ fun LoginPage( ), placeholder = { Text( - text = stringResource(R.string.nsec_npub_hex_private_key), + text = stringRes(R.string.nsec_npub_hex_private_key), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -316,9 +315,9 @@ fun LoginPage( if (showCharsKey) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility, contentDescription = if (showCharsKey) { - stringResource(R.string.show_password) + stringRes(R.string.show_password) } else { - stringResource( + stringRes( R.string.hide_password, ) }, @@ -339,7 +338,7 @@ fun LoginPage( Icon( painter = painterResource(R.drawable.ic_qrcode), contentDescription = - stringResource( + stringRes( R.string.login_with_qr_code, ), modifier = Modifier.size(24.dp), @@ -353,15 +352,15 @@ fun LoginPage( KeyboardActions( onGo = { if (!acceptedTerms.value) { - termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) + termsAcceptanceIsRequired = stringRes(context, R.string.acceptance_of_terms_is_required) } if (key.value.text.isBlank()) { - errorMessage = context.getString(R.string.key_is_required) + errorMessage = stringRes(context, R.string.key_is_required) } if (needsPassword.value && password.value.text.isBlank()) { - errorMessage = context.getString(R.string.password_is_required) + errorMessage = stringRes(context, R.string.password_is_required) } if (acceptedTerms.value && key.value.text.isNotBlank() && !(needsPassword.value && password.value.text.isBlank())) { @@ -370,9 +369,9 @@ fun LoginPage( processingLogin = false errorMessage = if (it != null) { - context.getString(R.string.invalid_key_with_message, it) + stringRes(context, R.string.invalid_key_with_message, it) } else { - context.getString(R.string.invalid_key) + stringRes(context, R.string.invalid_key) } } } @@ -395,8 +394,7 @@ fun LoginPage( Modifier .onGloballyPositioned { coordinates -> autofillNodePassword.boundingBox = coordinates.boundsInWindow() - } - .onFocusChanged { focusState -> + }.onFocusChanged { focusState -> autofill?.run { if (focusState.isFocused) { requestAutofillForNode(autofillNodePassword) @@ -420,7 +418,7 @@ fun LoginPage( ), placeholder = { Text( - text = stringResource(R.string.ncryptsec_password), + text = stringRes(R.string.ncryptsec_password), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -432,9 +430,9 @@ fun LoginPage( if (showCharsPassword) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility, contentDescription = if (showCharsPassword) { - stringResource(R.string.show_password) + stringRes(R.string.show_password) } else { - stringResource( + stringRes( R.string.hide_password, ) }, @@ -448,15 +446,15 @@ fun LoginPage( KeyboardActions( onGo = { if (!acceptedTerms.value) { - termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) + termsAcceptanceIsRequired = stringRes(context, R.string.acceptance_of_terms_is_required) } if (key.value.text.isBlank()) { - errorMessage = context.getString(R.string.key_is_required) + errorMessage = stringRes(context, R.string.key_is_required) } if (needsPassword.value && password.value.text.isBlank()) { - errorMessage = context.getString(R.string.password_is_required) + errorMessage = stringRes(context, R.string.password_is_required) } if (acceptedTerms.value && key.value.text.isNotBlank() && !(needsPassword.value && password.value.text.isBlank())) { @@ -465,9 +463,9 @@ fun LoginPage( processingLogin = false errorMessage = if (it != null) { - context.getString(R.string.invalid_key_with_message, it) + stringRes(context, R.string.invalid_key_with_message, it) } else { - context.getString(R.string.invalid_key) + stringRes(context, R.string.invalid_key) } } } @@ -488,7 +486,7 @@ fun LoginPage( }, ) - Text(stringResource(R.string.connect_via_tor)) + Text(stringRes(R.string.connect_via_tor)) } if (connectOrbotDialogOpen) { @@ -500,12 +498,12 @@ fun LoginPage( }, onError = { scope.launch { - Toast.makeText( - context, - it, - Toast.LENGTH_LONG, - ) - .show() + Toast + .makeText( + context, + it, + Toast.LENGTH_LONG, + ).show() } }, proxyPort, @@ -527,11 +525,11 @@ fun LoginPage( val annotatedTermsString = buildAnnotatedString { - withStyle(regularText) { append(stringResource(R.string.i_accept_the)) } + withStyle(regularText) { append(stringRes(R.string.i_accept_the)) } withStyle(clickableTextStyle) { pushStringAnnotation("openTerms", "") - append(stringResource(R.string.terms_of_use)) + append(stringRes(R.string.terms_of_use)) pop() } } @@ -539,8 +537,7 @@ fun LoginPage( ClickableText( text = annotatedTermsString, ) { spanOffset -> - annotatedTermsString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { - span -> + annotatedTermsString.getStringAnnotations(spanOffset, spanOffset).firstOrNull()?.also { span -> if (span.tag == "openTerms") { runCatching { uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md") @@ -567,15 +564,15 @@ fun LoginPage( onClick = { if (!acceptedTerms.value) { termsAcceptanceIsRequired = - context.getString(R.string.acceptance_of_terms_is_required) + stringRes(context, R.string.acceptance_of_terms_is_required) } if (key.value.text.isBlank()) { - errorMessage = context.getString(R.string.key_is_required) + errorMessage = stringRes(context, R.string.key_is_required) } if (needsPassword.value && password.value.text.isBlank()) { - errorMessage = context.getString(R.string.password_is_required) + errorMessage = stringRes(context, R.string.password_is_required) } if (acceptedTerms.value && key.value.text.isNotBlank() && !(needsPassword.value && password.value.text.isBlank())) { @@ -584,9 +581,9 @@ fun LoginPage( processingLogin = false errorMessage = if (it != null) { - context.getString(R.string.invalid_key_with_message, it) + stringRes(context, R.string.invalid_key_with_message, it) } else { - context.getString(R.string.invalid_key) + stringRes(context, R.string.invalid_key) } } } @@ -599,7 +596,7 @@ fun LoginPage( LoadingAnimation() Spacer(modifier = DoubleHorzSpacer) } - Text(stringResource(R.string.login)) + Text(stringRes(R.string.login)) } } } @@ -611,7 +608,7 @@ fun LoginPage( onClick = { if (!acceptedTerms.value) { termsAcceptanceIsRequired = - context.getString(R.string.acceptance_of_terms_is_required) + stringRes(context, R.string.acceptance_of_terms_is_required) return@Button } @@ -622,7 +619,7 @@ fun LoginPage( modifier = Modifier.height(50.dp), ) { Text( - text = stringResource(R.string.login_with_external_signer), + text = stringRes(R.string.login_with_external_signer), modifier = Modifier.padding(horizontal = 40.dp), ) } @@ -631,7 +628,7 @@ fun LoginPage( Spacer(modifier = Modifier.height(Size40dp)) - Text(text = stringResource(R.string.don_t_have_an_account)) + Text(text = stringRes(R.string.don_t_have_an_account)) Spacer(modifier = Modifier.height(Size20dp)) @@ -642,7 +639,7 @@ fun LoginPage( modifier = Modifier.height(50.dp), ) { Text( - text = stringResource(R.string.sign_up), + text = stringRes(R.string.sign_up), modifier = Modifier.padding(horizontal = Size40dp), ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt index a67ba3a79b..718e49f1fb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/SignUpScreen.kt @@ -54,7 +54,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.ImeAction @@ -70,6 +69,7 @@ import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.service.PackageUtils import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size35dp @@ -118,18 +118,18 @@ fun SignUpPage( ) { Image( imageVector = CustomHashTagIcons.Amethyst, - contentDescription = stringResource(R.string.app_logo), + contentDescription = stringRes(R.string.app_logo), modifier = Modifier.size(150.dp), contentScale = ContentScale.Inside, ) Spacer(modifier = Modifier.height(Size40dp)) - Text(text = stringResource(R.string.welcome), style = MaterialTheme.typography.titleLarge) + Text(text = stringRes(R.string.welcome), style = MaterialTheme.typography.titleLarge) Spacer(modifier = Modifier.height(Size20dp)) - Text(text = stringResource(R.string.how_should_we_call_you), style = MaterialTheme.typography.titleMedium) + Text(text = stringRes(R.string.how_should_we_call_you), style = MaterialTheme.typography.titleMedium) Spacer(modifier = Modifier.height(Size20dp)) @@ -144,7 +144,7 @@ fun SignUpPage( ), placeholder = { Text( - text = stringResource(R.string.my_awesome_name), + text = stringRes(R.string.my_awesome_name), color = MaterialTheme.colorScheme.placeholderText, ) }, @@ -153,11 +153,11 @@ fun SignUpPage( onGo = { if (!acceptedTerms.value) { termsAcceptanceIsRequired = - context.getString(R.string.acceptance_of_terms_is_required) + stringRes(context, R.string.acceptance_of_terms_is_required) } if (displayName.value.text.isBlank()) { - errorMessage = context.getString(R.string.name_is_required) + errorMessage = stringRes(context, R.string.name_is_required) } if (acceptedTerms.value && displayName.value.text.isNotBlank()) { @@ -188,11 +188,11 @@ fun SignUpPage( val annotatedTermsString = buildAnnotatedString { - withStyle(regularText) { append(stringResource(R.string.i_accept_the)) } + withStyle(regularText) { append(stringRes(R.string.i_accept_the)) } withStyle(clickableTextStyle) { pushStringAnnotation("openTerms", "") - append(stringResource(R.string.terms_of_use)) + append(stringRes(R.string.terms_of_use)) pop() } } @@ -229,7 +229,7 @@ fun SignUpPage( }, ) - Text(stringResource(R.string.connect_via_tor)) + Text(stringRes(R.string.connect_via_tor)) } if (connectOrbotDialogOpen) { @@ -261,11 +261,11 @@ fun SignUpPage( enabled = acceptedTerms.value, onClick = { if (!acceptedTerms.value) { - termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) + termsAcceptanceIsRequired = stringRes(context, R.string.acceptance_of_terms_is_required) } if (displayName.value.text.isBlank()) { - errorMessage = context.getString(R.string.key_is_required) + errorMessage = stringRes(context, R.string.key_is_required) } if (acceptedTerms.value && displayName.value.text.isNotBlank()) { @@ -276,7 +276,7 @@ fun SignUpPage( modifier = Modifier.height(50.dp), ) { Text( - text = stringResource(R.string.create_account), + text = stringRes(R.string.create_account), modifier = Modifier.padding(horizontal = Size40dp), ) } @@ -284,7 +284,7 @@ fun SignUpPage( Spacer(modifier = Modifier.height(Size40dp)) - Text(text = stringResource(R.string.already_have_an_account)) + Text(text = stringRes(R.string.already_have_an_account)) Spacer(modifier = Modifier.height(Size20dp)) @@ -295,7 +295,7 @@ fun SignUpPage( modifier = Modifier.height(50.dp), ) { Text( - text = stringResource(R.string.login), + text = stringRes(R.string.login), modifier = Modifier.padding(horizontal = Size40dp), ) } diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 33d736973d..4f3eb79646 100644 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -49,7 +49,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow @@ -60,6 +59,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.quartz.events.ImmutableListOfLists @@ -182,11 +182,11 @@ private fun TranslationMessage( buildAnnotatedString { withStyle(clickableTextStyle) { pushStringAnnotation("langSettings", true.toString()) - append(stringResource(R.string.translations_auto)) + append(stringRes(R.string.translations_auto)) pop() } - append("-${stringResource(R.string.translations_translated_from)} ") + append("-${stringRes(R.string.translations_translated_from)} ") withStyle(clickableTextStyle) { pushStringAnnotation("showOriginal", true.toString()) @@ -194,7 +194,7 @@ private fun TranslationMessage( pop() } - append(" ${stringResource(R.string.translations_to)} ") + append(" ${stringRes(R.string.translations_to)} ") withStyle(clickableTextStyle) { pushStringAnnotation("showOriginal", false.toString()) @@ -244,7 +244,7 @@ private fun TranslationMessage( Spacer(modifier = Modifier.size(10.dp)) Text( - stringResource( + stringRes( R.string.translations_never_translate_from_lang, Locale(source).displayName, ), @@ -275,7 +275,7 @@ private fun TranslationMessage( Spacer(modifier = Modifier.size(10.dp)) Text( - stringResource( + stringRes( R.string.translations_show_in_lang_first, Locale(source).displayName, ), @@ -305,7 +305,7 @@ private fun TranslationMessage( Spacer(modifier = Modifier.size(10.dp)) Text( - stringResource( + stringRes( R.string.translations_show_in_lang_first, Locale(target).displayName, ), @@ -340,7 +340,7 @@ private fun TranslationMessage( Spacer(modifier = Modifier.size(10.dp)) Text( - stringResource( + stringRes( R.string.translations_always_translate_to_lang, lang.displayName, ), From aae47aa2e15ef9894e0acc86960b1b89053f3a4c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 15:40:14 -0400 Subject: [PATCH 33/45] Fixing Options Button --- .../amethyst/ui/components/ClickableBox.kt | 2 + .../amethyst/ui/note/BadgeCompose.kt | 43 ++++--------------- .../vitorpamplona/amethyst/ui/note/Icons.kt | 8 ++-- .../amethyst/ui/note/MessageSetCompose.kt | 16 +++---- .../amethyst/ui/note/MultiSetCompose.kt | 7 +-- .../amethyst/ui/note/elements/DropDownMenu.kt | 29 ++++++------- .../ui/screen/loggedIn/VideoScreen.kt | 29 +++++++------ 7 files changed, 56 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt index 341e970246..57410903e2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBox.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.material.ripple.rememberRipple import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.Role import com.vitorpamplona.amethyst.ui.theme.Size24dp @@ -43,6 +44,7 @@ fun ClickableBox( indication = rememberRipple(bounded = false, radius = Size24dp), onClick = onClick, ), + contentAlignment = Alignment.Center, ) { content() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index 584216f417..08639b0acc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.note import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background -import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -31,17 +31,12 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MilitaryTech -import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -49,14 +44,12 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.routeFor -import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu +import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay import com.vitorpamplona.amethyst.ui.screen.BadgeCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes -import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.placeholderText -import kotlinx.coroutines.launch @OptIn(ExperimentalFoundationApi::class) @Composable @@ -75,11 +68,6 @@ fun BadgeCompose( val context = LocalContext.current.applicationContext - val popupExpanded = remember { mutableStateOf(false) } - val enablePopup = remember { { popupExpanded.value = true } } - - val scope = rememberCoroutineScope() - if (note == null) { BlankNote(Modifier) } else { @@ -94,16 +82,13 @@ fun BadgeCompose( modifier = Modifier .background(backgroundColor.value) - .combinedClickable( + .clickable( onClick = { - scope.launch { - routeFor( - note, - accountViewModel.userProfile(), - )?.let { nav(it) } - } + routeFor( + note, + accountViewModel.userProfile(), + )?.let { nav(it) } }, - onLongClick = enablePopup, ), ) { Row( @@ -142,19 +127,7 @@ fun BadgeCompose( maxLines = 1, ) - IconButton( - modifier = Modifier.then(Modifier.size(24.dp)), - onClick = enablePopup, - ) { - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = stringRes(id = R.string.more_options), - modifier = Size15Modifier, - tint = MaterialTheme.colorScheme.placeholderText, - ) - - NoteDropDownMenu(note, popupExpanded, null, accountViewModel, nav) - } + MoreOptionsButton(note, null, accountViewModel, nav) } note.replyTo?.firstOrNull()?.let { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt index a980f0e33f..905f36d81f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/Icons.kt @@ -73,7 +73,7 @@ import com.vitorpamplona.amethyst.commons.icons.Zap import com.vitorpamplona.amethyst.commons.icons.ZapSplit import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange -import com.vitorpamplona.amethyst.ui.theme.Size18Modifier +import com.vitorpamplona.amethyst.ui.theme.Size19Modifier import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size30Modifier import com.vitorpamplona.amethyst.ui.theme.grayText @@ -508,11 +508,11 @@ fun LinkIcon( } @Composable -fun VerticalDotsIcon(contentDescriptor: Int? = null) { +fun VerticalDotsIcon() { Icon( imageVector = Icons.Default.MoreVert, - contentDescription = contentDescriptor?.let { stringRes(id = it) }, - modifier = Size18Modifier, + contentDescription = stringRes(id = R.string.note_options), + modifier = Size19Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt index 5c7417b26b..3ea88e7aa4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt @@ -68,25 +68,23 @@ fun MessageSetCompose( val columnModifier = remember(backgroundColor.value) { - Modifier.background(backgroundColor.value) + Modifier + .background(backgroundColor.value) .padding( start = 12.dp, end = 12.dp, top = 10.dp, - ) - .combinedClickable( + ).combinedClickable( onClick = { scope.launch { routeFor( baseNote, accountViewModel.userProfile(), - ) - ?.let { nav(it) } + )?.let { nav(it) } } }, onLongClick = enablePopup, - ) - .fillMaxWidth() + ).fillMaxWidth() } Column(columnModifier) { @@ -111,7 +109,9 @@ fun MessageSetCompose( nav = nav, ) - NoteDropDownMenu(baseNote, popupExpanded, null, accountViewModel, nav) + if (popupExpanded.value) { + NoteDropDownMenu(baseNote, { popupExpanded.value = false }, null, accountViewModel, nav) + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index e6b52a50db..4552e57db7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -106,7 +106,6 @@ fun MultiSetCompose( val baseNote = remember { multiSetCard.note } val popupExpanded = remember { mutableStateOf(false) } - val enablePopup = remember { { popupExpanded.value = true } } val scope = rememberCoroutineScope() @@ -126,7 +125,7 @@ fun MultiSetCompose( onClick = { scope.launch { routeFor(baseNote, accountViewModel.userProfile())?.let { nav(it) } } }, - onLongClick = enablePopup, + onLongClick = { popupExpanded.value = true }, ).padding( start = 12.dp, end = 12.dp, @@ -152,7 +151,9 @@ fun MultiSetCompose( nav = nav, ) - NoteDropDownMenu(baseNote, popupExpanded, null, accountViewModel, nav) + if (popupExpanded.value) { + NoteDropDownMenu(baseNote, { popupExpanded.value = false }, null, accountViewModel, nav) + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt index 12006581be..1c251469dc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt @@ -28,7 +28,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -71,15 +70,17 @@ fun MoreOptionsButton( modifier = Size24Modifier, onClick = { popupExpanded.value = true }, ) { - VerticalDotsIcon(R.string.note_options) + VerticalDotsIcon() - NoteDropDownMenu( - baseNote, - popupExpanded, - editState, - accountViewModel, - nav, - ) + if (popupExpanded.value) { + NoteDropDownMenu( + note = baseNote, + onDismiss = { popupExpanded.value = false }, + editState = editState, + accountViewModel = accountViewModel, + nav = nav, + ) + } } } @@ -96,7 +97,7 @@ data class DropDownParams( @Composable fun NoteDropDownMenu( note: Note, - popupExpanded: MutableState, + onDismiss: () -> Unit, editState: State>? = null, accountViewModel: AccountViewModel, nav: (String) -> Unit, @@ -116,8 +117,6 @@ fun NoteDropDownMenu( ) } - val onDismiss = remember(popupExpanded) { { popupExpanded.value = false } } - val wantsToEditPost = remember { mutableStateOf(false) @@ -137,7 +136,7 @@ fun NoteDropDownMenu( EditPostView( onClose = { - popupExpanded.value = false + onDismiss() wantsToEditPost.value = false }, edit = note, @@ -150,7 +149,7 @@ fun NoteDropDownMenu( if (wantsToEditDraft.value) { NewPostView( onClose = { - popupExpanded.value = false + onDismiss() wantsToEditDraft.value = false }, accountViewModel = accountViewModel, @@ -160,7 +159,7 @@ fun NoteDropDownMenu( } DropdownMenu( - expanded = popupExpanded.value, + expanded = true, onDismissRequest = onDismiss, ) { val clipboardManager = LocalClipboardManager.current diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index f270bba93f..db66f5e303 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -39,7 +39,6 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -63,6 +62,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.NostrVideoDataSource import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.actions.NewPostView +import com.vitorpamplona.amethyst.ui.components.ClickableBox import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.navigation.routeFor import com.vitorpamplona.amethyst.ui.note.BoostReaction @@ -89,6 +89,8 @@ import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.AuthorInfoVideoFeed import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer +import com.vitorpamplona.amethyst.ui.theme.Size20Modifier +import com.vitorpamplona.amethyst.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.ui.theme.Size35Modifier import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.Size40Modifier @@ -343,26 +345,27 @@ private fun VideoUserOptionAction( nav: (String) -> Unit, ) { val popupExpanded = remember { mutableStateOf(false) } - val enablePopup = remember { { popupExpanded.value = true } } - IconButton( - modifier = remember { Modifier.size(22.dp) }, - onClick = enablePopup, + ClickableBox( + modifier = Size22Modifier, + onClick = { popupExpanded.value = true }, ) { Icon( imageVector = Icons.Default.MoreVert, contentDescription = stringRes(id = R.string.more_options), - modifier = remember { Modifier.size(20.dp) }, + modifier = Size20Modifier, tint = MaterialTheme.colorScheme.placeholderText, ) - NoteDropDownMenu( - note, - popupExpanded, - null, - accountViewModel, - nav, - ) + if (popupExpanded.value) { + NoteDropDownMenu( + note, + { popupExpanded.value = false }, + null, + accountViewModel, + nav, + ) + } } } From 239f390e7c45a1197cfc1d907369e5ef6dfa3e05 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 15:43:10 -0400 Subject: [PATCH 34/45] Fixes Fdroid tests --- .../amethyst/ui/components/SelectNotificationProvider.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt index 41ab2ef745..d677caaec2 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt @@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.CheckifItNeedsToRequestNoti import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.SpinnerSelectionDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer +import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList From d28f20519b982fb42cb50836f580410ba9a52bf1 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 19 Jun 2024 16:34:01 -0400 Subject: [PATCH 35/45] v0.88.0 --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7e126ba3d6..a40084a075 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,9 +12,9 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 376 - versionName "0.87.7" - buildConfigField "String", "RELEASE_NOTES_ID", "\"863124b6592359494396c22b917f9d251ad12ac31b09ea29e0265e3c088ce9f8\"" + versionCode 377 + versionName "0.88.0" + buildConfigField "String", "RELEASE_NOTES_ID", "\"2a34cbadd03212c8162e1ff896ba12641821088a2ec8d5e40d54aa80c0510800\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { From d33befe1ad8b3fe46012822bddcfd3343ee99227 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 09:42:10 -0400 Subject: [PATCH 36/45] Removes account migration and unused keys for shared preferences. --- .../amethyst/LocalPreferences.kt | 33 ++----------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 765456d702..a1aa03e1b9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -72,7 +72,6 @@ data class AccountInfo( private object PrefKeys { const val CURRENT_ACCOUNT = "currently_logged_in_account" - const val SAVED_ACCOUNTS = "all_saved_accounts" const val NOSTR_PRIVKEY = "nostr_privkey" const val NOSTR_PUBKEY = "nostr_pubkey" const val RELAYS = "relays" @@ -99,14 +98,7 @@ private object PrefKeys { const val WARN_ABOUT_REPORTS = "warn_about_reports" const val FILTER_SPAM_FROM_STRANGERS = "filter_spam_from_strangers" const val LAST_READ_PER_ROUTE = "last_read_route_per_route" - const val AUTOMATICALLY_SHOW_IMAGES = "automatically_show_images" - const val AUTOMATICALLY_START_PLAYBACK = "automatically_start_playback" - const val THEME = "theme" - const val PREFERRED_LANGUAGE = "preferred_Language" - const val AUTOMATICALLY_LOAD_URL_PREVIEW = "automatically_load_url_preview" - const val AUTOMATICALLY_HIDE_NAV_BARS = "automatically_hide_nav_bars" const val LOGIN_WITH_EXTERNAL_SIGNER = "login_with_external_signer" - const val AUTOMATICALLY_SHOW_PROFILE_PICTURE = "automatically_show_profile_picture" const val SIGNER_PACKAGE_NAME = "signer_package_name" const val HAS_DONATED_IN_VERSION = "has_donated_in_version" const val PENDING_ATTESTATIONS = "pending_attestations" @@ -150,20 +142,6 @@ object LocalPreferences { if (newSystemOfAccounts != null && newSystemOfAccounts.isNotEmpty()) { savedAccounts = newSystemOfAccounts - } else { - val oldAccounts = getString(PrefKeys.SAVED_ACCOUNTS, null)?.split(COMMA) ?: listOf() - - val migrated = - oldAccounts.map { npub -> - AccountInfo( - npub, - encryptedPreferences(npub).getBoolean(PrefKeys.LOGIN_WITH_EXTERNAL_SIGNER, false), - (encryptedPreferences(npub).getString(PrefKeys.NOSTR_PRIVKEY, "") ?: "") - .isNotBlank(), - ) - } - - savedAccounts = migrated } } } @@ -265,9 +243,7 @@ object LocalPreferences { saveToEncryptedStorage(account) } - fun allSavedAccounts(): List { - return savedAccounts() - } + fun allSavedAccounts(): List = savedAccounts() suspend fun saveToEncryptedStorage(account: Account) { Log.d("LocalPreferences", "Saving to encrypted storage") @@ -345,14 +321,11 @@ object LocalPreferences { PrefKeys.PENDING_ATTESTATIONS, Event.mapper.writeValueAsString(account.pendingAttestations.value), ) - } - .apply() + }.apply() } } - suspend fun loadCurrentAccountFromEncryptedStorage(): Account? { - return currentAccount()?.let { loadCurrentAccountFromEncryptedStorage(it) } - } + suspend fun loadCurrentAccountFromEncryptedStorage(): Account? = currentAccount()?.let { loadCurrentAccountFromEncryptedStorage(it) } suspend fun saveSharedSettings( sharedSettings: Settings, From 3a4e2e962363b3120bcd16fe5de6f691fa4c7424 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 09:47:11 -0400 Subject: [PATCH 37/45] Don't use DM kinds to get information about other logged-in accounts --- .../service/NostrAccountDataSource.kt | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index 7b8761b278..298bcb6b3e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -27,6 +27,7 @@ import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.amethyst.service.relays.EOSETime +import com.vitorpamplona.amethyst.service.relays.EVENT_FINDER_TYPES import com.vitorpamplona.amethyst.service.relays.JsonFilter import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.service.relays.TypedFilter @@ -76,8 +77,8 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { val latestEOSEs = EOSEAccount() val hasLoadedTheBasics = mutableMapOf() - fun createAccountContactListFilter(): TypedFilter { - return TypedFilter( + fun createAccountContactListFilter(): TypedFilter = + TypedFilter( types = COMMON_FEED_TYPES, filter = JsonFilter( @@ -86,10 +87,9 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { limit = 1, ), ) - } - fun createAccountMetadataFilter(): TypedFilter { - return TypedFilter( + fun createAccountMetadataFilter(): TypedFilter = + TypedFilter( types = COMMON_FEED_TYPES, filter = JsonFilter( @@ -98,10 +98,9 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { limit = 1, ), ) - } - fun createAccountRelayListFilter(): TypedFilter { - return TypedFilter( + fun createAccountRelayListFilter(): TypedFilter = + TypedFilter( types = COMMON_FEED_TYPES, filter = JsonFilter( @@ -110,12 +109,11 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { limit = 10, ), ) - } fun createOtherAccountsBaseFilter(): TypedFilter? { if (otherAccounts.isEmpty()) return null return TypedFilter( - types = COMMON_FEED_TYPES, + types = EVENT_FINDER_TYPES, filter = JsonFilter( kinds = @@ -136,8 +134,8 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { ) } - fun createAccountSettingsFilter(): TypedFilter { - return TypedFilter( + fun createAccountSettingsFilter(): TypedFilter = + TypedFilter( types = COMMON_FEED_TYPES, filter = JsonFilter( @@ -146,10 +144,9 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { limit = 100, ), ) - } - fun createAccountReportsFilter(): TypedFilter { - return TypedFilter( + fun createAccountReportsFilter(): TypedFilter = + TypedFilter( types = COMMON_FEED_TYPES, filter = JsonFilter( @@ -162,10 +159,9 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { ?.relayList, ), ) - } - fun createAccountLastPostsListFilter(): TypedFilter { - return TypedFilter( + fun createAccountLastPostsListFilter(): TypedFilter = + TypedFilter( types = COMMON_FEED_TYPES, filter = JsonFilter( @@ -173,7 +169,6 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { limit = 400, ), ) - } fun createNotificationFilter(): TypedFilter { val since = @@ -404,8 +399,8 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { } } - override fun updateChannelFilters() { - return if (hasLoadedTheBasics[account.userProfile()] != null) { + override fun updateChannelFilters() = + if (hasLoadedTheBasics[account.userProfile()] != null) { // gets everything about the user logged in accountChannel.typedFilters = listOfNotNull( @@ -419,8 +414,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { createAccountSettingsFilter(), createAccountLastPostsListFilter(), createOtherAccountsBaseFilter(), - ) - .ifEmpty { null } + ).ifEmpty { null } } else { // just the basics. accountChannel.typedFilters = @@ -429,10 +423,8 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { createAccountContactListFilter(), createAccountRelayListFilter(), createAccountSettingsFilter(), - ) - .ifEmpty { null } + ).ifEmpty { null } } - } override fun auth( relay: Relay, From 0d956c2f39e3f2fd7405c2f720ae98f89d85c52b Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 09:47:43 -0400 Subject: [PATCH 38/45] Removes the need to exclude byte-buddy due to jackson's earlier version bug. --- quartz/build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quartz/build.gradle b/quartz/build.gradle index fb153c6f0b..f775df581b 100644 --- a/quartz/build.gradle +++ b/quartz/build.gradle @@ -57,9 +57,7 @@ dependencies { implementation 'net.java.dev.jna:jna:5.14.0@aar' // Performant Parser of JSONs into Events - api(libs.jackson.module.kotlin) { - exclude(module: 'byte-buddy') // Workaround https://github.com/FasterXML/jackson-databind/issues/4428 until Jackson 2.17.1 - } + api(libs.jackson.module.kotlin) // immutable collections to avoid recomposition api libs.kotlinx.collections.immutable From eaa09055fc4b8bff7de414409392e474e3e41e82 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 09:48:10 -0400 Subject: [PATCH 39/45] v0.88.1 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a40084a075..0b028c989c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 377 - versionName "0.88.0" + versionCode 378 + versionName "0.88.1" buildConfigField "String", "RELEASE_NOTES_ID", "\"2a34cbadd03212c8162e1ff896ba12641821088a2ec8d5e40d54aa80c0510800\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From ec19038e5c39d28c419e71ef195dd386c56e3965 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 20 Jun 2024 13:50:41 +0000 Subject: [PATCH 40/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-es-rES/strings.xml | 8 ++++++++ app/src/main/res/values-es-rMX/strings.xml | 8 ++++++++ app/src/main/res/values-es-rUS/strings.xml | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index de844f632b..e5b2b33275 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -113,6 +113,7 @@ Dirección web Dirección LN Dirección LN (antigua) + Guardar en la galería Imagen guardada en la galería Error al guardar la imagen Cargar imagen @@ -407,6 +408,7 @@ Idiomas Etiquetas Política de publicación + Errores y avisos de este relé Longitud del mensaje Suscripciones Filtros @@ -449,6 +451,7 @@ Nunca Completo Simplificado + Rendimiento Sistema Claro Oscuro @@ -500,6 +503,7 @@ Cuándo cargar imágenes Copiar al portapapeles Copiar npub al portapapeles + Compartir o guardar Copiar URL al portapapeles Copiar ID de la nota al portapapeles Creado @@ -512,6 +516,10 @@ Mensaje para el usuario OK No se pudo llegar a %1$s: %2$s + Error al ensamblar la url NIP-11 para %1$s: %2$s + No se pudo contactar %1$s: %2$s + Error al analizar la respuesta de %1$s: %2$s + El relé rechazó la solicitud %1$s: %2$s No se pudo llegar a %1$s: %2$s Error al analizar el resultado de %1$s: %2$s %1$s falló con el código %2$s diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index 5b632d029c..31b18062b0 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -113,6 +113,7 @@ URL del sitio web Dirección de Lightning URL de Lightning (obsoleta) + Guardar en la galería Imagen guardada en la galería Error al guardar la imagen Subir imagen @@ -407,6 +408,7 @@ Idiomas Etiquetas Política de publicación + Errores y avisos de este relé Longitud del mensaje Suscripciones Filtros @@ -449,6 +451,7 @@ Nunca Completo Simplificado + Rendimiento Sistema Claro Oscuro @@ -500,6 +503,7 @@ Cuándo cargar imágenes Copiar al portapapeles Copiar npub al portapapeles + Compartir o guardar Copiar URL al portapapeles Copiar ID de la nota al portapapeles Creado @@ -512,6 +516,10 @@ Mensaje para el usuario OK No se pudo llegar a %1$s: %2$s + Error al ensamblar la url NIP-11 para %1$s: %2$s + No se pudo contactar %1$s: %2$s + Error al analizar la respuesta de %1$s: %2$s + El relé rechazó la solicitud %1$s: %2$s No se pudo llegar a %1$s: %2$s Error al analizar el resultado de %1$s: %2$s %1$s falló con el código %2$s diff --git a/app/src/main/res/values-es-rUS/strings.xml b/app/src/main/res/values-es-rUS/strings.xml index c51b768794..a52f9e805f 100644 --- a/app/src/main/res/values-es-rUS/strings.xml +++ b/app/src/main/res/values-es-rUS/strings.xml @@ -113,6 +113,7 @@ URL del sitio web Dirección de Lightning URL de Lightning (obsoleta) + Guardar en la galería Imagen guardada en la galería Error al guardar la imagen Subir imagen @@ -407,6 +408,7 @@ Idiomas Etiquetas Política de publicación + Errores y avisos de este relé Longitud del mensaje Suscripciones Filtros @@ -449,6 +451,7 @@ Nunca Completo Simplificado + Rendimiento Sistema Claro Oscuro @@ -500,6 +503,7 @@ Cuándo cargar imágenes Copiar al portapapeles Copiar npub al portapapeles + Compartir o guardar Copiar URL al portapapeles Copiar ID de la nota al portapapeles Creado @@ -512,6 +516,10 @@ Mensaje para el usuario OK No se pudo llegar a %1$s: %2$s + Error al ensamblar la url NIP-11 para %1$s: %2$s + No se pudo contactar %1$s: %2$s + Error al analizar la respuesta de %1$s: %2$s + El relé rechazó la solicitud %1$s: %2$s No se pudo llegar a %1$s: %2$s Error al analizar el resultado de %1$s: %2$s %1$s falló con el código %2$s From 82f99faec849985fc977180c91788dbbd58c4d7e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 12:22:07 -0400 Subject: [PATCH 41/45] Fixes name instead of uri --- .../vitorpamplona/amethyst/ui/components/VideoView.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 9e0801307e..4636903435 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -408,7 +408,15 @@ fun GetMediaItem( authorName: String?, inner: @Composable (State) -> Unit, ) { - val data = remember(videoUri) { MediaItemData(videoUri, title, artworkUri, authorName) } + val data = + remember(videoUri) { + MediaItemData( + videoUri = videoUri, + authorName = authorName, + title = title, + artworkUri = artworkUri, + ) + } val mediaItem by produceCachedState(cache = mediaItemCache, key = data) mediaItem?.let { From 9e9e0667cde3b1a4acef8f5fb059dc00c4a1525f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 16:29:48 -0400 Subject: [PATCH 42/45] Reverts old migration of accounts due the fact that some people were still in the old model --- .../amethyst/LocalPreferences.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index a1aa03e1b9..3b21ef66d8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -72,6 +72,7 @@ data class AccountInfo( private object PrefKeys { const val CURRENT_ACCOUNT = "currently_logged_in_account" + const val SAVED_ACCOUNTS = "all_saved_accounts" const val NOSTR_PRIVKEY = "nostr_privkey" const val NOSTR_PUBKEY = "nostr_pubkey" const val RELAYS = "relays" @@ -140,8 +141,24 @@ object LocalPreferences { Event.mapper.readValue>(it) } - if (newSystemOfAccounts != null && newSystemOfAccounts.isNotEmpty()) { + if (!newSystemOfAccounts.isNullOrEmpty()) { savedAccounts = newSystemOfAccounts + } else { + val oldAccounts = getString(PrefKeys.SAVED_ACCOUNTS, null)?.split(COMMA) ?: listOf() + + val migrated = + oldAccounts.map { npub -> + AccountInfo( + npub, + encryptedPreferences(npub).getBoolean(PrefKeys.LOGIN_WITH_EXTERNAL_SIGNER, false), + (encryptedPreferences(npub).getString(PrefKeys.NOSTR_PRIVKEY, "") ?: "") + .isNotBlank(), + ) + } + + savedAccounts = migrated + + edit().apply { putString(PrefKeys.ALL_ACCOUNT_INFO, Event.mapper.writeValueAsString(savedAccounts)) }.apply() } } } From b39ac214a5b505ff9ce292b05d2ffad073e340dd Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 16:30:12 -0400 Subject: [PATCH 43/45] Limits the amount of zaps on the user profile --- .../amethyst/service/NostrUserProfileDataSource.kt | 4 ++-- .../src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt index 9c2db5c657..58ab69b5bb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt @@ -96,6 +96,7 @@ object NostrUserProfileDataSource : NostrDataSource("UserProfileFeed") { JsonFilter( kinds = listOf(LnZapEvent.KIND), tags = mapOf("p" to listOf(it.pubkeyHex)), + limit = 200, ), ) } @@ -178,7 +179,6 @@ object NostrUserProfileDataSource : NostrDataSource("UserProfileFeed") { createAcceptedAwardsFilter(), createReceivedAwardsFilter(), createBookmarksFilter(), - ) - .ifEmpty { null } + ).ifEmpty { null } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt b/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt index bb13e4f998..2b71a4e606 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/utils/TimeUtils.kt @@ -55,5 +55,7 @@ object TimeUtils { fun oneWeekAgo() = now() - ONE_WEEK + fun oneMonthAgo() = now() - ONE_MONTH + fun randomWithTwoDays() = System.currentTimeMillis() / 1000 - CryptoUtils.randomInt(twoDays()) } From 0e1e379c7dc65a99d0fabaf5fe228bca7ed310a8 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 20 Jun 2024 16:30:33 -0400 Subject: [PATCH 44/45] v0.88.2 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0b028c989c..cb9b24d5d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 378 - versionName "0.88.1" + versionCode 379 + versionName "0.88.2" buildConfigField "String", "RELEASE_NOTES_ID", "\"2a34cbadd03212c8162e1ff896ba12641821088a2ec8d5e40d54aa80c0510800\"" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From fece7411c944d17903aba67651fc367ccd98de67 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 20 Jun 2024 20:32:46 +0000 Subject: [PATCH 45/45] New Crowdin translations by GitHub Action --- app/src/main/res/values-fr/strings.xml | 3 ++- app/src/main/res/values-hu/strings.xml | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8ef284a6b6..c63292a5e3 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -8,7 +8,7 @@ Montrer quand même Ce message a été masqué car il mentionne vos utilisateurs ou mots cachés Post signalé inapproprié par - Post non trouvé + L\'événement est en cours de chargement ou ne peut pas être trouvé dans votre liste de relais Image du canal référence de l\'évènement non trouvée Impossible de déchiffrer le message @@ -451,6 +451,7 @@ Jamais Complet Simplifié + Performance Système Clair Sombre diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 78bb18d817..7672545ad6 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -113,6 +113,7 @@ Oldalam URL-je LN Cím LN URL (elavult) + Mentés a galériába A kép a galériába mentve Nem sikerült menteni a képet Kép feltöltése @@ -449,6 +450,7 @@ Soha Teljes Egyszerűsített + Teljesítmény-beállítások Rendszer Világos Sötét @@ -500,6 +502,7 @@ Mikor kell a képeket betölteni Másolás a vágólapra Npub másolása a vágólapra + Megosztás vagy Mentés Az URL vágólapra másolása A bejegyzésazonosító vágólapra másolása Létrehozva @@ -512,6 +515,10 @@ Üzenet a Felhasználónak Ok Nem sikerült elérni %1$s: %2$s + Nem sikerült összeállítani a NIP-11 URL-t a következőhöz: %1$s: %2$s + Nem sikerült elérni %1$s: %2$s + Nem sikerült a válasz elemzése a %1$s: %2$s + A csomópont elutasította a(z) %1$s kérést: %2$s Nem sikerült elérni %1$s: %2$s Nem sikerült az eredmény elemzése a %1$s: %2$s %1$s hiba a következő kóddal %2$s