diff --git a/app/build.gradle b/app/build.gradle index 48a4f0f..d3ab720 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { minSdkVersion 21 targetSdkVersion 30 - versionCode 24 - versionName "1.6.0" + versionCode 25 + versionName "1.7.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -130,7 +130,6 @@ dependencies { implementation "com.github.TorrentStream:TorrentStream-Android:2.7.0" implementation "io.github.kobakei:ratethisapp:1.2.0" - implementation 'com.github.HITGIF:TextFieldBoxes:1.4.5' implementation 'com.github.vkay94:DoubleTapPlayerView:1.0.0' implementation "androidx.work:work-runtime:2.4.0" diff --git a/app/src/acad/res/values/strings.xml b/app/src/acad/res/values/strings.xml index 63e9350..4d22804 100644 --- a/app/src/acad/res/values/strings.xml +++ b/app/src/acad/res/values/strings.xml @@ -18,9 +18,19 @@ Vidéos dans une liste Change la mise en page pour afficher les vidéos dans une liste + Exporter + Importer + + Supprimer l\'historique de vidéos + Êtes vous sur de vouloir supprimer toutes les vidéos de votre historique ? + Exportation réussie ! + Cliquer ici pour envoyer l\'exportation par mèl. + Nouvelle liste de lecture + Ouvrez la pièce jointe avec l\'application TubeAcad + Montrer plus Montrer moins - + Aucune instance ! Verrouillage d\'écran Continuer à lire des vidéos lorsque l\'écran est verrouillé @@ -165,8 +175,12 @@ Logo de l’application Abonnements + Supprimer l\'instance + Etes-vous sûr de vouloir supprimer cette instance ? + Supprimer le commentaire Etes-vous sûr de vouloir supprimer ce commentaire ? + Mode pour les vidéos Filtrer Recherche sépia @@ -287,6 +301,7 @@ Faible Voulez-vous vous désabonner de ce compte ? + Aucune liste de lecture ! Titre de la vidéo Rejoignez Peertube J\'ai au moins 16 ans et je suis d\'accord avec les %1$s de cette instance diff --git a/app/src/acad/res/xml/file_paths.xml b/app/src/acad/res/xml/file_paths.xml new file mode 100644 index 0000000..4175376 --- /dev/null +++ b/app/src/acad/res/xml/file_paths.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/fdroid_acad/AndroidManifest.xml b/app/src/fdroid_acad/AndroidManifest.xml new file mode 100644 index 0000000..89d0750 --- /dev/null +++ b/app/src/fdroid_acad/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/fdroid_full/play/release-notes/en-US/default.txt b/app/src/fdroid_full/play/release-notes/en-US/default.txt index 1afccdf..b010cef 100644 --- a/app/src/fdroid_full/play/release-notes/en-US/default.txt +++ b/app/src/fdroid_full/play/release-notes/en-US/default.txt @@ -1,25 +1,14 @@ Added: -- Device notifications (refresh time can be set in settings or disabled) -- Double tap video left/right to seek - or + 10 seconds -- Display video in a list with small thumbnails (default: disabled) -- Automatically adapt full-screen in portrait or landscape -- Incognito: Enable/disable reccords in history -- Video suggestions -- Enable/Disable playback when screen is off (default: disabled) -- Add support for Torrent URLs -- Toggle full video description when available -- Channel can be visited from playing video activity -- Play videos from URL search -- Allow to set behavior in settings for sensitive media -- Remember last play position -- Honor don't download videos when forbidden -- Share channel or account links when visiting profiles +- Display follow button for Sepia Search +- Reach owner from channels +- Surfing mode (store instances in db with quick switch) +- Allow to delete history Changed: -- Video mode (Normal, webview, magnet and torrent) -- Accept URLs for instances +- Quicker access to account settings +- Improve landscape mode Fix: -- Enable to end playing with top back button -- Fix FP message with token -- Share the page on Peertube and not the video file. \ No newline at end of file +- Pull to refresh crashes +- Settings crashes +- Fix an issue with unlisted playlists \ No newline at end of file diff --git a/app/src/full/res/values-ar/strings.xml b/app/src/full/res/values-ar/strings.xml index a81e75d..9c5700e 100644 --- a/app/src/full/res/values-ar/strings.xml +++ b/app/src/full/res/values-ar/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -136,6 +137,8 @@ شعار التطبيق الاشتراكات + Delete an instance + Are you sure to delete this instance? حذف التعليق هل أنت متأكد من أنك تود حذف هذا التعليق؟ أسلوب عرض الفيديوهات @@ -220,7 +223,16 @@ ارسل تعليق الكل + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab قوائم التشغيل + No playlists الاسم العلني You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist يجب عليك إدخال اسم علني! diff --git a/app/src/full/res/values-de/strings.xml b/app/src/full/res/values-de/strings.xml index df32579..de7f931 100644 --- a/app/src/full/res/values-de/strings.xml +++ b/app/src/full/res/values-de/strings.xml @@ -2,6 +2,7 @@ Videoliste Layout für die Anzeige von Videos in einer Liste ändern + Keine Instanzen ! Mehr anzeigen Weniger anzeigen Bildschirmsperre @@ -25,7 +26,7 @@ Videoimport abgeschlossen Du oder dein Kanal(e) haben einen neuen Follower Jemand hat dich in einem Kommentar erwähnt - Ein Missbrauchsbericht hat eine neue Nachricht erhalten + Es gibt eine neue Nachricht zu einem Missbrauchsbericht Ein Missbrauchsbericht wurde von Moderatoren akzeptiert oder abgelehnt %d Antwort @@ -40,7 +41,7 @@ Entdecken Benachrichtigungen Zuletzt hinzugefügt - Beliebt + Angesagt Beliebteste Hoppla, es gab einen Fehler! Stummgeschaltet @@ -132,6 +133,8 @@ Logo der Anwendung Abonnements + Eine Instanz entfernen + Möchtest du diese Instanz wirklich entfernen? Kommentar löschen Möchtest du diesen Kommentar wirklich löschen? Videomodus @@ -178,19 +181,19 @@ Name Mehr anzeigen Keine Kanäle! - Einige Erklärungen zu deinem Bericht… + Einige Erklärungen zu deiner Meldung… Video melden - Bericht + Melden Wähle eine andere Instanz Verlauf Bearbeiten Video-Einstellungen Benutzeroberfläche Zwischenspeicher - Lege die Größe des Zwischenspeichers für Videos fest (Standard 100Mb) + Lege die Größe des Zwischenspeichers für Videos fest (Standard 100MB) Standardqualität für Videos festlegen Auflösung für Videos - Video-Zwischenspeicher: %d Mb + Video-Zwischenspeicher: %d MB Untertitel Untertitel abholen Keine @@ -216,7 +219,16 @@ Kommentar absenden Alle + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Wiedergabelisten + No playlists Anzeigename Sie haben noch keine Wiedergabelisten. Klicken Sie auf das Symbol „➕”, um eine neue Wiedergabeliste hinzuzufügen. Du musst einen Anzeigenamen angeben! @@ -241,7 +253,7 @@ Du kannst nun deinen Account verbinden, indem du %1$s in das erste Feld schreibst und auf Verbindenklickst.\n\n Wichtig: Wenn deine Instanz eine Bestätigung benötigt, erhältst du eine E-Mail, sobald sie geprüft wurde! - Account + Benutzerkonto Account melden Normal diff --git a/app/src/full/res/values-el/strings.xml b/app/src/full/res/values-el/strings.xml index 310e1ff..06071ca 100644 --- a/app/src/full/res/values-el/strings.xml +++ b/app/src/full/res/values-el/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -132,6 +133,8 @@ Το λογότυπο της εφαρμογής Συνδρομές + Delete an instance + Are you sure to delete this instance? Διαγραφή ενός σχόλιου Θέλετε να διαγράψετε αυτό το σχόλιο, στα σίγουρα; Κατάσταση λειτουργίας για τα βίντεο @@ -216,7 +219,16 @@ Αποστολή σχόλιου Όλα + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Λίστες αναπαραγωγής + No playlists Εμφανιζόμενο όνομα Δεν έχετε καμία λίστα αναπαραγωγής. Κάντε κλικ στο εικονίδιο « + », για να προσθέσετε μία καινούργια λίστα Πρέπει να εισάγεται ένα όνομα εμφάνισης! diff --git a/app/src/full/res/values-es/strings.xml b/app/src/full/res/values-es/strings.xml index 7e55b5d..f704f7a 100644 --- a/app/src/full/res/values-es/strings.xml +++ b/app/src/full/res/values-es/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -132,6 +133,8 @@ Logo de la aplicación Suscripciones + Delete an instance + Are you sure to delete this instance? Eliminar un comentario ¿Realmente deseas eliminar este comentario? Aplicar el modo de video @@ -216,7 +219,16 @@ Enviar comentario Todo + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Listas de reproducción + No playlists Nombre para mostrar No tienes ninguna lista de reproducción. Pulsa en el icono \"+\" para añadir una nueva lista ¡Debe proporcionar un nombre para mostrar! diff --git a/app/src/full/res/values-fr/strings.xml b/app/src/full/res/values-fr/strings.xml index c85e26f..008b24a 100644 --- a/app/src/full/res/values-fr/strings.xml +++ b/app/src/full/res/values-fr/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -132,6 +133,8 @@ Logo de l’application Abonnements + Delete an instance + Are you sure to delete this instance? Supprimer le commentaire Etes-vous sûr de vouloir supprimer ce commentaire ? Mode pour les vidéos @@ -216,7 +219,16 @@ Envoyer un commentaire Tout + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Listes de lecture + No playlists Nom d\'affichage Vous n\'avez aucune liste de lecture. Cliquez sur l\'icône « + » pour en ajouter une Vous devez fournir un nom d\'affichage ! diff --git a/app/src/full/res/values-it/strings.xml b/app/src/full/res/values-it/strings.xml index ade4214..bd60d83 100644 --- a/app/src/full/res/values-it/strings.xml +++ b/app/src/full/res/values-it/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -132,6 +133,8 @@ Logo dell\'applicazione Abbonamenti + Delete an instance + Are you sure to delete this instance? Elimina il commento Sei sicuro di voler eliminare questo commento? Modalità per i video @@ -216,7 +219,16 @@ Invia commento Tutto + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Playlist + No playlists Nome visualizzato Non hai nessuna playlist. Premi l\'icona \"+\" per aggiungere una nuova playlist È necessario fornire un nome da visualizzare! diff --git a/app/src/full/res/values-ja/strings.xml b/app/src/full/res/values-ja/strings.xml index b658d1a..75b15ac 100644 --- a/app/src/full/res/values-ja/strings.xml +++ b/app/src/full/res/values-ja/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -131,6 +132,8 @@ アプリケーションのロゴ サブスクリプション + Delete an instance + Are you sure to delete this instance? コメントを削除 このコメントを削除しますか? 動画のモード @@ -215,7 +218,16 @@ コメントを送信 すべて + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab プレイリスト + No playlists 表示名 You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist 表示名を入力する必要があります! diff --git a/app/src/full/res/values-ko/strings.xml b/app/src/full/res/values-ko/strings.xml index 930c9b1..9cf58e5 100644 --- a/app/src/full/res/values-ko/strings.xml +++ b/app/src/full/res/values-ko/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -131,6 +132,8 @@ 응용프로그램 로고 Subscriptions + Delete an instance + Are you sure to delete this instance? Delete a comment Are you sure to delete this comment? Mode for videos @@ -215,7 +218,16 @@ 댓글 보내기 모두 + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab 재생목록 + No playlists 표시되는 이름 You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist You must provide a display name! diff --git a/app/src/full/res/values-nl/strings.xml b/app/src/full/res/values-nl/strings.xml index 2ef3611..ea6381d 100644 --- a/app/src/full/res/values-nl/strings.xml +++ b/app/src/full/res/values-nl/strings.xml @@ -2,6 +2,7 @@ Video lijst Wijzig de lay-out voor het weergeven van video\'s in een lijst + Geen instanties ! Meer weergeven Minder weergeven Schermvergrendeling @@ -90,7 +91,7 @@ %d m %d h %d d - %s aanzichten + %s weergaven Instantie host Uploaden, wacht even… De video is geüpload! @@ -132,6 +133,8 @@ Logo van de applicatie Abonnementen + Een instantie vewijderen + Weet u zeker dat u deze instantie wilt verijderen? Een opmerking verwijderen Weet u zeker dat u deze reactie wilt verwijderen? Modus voor video\'s @@ -155,7 +158,7 @@ Een van deze tags Filter toepassen - Beste wedstrijd + Beste overeenkomst Meest recente Minst recent @@ -216,7 +219,16 @@ Reactie versturen Allemaal + Delete videos history + Are you sure you want to delete all your videos history? + Exporteren + Importeren + Export succesvol! + Klik hier om de export per email te versturen + Nieuwe afspeellijst + Open het bijgevoegde bestand met TubeLab Afspeellijsten + Geen afspeellijst Weergave naam Je hebt geen afspeellijsten. Tik op het \"+\"-pictogram om een nieuwe afspeellijst toe te voegen U moet een displaynaam opgeven! diff --git a/app/src/full/res/values-pl/strings.xml b/app/src/full/res/values-pl/strings.xml index 5c0b527..bf9f541 100644 --- a/app/src/full/res/values-pl/strings.xml +++ b/app/src/full/res/values-pl/strings.xml @@ -1,32 +1,33 @@ - Videos in list - Change the layout for displaying videos in a list - Show more - Show less - Screen lock - Keep playing videos when the screen is locked - Save - Enable history - Change profile picture - Automatic playback - If enabled, videos will be played automatically - Fullscreen - Automatically open videos in fullscreen - Automatically start playing the next video - When a video ends, follow up with the next suggested video. + Filmy na liście + Zmień układ wyświetlania filmów na liście + Brak instancji! + Pokaż więcej + Pokaż mniej + Blokada ekranu + Odtwarzaj filmy kiedy ekran jest zablokowany + Zapisz + Włącz historię + Zmień zdjęcie profilowe + Automatyczne odtwarzanie + Jeśli włączone, filmy będą odtwarzane automatycznie + Pełny ekran + Automatycznie otwieraj filmy w trybie pełnoekranowym + Automatycznie rozpocznij odtwarzanie następnego filmu + Kiedy film się skończy, odtwórz następny sugerowany film. Dodaj publiczną odpowiedź - Activity - App - New video from your subscriptions - New comment on your video - One of your video is blocked/unblocked - Video published (after transcoding/scheduled update) - Video import finished - You or your channel(s) has a new follower - Someone mentioned you in video comments - An abuse report received a new message - One of your abuse reports has been accepted or rejected by moderators + Aktywność + Aplikacja + Nowy film z twoich subskrypcji + Nowy komentarz do Twojego filmu + Jeden z Twoich filmów jest zablokowany/odblokowany + Wideo opublikowane (po transkodowaniu/zaplanowanej aktualizacji) + Import wideo zakończony + Ty lub Twój kanał ma nowego obserwującego + Ktoś wspomniał o tobie w komentarzach + Raport o nadużyciach otrzymał nową wiadomość + Jeden z Twoich raportów o nadużyciach został zaakceptowany lub odrzucony przez moderatorów %d odpowiedź %d odpowiedzi @@ -36,7 +37,7 @@ Odpowiedz Motyw Zezwól na zmianę motywu aplikacji - The video cannot be federated! + Film nie może być zfederowany! Początek Lokalne Odkrywaj @@ -62,24 +63,24 @@ Prześlij Podgląd obrazu Wybierz plik do przesłania - New video - New blacklist info - Your video is published - Error when publishing your video - New comment - New follow + Nowy film + Nowe informacje o czarnej liście + Twój film został opublikowany + Błąd podczas publikowania filmu + Nowy komentarz + Nowy obserwujący Kanał Filmy Kanały - Fetch every: + Sprawdzaj co: - Never - 15 minutes - 30 minutes - 1 hour - 2 hours - 6 hours - 12 hours + Nigdy + 15 minut + 30 minut + 1 godzina + 2 godziny + 6 godzin + 12 godzin Tak Nie @@ -100,7 +101,7 @@ Dotknij tutaj, aby edytować dane filmu. Podczas wyboru nośnika wystąpił błąd! Pobierz %1$s - The account has been updated! + Konto zostało zaktualizowane! Prywatność Wyloguj Zaloguj @@ -134,6 +135,8 @@ Logo aplikacji Abonamenty + Usuń instancję + Czy na pewno chcesz usunąć tę instancję? Usuń komentarz Czy na pewno usuniesz ten komentarz? Tryb dla filmów wideo @@ -148,7 +151,7 @@ Ostatnie 365 dni Czas trwania - + 10 min)]]> Wyświetl wszystkie kategorie Wyświetl wszystkie licencje @@ -163,7 +166,7 @@ Sortuj według Słowo kluczowe, kanał, film itp. - Sepia Search displays videos and channels that match your search but is not the publisher, nor the owner. If you notice any problems with a video, report it to the administrators on the PeerTube website where the video is published. + Sepia Search wyświetla filmy i kanały pasujące do Twojego wyszukiwania, ale nie jest wydawcą ani właścicielem. Jeśli zauważysz jakiekolwiek problemy z filmem, zgłoś je administratorom na stronie PeerTube, na której film jest publikowany. Moje filmy Tytuł Licencja @@ -212,13 +215,22 @@ %1$s publikuje nowy film: %2$s]]> %1$s został umieszczony na czarnej liście]]> %1$s został usunięty z czarnej listy]]> - %1$s has been accepted]]> + %1$s został zaakceptowany]]> %1$s]]> Dodaj publiczny komentarz Prześlij komentarz Wszystkie + Delete videos history + Are you sure you want to delete all your videos history? + Eksportuj + Importuj + Eksport zakończony sukcesem! + Dotknij tutaj, aby wysłać eksport przez e-mail + Nowa playlista + Otwórz załączony plik przez TubeLab Listy odtwarzania + Brak playlist Wyświetlana nazwa Nie masz żadnej playlisty. Stuknij ikonę \"+\", aby dodać nową listę odtwarzania Musisz podać nazwę wyświetlacza! @@ -248,7 +260,7 @@ Normalny Webview - Magnet + Magnes Torrent @@ -305,7 +317,7 @@ Kategorie wyboru Wybieranie języków Aktualizacja informacji - Fetch notifications + Sprawdź powiadomienia Dodaj konto Lista rachunków Przerwa diff --git a/app/src/full/res/values-pt/strings.xml b/app/src/full/res/values-pt/strings.xml index 5f09498..f93405d 100644 --- a/app/src/full/res/values-pt/strings.xml +++ b/app/src/full/res/values-pt/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -132,6 +133,8 @@ Logótipo do aplicativo Inscrições + Delete an instance + Are you sure to delete this instance? Excluir comentário Tem certeza de que deseja excluir este comentário? Modo para vídeos @@ -216,7 +219,16 @@ Enviar comentário Tudo + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Listas de reprodução + No playlists Nome de exibição You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist Você deve inserir um nome de exibição! diff --git a/app/src/full/res/values-ro/strings.xml b/app/src/full/res/values-ro/strings.xml index 07836f1..21d56bc 100644 --- a/app/src/full/res/values-ro/strings.xml +++ b/app/src/full/res/values-ro/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -133,6 +134,8 @@ Logo of the application Subscriptions + Delete an instance + Are you sure to delete this instance? Delete a comment Are you sure to delete this comment? Mode for videos @@ -217,7 +220,16 @@ Send comment All + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Playlists + No playlists Display name You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist You must provide a display name! diff --git a/app/src/full/res/values-ru/strings.xml b/app/src/full/res/values-ru/strings.xml index 1dd1ba6..c8d071d 100644 --- a/app/src/full/res/values-ru/strings.xml +++ b/app/src/full/res/values-ru/strings.xml @@ -2,6 +2,7 @@ Видео в списке Изменить расположение для отображения видео в списке + No instances ! Показать еще Показать меньше Блокировка экрана @@ -134,6 +135,8 @@ Логотип приложения Подписки + Delete an instance + Are you sure to delete this instance? Удалить комментарий Вы уверены, что хотите удалить этот комментарий? Режим для видео @@ -218,7 +221,16 @@ Оставить комментарий Все + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Плейлисты + No playlists Отображаемое имя У вас нет плейлистов. Нажмите на \"+\", чтобы добавить новый Вы должны указать отображаемое имя! diff --git a/app/src/full/res/values-sv/strings.xml b/app/src/full/res/values-sv/strings.xml index 4f2676a..dd572a3 100644 --- a/app/src/full/res/values-sv/strings.xml +++ b/app/src/full/res/values-sv/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -132,6 +133,8 @@ Applikationens logo Prenumerationer + Delete an instance + Are you sure to delete this instance? Ta bort kommentar Är du säker på att ta bort denna kommentar? Lägen för video @@ -216,7 +219,16 @@ Skicka kommentar Allt + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab Spellistor + No playlists Visningsnamn You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist Du måste ange ett visningsnamn! diff --git a/app/src/full/res/values-zh-rCN/strings.xml b/app/src/full/res/values-zh-rCN/strings.xml index 9115fab..a56b305 100644 --- a/app/src/full/res/values-zh-rCN/strings.xml +++ b/app/src/full/res/values-zh-rCN/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -131,6 +132,8 @@ 应用程序的标志 订阅列表 + Delete an instance + Are you sure to delete this instance? 删除评论 您确定要删除此评论吗? 视频播放模式 @@ -215,7 +218,16 @@ 发送评论 全部 + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab 播放列表 + No playlists 显示昵称 您没有任何播放列表,点击 + 号添加一个新的播放列表 您必须指定一个昵称! diff --git a/app/src/full/res/values-zh-rTW/strings.xml b/app/src/full/res/values-zh-rTW/strings.xml index 708cb88..9fbbfec 100644 --- a/app/src/full/res/values-zh-rTW/strings.xml +++ b/app/src/full/res/values-zh-rTW/strings.xml @@ -2,6 +2,7 @@ Videos in list Change the layout for displaying videos in a list + No instances ! Show more Show less Screen lock @@ -131,6 +132,8 @@ 應用程式圖示 訂閱 + Delete an instance + Are you sure to delete this instance? 刪除留言 您想要刪除此留言嗎? 影片模式 @@ -215,7 +218,16 @@ 傳送留言 全部 + Delete videos history + Are you sure you want to delete all your videos history? + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab 播放清單 + No playlists 顯示名稱 You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist 您必須提供顯示名稱! diff --git a/app/src/full/res/values/strings.xml b/app/src/full/res/values/strings.xml index 0672486..5ffe68b 100644 --- a/app/src/full/res/values/strings.xml +++ b/app/src/full/res/values/strings.xml @@ -16,7 +16,7 @@ set_video_sensitive_choice Videos in list Change the layout for displaying videos in a list - + No instances ! Show more Show less @@ -180,6 +180,9 @@ Subscriptions + Delete an instance + Are you sure to delete this instance? + Delete a comment Are you sure to delete this comment? Mode for videos @@ -280,7 +283,19 @@ All + + Delete videos history + Are you sure you want to delete all your videos history? + + Export + Import + Successful export! + Tap here to send the export by email + New Playlist + Open the attached file with TubeLab + Playlists + No playlists Display name You don\'t have any playlists. Tap on the \"+\" icon to add a new playlist You must provide a display name! diff --git a/app/src/full/res/xml/file_paths.xml b/app/src/full/res/xml/file_paths.xml new file mode 100644 index 0000000..2d5ce66 --- /dev/null +++ b/app/src/full/res/xml/file_paths.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/google_acad/AndroidManifest.xml b/app/src/google_acad/AndroidManifest.xml new file mode 100644 index 0000000..89d0750 --- /dev/null +++ b/app/src/google_acad/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f63e144..c55b5a0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -83,7 +83,11 @@ android:configChanges="orientation|screenSize" android:label="@string/app_name" android:windowSoftInputMode="stateAlwaysHidden" /> - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java index a413d82..8f94d47 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java @@ -37,19 +37,18 @@ import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.tabs.TabLayout; import org.jetbrains.annotations.NotNull; -import java.util.List; - import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; import app.fedilab.fedilabtube.client.data.AccountData.Account; -import app.fedilab.fedilabtube.drawer.OwnAccountsAdapter; import app.fedilab.fedilabtube.fragment.DisplayAccountsFragment; import app.fedilab.fedilabtube.fragment.DisplayChannelsFragment; import app.fedilab.fedilabtube.fragment.DisplayNotificationsFragment; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.helper.SwitchAccountHelper; import app.fedilab.fedilabtube.sqlite.AccountDAO; import app.fedilab.fedilabtube.sqlite.Sqlite; @@ -99,6 +98,8 @@ public class AccountActivity extends AppCompatActivity { displayname.setText(account.getDisplayName()); instanceView.setText(account.getHost()); + FloatingActionButton edit_profile = findViewById(R.id.edit_profile); + edit_profile.setOnClickListener(v -> startActivity(new Intent(AccountActivity.this, MyAccountActivity.class))); Button logout_button = findViewById(R.id.logout_button); logout_button.setOnClickListener(v -> { @@ -210,42 +211,7 @@ public class AccountActivity extends AppCompatActivity { finish(); return true; } else if (item.getItemId() == R.id.action_add_account) { - SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - List accounts = new AccountDAO(AccountActivity.this, db).getAllAccount(); - - AlertDialog.Builder builderSingle = new AlertDialog.Builder(AccountActivity.this); - builderSingle.setTitle(getString(R.string.list_of_accounts)); - if (accounts != null) { - final OwnAccountsAdapter accountsListAdapter = new OwnAccountsAdapter(AccountActivity.this, accounts); - final Account[] accountArray = new Account[accounts.size()]; - int i = 0; - for (Account account : accounts) { - accountArray[i] = account; - i++; - } - builderSingle.setAdapter(accountsListAdapter, (dialog, which) -> { - final Account account = accountArray[which]; - SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, account.getToken()); - editor.putString(Helper.PREF_INSTANCE, account.getHost()); - editor.putString(Helper.PREF_KEY_ID, account.getId()); - editor.putString(Helper.PREF_KEY_NAME, account.getUsername()); - editor.apply(); - dialog.dismiss(); - Intent intent = new Intent(AccountActivity.this, MainActivity.class); - startActivity(intent); - finish(); - }); - } - builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); - builderSingle.setPositiveButton(R.string.add_account, (dialog, which) -> { - Intent intent = new Intent(AccountActivity.this, LoginActivity.class); - startActivity(intent); - finish(); - }); - - builderSingle.show(); + SwitchAccountHelper.switchDialog(AccountActivity.this, true); } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/java/app/fedilab/fedilabtube/AllLocalPlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AllLocalPlaylistsActivity.java new file mode 100644 index 0000000..775edc5 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/AllLocalPlaylistsActivity.java @@ -0,0 +1,120 @@ +package app.fedilab.fedilabtube; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + + +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.fedilabtube.client.data.PlaylistData.Playlist; +import app.fedilab.fedilabtube.client.data.VideoPlaylistData; +import app.fedilab.fedilabtube.drawer.PlaylistAdapter; +import app.fedilab.fedilabtube.viewmodel.PlaylistsVM; + + +public class AllLocalPlaylistsActivity extends AppCompatActivity implements PlaylistAdapter.AllPlaylistRemoved { + + + PlaylistAdapter playlistAdapter; + private RelativeLayout mainLoader; + private RelativeLayout textviewNoAction; + private List playlists; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_all_playlist); + + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + setTitle(R.string.playlists); + + + textviewNoAction = findViewById(R.id.no_action); + mainLoader = findViewById(R.id.loader); + RelativeLayout nextElementLoader = findViewById(R.id.loading_next_items); + mainLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.GONE); + + PlaylistsVM viewModel = new ViewModelProvider(AllLocalPlaylistsActivity.this).get(PlaylistsVM.class); + viewModel.localePlaylist().observe(AllLocalPlaylistsActivity.this, this::manageVIewPlaylists); + + FloatingActionButton add_new = findViewById(R.id.add_new); + add_new.setVisibility(View.GONE); + + TextView no_action_text = findViewById(R.id.no_action_text); + no_action_text.setText(R.string.no_playlist); + playlists = new ArrayList<>(); + RecyclerView lv_playlist = findViewById(R.id.lv_playlist); + playlistAdapter = new PlaylistAdapter(playlists, true); + playlistAdapter.allPlaylistRemoved = this; + lv_playlist.setAdapter(playlistAdapter); + LinearLayoutManager mLayoutManager = new LinearLayoutManager(AllLocalPlaylistsActivity.this); + lv_playlist.setLayoutManager(mLayoutManager); + + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + + public void manageVIewPlaylists(List videoPlaylistExports) { + mainLoader.setVisibility(View.GONE); + if (videoPlaylistExports == null) { + textviewNoAction.setVisibility(View.VISIBLE); + return; + } + if (videoPlaylistExports.size() > 0) { + for (VideoPlaylistData.VideoPlaylistExport videoPlaylistExport : videoPlaylistExports) { + playlists.add(videoPlaylistExport.getPlaylist()); + } + playlistAdapter.notifyDataSetChanged(); + textviewNoAction.setVisibility(View.GONE); + } else { + textviewNoAction.setVisibility(View.VISIBLE); + } + } + + @Override + public void onAllPlaylistRemoved() { + textviewNoAction.setVisibility(View.VISIBLE); + } + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java index bc18507..3fb4710 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java @@ -29,7 +29,6 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; -import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.Toast; @@ -37,6 +36,8 @@ import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -61,7 +62,7 @@ import es.dmoral.toasty.Toasty; import static app.fedilab.fedilabtube.MainActivity.peertubeInformation; -public class AllPlaylistsActivity extends AppCompatActivity { +public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistAdapter.AllPlaylistRemoved { PlaylistAdapter playlistAdapter; @@ -109,10 +110,12 @@ public class AllPlaylistsActivity extends AppCompatActivity { playlists = new ArrayList<>(); - ListView lv_playlist = findViewById(R.id.lv_playlist); - playlistAdapter = new PlaylistAdapter(AllPlaylistsActivity.this, playlists, textviewNoAction); + RecyclerView lv_playlist = findViewById(R.id.lv_playlist); + playlistAdapter = new PlaylistAdapter(playlists, false); + playlistAdapter.allPlaylistRemoved = this; lv_playlist.setAdapter(playlistAdapter); - + LinearLayoutManager mLayoutManager = new LinearLayoutManager(AllPlaylistsActivity.this); + lv_playlist.setLayoutManager(mLayoutManager); add_new.setOnClickListener(view -> manageAlert(null)); } @@ -378,4 +381,9 @@ public class AllPlaylistsActivity extends AppCompatActivity { set_upload_channel.setSelection(position); } } + + @Override + public void onAllPlaylistRemoved() { + textviewNoAction.setVisibility(View.VISIBLE); + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java b/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java index ff2be2c..95cf7b2 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java +++ b/app/src/main/java/app/fedilab/fedilabtube/FedilabTube.java @@ -41,7 +41,7 @@ public class FedilabTube extends MultiDexApplication { .setMinimumLoggingLevel(android.util.Log.INFO) .build(); WorkManager.initialize(FedilabTube.this, myConfig); - if( interval >= 15 ) { + if (interval >= 15) { WorkHelper.fetchNotifications(this, interval); } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/LocalPlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/LocalPlaylistsActivity.java new file mode 100644 index 0000000..653e500 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/LocalPlaylistsActivity.java @@ -0,0 +1,79 @@ +package app.fedilab.fedilabtube; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.os.Bundle; +import android.view.MenuItem; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentTransaction; + +import app.fedilab.fedilabtube.client.data.PlaylistData; +import app.fedilab.fedilabtube.fragment.DisplayVideosFragment; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.viewmodel.TimelineVM; +import es.dmoral.toasty.Toasty; + + +public class LocalPlaylistsActivity extends AppCompatActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + + setContentView(R.layout.activity_playlists); + + + PlaylistData.Playlist playlist; + Bundle b = getIntent().getExtras(); + if (b != null) { + playlist = b.getParcelable("playlist"); + if (playlist == null) { + return; + } + } else { + Toasty.error(LocalPlaylistsActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + return; + } + setTitle(playlist.getDisplayName()); + if (savedInstanceState == null) { + DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable(Helper.TIMELINE_TYPE, TimelineVM.TimelineType.VIDEOS_IN_LOCAL_PLAYLIST); + bundle.putSerializable("playlistId", playlist.getUuid()); + displayVideosFragment.setArguments(bundle); + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.add(R.id.nav_host_fragment, displayVideosFragment).commit(); + } + + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java index 0454cfd..78f3f47 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java @@ -101,7 +101,6 @@ public class LoginActivity extends AppCompatActivity { } - if (!BuildConfig.full_instances) { binding.loginUid.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { @@ -142,7 +141,7 @@ public class LoginActivity extends AppCompatActivity { instance = host = binding.loginInstance.getText().toString().trim().toLowerCase(); } - if( instance.startsWith("http")) { + if (instance.startsWith("http")) { try { URL url = new URL(instance); instance = url.getHost(); @@ -150,8 +149,16 @@ public class LoginActivity extends AppCompatActivity { } catch (MalformedURLException e) { e.printStackTrace(); } + } else if (instance.endsWith("/")) { + try { + URL url = new URL("https://" + instance); + instance = url.getHost(); + host = instance; + } catch (MalformedURLException e) { + e.printStackTrace(); + } } - if (!Patterns.WEB_URL.matcher("https://"+instance).matches()) { + if (!Patterns.WEB_URL.matcher("https://" + instance).matches()) { Toasty.error(LoginActivity.this, getString(R.string.not_valide_instance)).show(); binding.loginButton.setEnabled(true); return; @@ -216,7 +223,7 @@ public class LoginActivity extends AppCompatActivity { oauthParams.setGrant_type("password"); oauthParams.setScope("user"); oauthParams.setUsername(binding.loginUid.getText().toString().trim()); - if( binding.loginPasswd.getText() != null) { + if (binding.loginPasswd.getText() != null) { oauthParams.setPassword(binding.loginPasswd.getText().toString()); } try { diff --git a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java index 993eb56..b2d0c83 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java @@ -26,8 +26,11 @@ import android.os.Bundle; import android.os.Handler; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.widget.EditText; +import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; @@ -36,7 +39,6 @@ import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.lifecycle.ViewModelProvider; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.kobakei.ratethisapp.RateThisApp; @@ -52,7 +54,7 @@ import java.util.regex.Pattern; import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; import app.fedilab.fedilabtube.client.data.AccountData.Account; -import app.fedilab.fedilabtube.client.data.VideoData; +import app.fedilab.fedilabtube.client.data.InstanceData; import app.fedilab.fedilabtube.client.entities.Error; import app.fedilab.fedilabtube.client.entities.OauthParams; import app.fedilab.fedilabtube.client.entities.PeertubeInformation; @@ -63,13 +65,17 @@ import app.fedilab.fedilabtube.client.entities.WellKnownNodeinfo; import app.fedilab.fedilabtube.fragment.DisplayOverviewFragment; import app.fedilab.fedilabtube.fragment.DisplayVideosFragment; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.helper.PlaylistExportHelper; +import app.fedilab.fedilabtube.helper.SwitchAccountHelper; import app.fedilab.fedilabtube.services.RetrieveInfoService; import app.fedilab.fedilabtube.sqlite.AccountDAO; import app.fedilab.fedilabtube.sqlite.Sqlite; -import app.fedilab.fedilabtube.viewmodel.SearchVM; +import app.fedilab.fedilabtube.sqlite.StoredInstanceDAO; import app.fedilab.fedilabtube.viewmodel.TimelineVM; import es.dmoral.toasty.Toasty; +import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.NORMAL; +import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.SURFING; import static app.fedilab.fedilabtube.helper.Helper.academies; public class MainActivity extends AppCompatActivity { @@ -77,33 +83,34 @@ public class MainActivity extends AppCompatActivity { public static PeertubeInformation peertubeInformation; public static int PICK_INSTANCE = 5641; + public static int PICK_INSTANCE_SURF = 5642; + public static UserMe userMe; + public static TypeOfConnection typeOfConnection; final FragmentManager fm = getSupportFragmentManager(); Fragment active; private DisplayVideosFragment recentFragment, locaFragment, trendingFragment, subscriptionFragment, mostLikedFragment; private DisplayOverviewFragment overviewFragment; - public static UserMe userMe; - private final BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = item -> { DisplayVideosFragment displayVideosFragment = null; int itemId = item.getItemId(); if (itemId == R.id.navigation_subscription) { displayVideosFragment = subscriptionFragment; - setTitle(R.string.subscriptions); + setTitleCustom(R.string.subscriptions); } else if (itemId == R.id.navigation_trending) { - setTitle(R.string.title_trending); + setTitleCustom(R.string.title_trending); displayVideosFragment = trendingFragment; } else if (itemId == R.id.navigation_most_liked) { - setTitle(R.string.title_most_liked); + setTitleCustom(R.string.title_most_liked); displayVideosFragment = mostLikedFragment; } else if (itemId == R.id.navigation_recently_added) { - setTitle(R.string.title_recently_added); + setTitleCustom(R.string.title_recently_added); displayVideosFragment = recentFragment; } else if (itemId == R.id.navigation_local) { - setTitle(R.string.title_local); + setTitleCustom(R.string.title_local); displayVideosFragment = locaFragment; } else if (itemId == R.id.navigation_discover) { - setTitle(R.string.title_discover); + setTitleCustom(R.string.title_discover); fm.beginTransaction().hide(active).show(overviewFragment).commit(); active = overviewFragment; return true; @@ -117,6 +124,71 @@ public class MainActivity extends AppCompatActivity { } }; + @SuppressLint("ApplySharedPref") + public static void showRadioButtonDialogFullInstances(Activity activity, boolean storeInDb) { + final SharedPreferences sharedpreferences = activity.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + AlertDialog.Builder alt_bld = new AlertDialog.Builder(activity); + alt_bld.setTitle(R.string.instance_choice); + String instance = Helper.getLiveInstance(activity); + final EditText input = new EditText(activity); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + input.setLayoutParams(lp); + alt_bld.setView(input); + input.setText(instance); + alt_bld.setPositiveButton(R.string.validate, + (dialog, which) -> new Thread(() -> { + try { + String newInstance = input.getText().toString().trim(); + WellKnownNodeinfo.NodeInfo instanceNodeInfo = new RetrofitPeertubeAPI(activity, newInstance, null).getNodeInfo(); + if (instanceNodeInfo.getSoftware() != null && instanceNodeInfo.getSoftware().getName().trim().toLowerCase().compareTo("peertube") == 0) { + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.PREF_INSTANCE, newInstance); + editor.commit(); + if (storeInDb) { + newInstance = newInstance.trim().toLowerCase(); + InstanceData.AboutInstance aboutInstance = new RetrofitPeertubeAPI(activity, newInstance, null).getAboutInstance(); + SQLiteDatabase db = Sqlite.getInstance(activity.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + new StoredInstanceDAO(activity, db).insertInstance(aboutInstance, newInstance); + activity.runOnUiThread(() -> { + dialog.dismiss(); + Helper.logoutNoRemoval(activity); + }); + } else { + activity.runOnUiThread(() -> { + dialog.dismiss(); + Intent intent = new Intent(activity, MainActivity.class); + activity.startActivity(intent); + }); + } + } else { + activity.runOnUiThread(() -> Toasty.error(activity, activity.getString(R.string.not_valide_instance), Toast.LENGTH_LONG).show()); + } + } catch (Exception e) { + e.printStackTrace(); + } + + }).start()); + alt_bld.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + alt_bld.setNeutralButton(R.string.help, (dialog, which) -> { + Intent intent = new Intent(activity, InstancePickerActivity.class); + if (storeInDb) { + activity.startActivityForResult(intent, PICK_INSTANCE_SURF); + } else { + activity.startActivityForResult(intent, PICK_INSTANCE); + } + }); + AlertDialog alert = alt_bld.create(); + alert.show(); + } + + private void setTitleCustom(int titleRId) { + Toolbar toolbar = findViewById(R.id.toolbar); + TextView mTitle = toolbar.findViewById(R.id.toolbar_title); + mTitle.setText(getString(titleRId)); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -125,10 +197,17 @@ public class MainActivity extends AppCompatActivity { Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); + typeOfConnection = TypeOfConnection.UNKNOWN; + BottomNavigationView navView = findViewById(R.id.nav_view); navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayShowTitleEnabled(false); + } + checkIfConnectedUsers(); + Fragment fragment = getSupportFragmentManager().findFragmentByTag("5"); if (fragment != null) getSupportFragmentManager().beginTransaction().remove(fragment).commit(); @@ -192,35 +271,36 @@ public class MainActivity extends AppCompatActivity { } }); - setTitle(R.string.title_discover); + setTitleCustom(R.string.title_discover); if (Helper.isLoggedIn(MainActivity.this)) { + navView.inflateMenu(R.menu.bottom_nav_menu_connected); - new Thread(() -> { - final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - String tokenStr = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); - String instance = Helper.getLiveInstance(MainActivity.this); - SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - String instanceShar = sharedpreferences.getString(Helper.PREF_INSTANCE, null); - String userIdShar = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - Account account = new AccountDAO(MainActivity.this, db).getAccountByToken(tokenStr); - if( account == null) { - account = new AccountDAO(MainActivity.this, db).getAccountByIdInstance(userIdShar, instanceShar); - } - if (account != null) { - Account finalAccount = account; - OauthParams oauthParams = new OauthParams(); - oauthParams.setGrant_type("refresh_token"); - oauthParams.setClient_id(account.getClient_id()); - oauthParams.setClient_secret(account.getClient_secret()); - oauthParams.setRefresh_token(account.getRefresh_token()); - oauthParams.setAccess_token(account.getToken()); + new Thread(() -> { + final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String tokenStr = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); + String instance = Helper.getLiveInstance(MainActivity.this); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + String instanceShar = sharedpreferences.getString(Helper.PREF_INSTANCE, null); + String userIdShar = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + Account account = new AccountDAO(MainActivity.this, db).getAccountByToken(tokenStr); + if (account == null) { + account = new AccountDAO(MainActivity.this, db).getAccountByIdInstance(userIdShar, instanceShar); + } + if (account != null) { + Account finalAccount = account; + OauthParams oauthParams = new OauthParams(); + oauthParams.setGrant_type("refresh_token"); + oauthParams.setClient_id(account.getClient_id()); + oauthParams.setClient_secret(account.getClient_secret()); + oauthParams.setRefresh_token(account.getRefresh_token()); + oauthParams.setAccess_token(account.getToken()); try { Token token = new RetrofitPeertubeAPI(MainActivity.this).manageToken(oauthParams); if (token == null && Helper.instanceOnline(instance)) { runOnUiThread(() -> Helper.logoutCurrentUser(MainActivity.this, finalAccount)); return; - }else if(token == null) { + } else if (token == null) { return; } runOnUiThread(() -> { @@ -261,7 +341,8 @@ public class MainActivity extends AppCompatActivity { runOnUiThread(() -> Helper.logoutCurrentUser(MainActivity.this, finalAccount)); error.printStackTrace(); } - }}).start(); + } + }).start(); } else { navView.inflateMenu(R.menu.bottom_nav_menu); @@ -279,7 +360,9 @@ public class MainActivity extends AppCompatActivity { RateThisApp.onCreate(this); RateThisApp.showRateDialogIfNeeded(this); } - + if (!BuildConfig.full_instances) { + PlaylistExportHelper.manageIntentUrl(MainActivity.this, getIntent()); + } } private void startInForeground() { @@ -303,11 +386,11 @@ public class MainActivity extends AppCompatActivity { Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})$"); Matcher matcherLink = link.matcher(query.trim()); if (matcherLink.find()) { - Intent intent = new Intent(MainActivity.this, PeertubeActivity.class); - intent.setData(Uri.parse(query.trim())); - startActivity(intent); - myActionMenuItem.collapseActionView(); - return false; + Intent intent = new Intent(MainActivity.this, PeertubeActivity.class); + intent.setData(Uri.parse(query.trim())); + startActivity(intent); + myActionMenuItem.collapseActionView(); + return false; } Intent intent = new Intent(MainActivity.this, SearchActivity.class); Bundle b = new Bundle(); @@ -327,7 +410,7 @@ public class MainActivity extends AppCompatActivity { return false; } }); - MenuItem instanceItem = menu.findItem(R.id.action_change_instance); + MenuItem uploadItem = menu.findItem(R.id.action_upload); MenuItem myVideosItem = menu.findItem(R.id.action_myvideos); MenuItem playslistItem = menu.findItem(R.id.action_playlist); @@ -336,40 +419,104 @@ public class MainActivity extends AppCompatActivity { MenuItem settingsItem = menu.findItem(R.id.action_settings); MenuItem sepiaSearchItem = menu.findItem(R.id.action_sepia_search); MenuItem incognitoItem = menu.findItem(R.id.action_incognito); - if (Helper.isLoggedIn(MainActivity.this)) { - instanceItem.setVisible(false); - uploadItem.setVisible(true); - myVideosItem.setVisible(true); - playslistItem.setVisible(true); - historyItem.setVisible(true); - settingsItem.setVisible(false); - mostLikedItem.setVisible(true); - incognitoItem.setVisible(true); - final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - boolean checked = sharedpreferences.getBoolean(getString(R.string.set_store_in_history), true); - incognitoItem.setChecked(checked); + MenuItem instanceItem = menu.findItem(R.id.action_change_instance); + MenuItem accountItem = menu.findItem(R.id.action_account); + + Toolbar toolbar = findViewById(R.id.toolbar); + ImageView instances = toolbar.findViewById(R.id.instances); + if (BuildConfig.full_instances && ((Helper.isLoggedIn(MainActivity.this) && typeOfConnection == NORMAL) || typeOfConnection == SURFING)) { + instances.setVisibility(View.VISIBLE); + instances.setOnClickListener(null); + instances.setOnClickListener(v -> { + Intent intent = new Intent(MainActivity.this, ManageInstancesActivity.class); + startActivity(intent); + overridePendingTransition(R.anim.slide_in_up, R.anim.slide_out_up); + }); } else { - instanceItem.setVisible(true); - uploadItem.setVisible(false); - myVideosItem.setVisible(false); - playslistItem.setVisible(false); - historyItem.setVisible(false); - settingsItem.setVisible(true); - mostLikedItem.setVisible(false); - incognitoItem.setVisible(false); + instances.setVisibility(View.GONE); } + switch (typeOfConnection) { + case UNKNOWN: + instanceItem.setVisible(false); + accountItem.setVisible(false); + uploadItem.setVisible(false); + myVideosItem.setVisible(false); + playslistItem.setVisible(false); + historyItem.setVisible(false); + settingsItem.setVisible(false); + mostLikedItem.setVisible(false); + incognitoItem.setVisible(false); + break; + case NORMAL: + accountItem.setVisible(true); + if (Helper.isLoggedIn(MainActivity.this)) { + instanceItem.setVisible(false); + uploadItem.setVisible(true); + myVideosItem.setVisible(true); + playslistItem.setVisible(true); + historyItem.setVisible(true); + settingsItem.setVisible(false); + mostLikedItem.setVisible(true); + incognitoItem.setVisible(true); + final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean checked = sharedpreferences.getBoolean(getString(R.string.set_store_in_history), true); + incognitoItem.setChecked(checked); + } else { + instanceItem.setVisible(true); + uploadItem.setVisible(false); + myVideosItem.setVisible(false); + playslistItem.setVisible(!BuildConfig.full_instances); + historyItem.setVisible(false); + settingsItem.setVisible(true); + mostLikedItem.setVisible(false); + incognitoItem.setVisible(false); + } + break; + case SURFING: + instanceItem.setVisible(false); + accountItem.setVisible(true); + uploadItem.setVisible(false); + myVideosItem.setVisible(false); + playslistItem.setVisible(false); + historyItem.setVisible(false); + settingsItem.setVisible(false); + mostLikedItem.setVisible(false); + incognitoItem.setVisible(false); + break; + } + + if (!BuildConfig.full_instances) { sepiaSearchItem.setVisible(false); } return true; } + private void checkIfConnectedUsers() { + new Thread(() -> { + try { + typeOfConnection = NORMAL; + if (!Helper.isLoggedIn(MainActivity.this)) { + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + List accounts = new AccountDAO(MainActivity.this, db).getAllAccount(); + if (accounts != null && accounts.size() > 0) { + //The user is not authenticated and there accounts in db. That means the user is surfing some other instances + typeOfConnection = TypeOfConnection.SURFING; + } + } + runOnUiThread(this::invalidateOptionsMenu); + + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_change_instance) { if (BuildConfig.full_instances) { - showRadioButtonDialogFullInstances(); + showRadioButtonDialogFullInstances(MainActivity.this, false); } else { showRadioButtonDialog(); } @@ -379,12 +526,16 @@ public class MainActivity extends AppCompatActivity { startActivity(intent); } else if (item.getItemId() == R.id.action_account) { Intent intent; - if (Helper.isLoggedIn(MainActivity.this)) { - intent = new Intent(MainActivity.this, AccountActivity.class); + if (typeOfConnection == SURFING) { + SwitchAccountHelper.switchDialog(MainActivity.this, false); } else { - intent = new Intent(MainActivity.this, LoginActivity.class); + if (Helper.isLoggedIn(MainActivity.this)) { + intent = new Intent(MainActivity.this, AccountActivity.class); + } else { + intent = new Intent(MainActivity.this, LoginActivity.class); + } + startActivity(intent); } - startActivity(intent); return true; } else if (item.getItemId() == R.id.action_upload) { Intent intent = new Intent(MainActivity.this, PeertubeUploadActivity.class); @@ -412,7 +563,12 @@ public class MainActivity extends AppCompatActivity { startActivity(intent); return true; } else if (item.getItemId() == R.id.action_playlist) { - Intent intent = new Intent(MainActivity.this, AllPlaylistsActivity.class); + Intent intent; + if (Helper.isLoggedIn(MainActivity.this)) { + intent = new Intent(MainActivity.this, AllPlaylistsActivity.class); + } else { + intent = new Intent(MainActivity.this, AllLocalPlaylistsActivity.class); + } startActivity(intent); return true; } else if (item.getItemId() == R.id.action_sepia_search) { @@ -463,9 +619,12 @@ public class MainActivity extends AppCompatActivity { if (extras.getInt(Helper.INTENT_ACTION) == Helper.ADD_USER_INTENT) { recreate(); } + } else if (!BuildConfig.full_instances) { + PlaylistExportHelper.manageIntentUrl(MainActivity.this, intent); } } + @SuppressLint("ApplySharedPref") private void showRadioButtonDialog() { @@ -493,50 +652,6 @@ public class MainActivity extends AppCompatActivity { alert.show(); } - @SuppressLint("ApplySharedPref") - private void showRadioButtonDialogFullInstances() { - final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - AlertDialog.Builder alt_bld = new AlertDialog.Builder(this); - alt_bld.setTitle(R.string.instance_choice); - String instance = Helper.getLiveInstance(MainActivity.this); - final EditText input = new EditText(MainActivity.this); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT); - input.setLayoutParams(lp); - alt_bld.setView(input); - input.setText(instance); - alt_bld.setPositiveButton(R.string.validate, - (dialog, which) -> new Thread(() -> { - try { - String newInstance = input.getText().toString().trim(); - WellKnownNodeinfo.NodeInfo instanceNodeInfo = new RetrofitPeertubeAPI(MainActivity.this, newInstance, null).getNodeInfo(); - if (instanceNodeInfo.getSoftware() != null && instanceNodeInfo.getSoftware().getName().trim().toLowerCase().compareTo("peertube") == 0) { - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.PREF_INSTANCE, newInstance); - editor.commit(); - runOnUiThread(() -> { - dialog.dismiss(); - recreate(); - }); - } else { - runOnUiThread(() -> Toasty.error(MainActivity.this, getString(R.string.not_valide_instance), Toast.LENGTH_LONG).show()); - } - } catch (Exception e) { - e.printStackTrace(); - } - - }).start()); - alt_bld.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); - alt_bld.setNeutralButton(R.string.help, (dialog, which) -> { - Intent intent = new Intent(MainActivity.this, InstancePickerActivity.class); - startActivityForResult(intent, PICK_INSTANCE); - }); - AlertDialog alert = alt_bld.create(); - alert.show(); - } - - @SuppressLint("ApplySharedPref") @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -547,8 +662,15 @@ public class MainActivity extends AppCompatActivity { SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(Helper.PREF_INSTANCE, String.valueOf(data.getData())); editor.commit(); - recreate(); + finish(); } } } + + + public enum TypeOfConnection { + UNKNOWN, + NORMAL, + SURFING + } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/ManageInstancesActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ManageInstancesActivity.java new file mode 100644 index 0000000..c5963b4 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/ManageInstancesActivity.java @@ -0,0 +1,130 @@ +package app.fedilab.fedilabtube; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.os.Handler; +import android.view.MenuItem; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; +import app.fedilab.fedilabtube.client.data.InstanceData; +import app.fedilab.fedilabtube.databinding.ActivityManageInstancesBinding; +import app.fedilab.fedilabtube.drawer.AboutInstanceAdapter; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.sqlite.Sqlite; +import app.fedilab.fedilabtube.sqlite.StoredInstanceDAO; +import app.fedilab.fedilabtube.viewmodel.InfoInstanceVM; + +import static app.fedilab.fedilabtube.MainActivity.PICK_INSTANCE_SURF; +import static app.fedilab.fedilabtube.MainActivity.showRadioButtonDialogFullInstances; + + +public class ManageInstancesActivity extends AppCompatActivity implements AboutInstanceAdapter.AllInstancesRemoved { + + private ActivityManageInstancesBinding binding; + private List aboutInstances; + private AboutInstanceAdapter aboutInstanceAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = ActivityManageInstancesBinding.inflate(getLayoutInflater()); + View view = binding.getRoot(); + setContentView(view); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + binding.loader.setVisibility(View.VISIBLE); + binding.noAction.setVisibility(View.GONE); + binding.lvInstances.setVisibility(View.GONE); + binding.actionButton.setOnClickListener(v -> showRadioButtonDialogFullInstances(ManageInstancesActivity.this, true)); + aboutInstances = new ArrayList<>(); + aboutInstanceAdapter = new AboutInstanceAdapter(this.aboutInstances); + aboutInstanceAdapter.allInstancesRemoved = this; + binding.lvInstances.setAdapter(aboutInstanceAdapter); + LinearLayoutManager layoutManager + = new LinearLayoutManager(ManageInstancesActivity.this); + binding.lvInstances.setLayoutManager(layoutManager); + InfoInstanceVM viewModelInfoInstance = new ViewModelProvider(ManageInstancesActivity.this).get(InfoInstanceVM.class); + viewModelInfoInstance.getInstances().observe(ManageInstancesActivity.this, this::manageVIewInfoInstance); + } + + private void manageVIewInfoInstance(List aboutInstances) { + binding.loader.setVisibility(View.GONE); + if (aboutInstances == null || aboutInstances.size() == 0) { + binding.noAction.setVisibility(View.VISIBLE); + binding.lvInstances.setVisibility(View.GONE); + return; + } + binding.noAction.setVisibility(View.GONE); + binding.lvInstances.setVisibility(View.VISIBLE); + this.aboutInstances.addAll(aboutInstances); + aboutInstanceAdapter.notifyItemRangeInserted(0, aboutInstances.size()); + + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + overridePendingTransition(R.anim.slide_out_up, R.anim.slide_in_up_down); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + overridePendingTransition(R.anim.slide_out_up, R.anim.slide_in_up_down); + return true; + } + return super.onOptionsItemSelected(item); + } + + + @SuppressLint("ApplySharedPref") + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_INSTANCE_SURF && resultCode == Activity.RESULT_OK) { + if (data != null && data.getData() != null) { + new Thread(() -> { + String newInstance = data.getData().toString().trim().toLowerCase(); + InstanceData.AboutInstance aboutInstance = new RetrofitPeertubeAPI(ManageInstancesActivity.this, newInstance, null).getAboutInstance(); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + new StoredInstanceDAO(ManageInstancesActivity.this, db).insertInstance(aboutInstance, newInstance); + runOnUiThread(() -> new Handler().post(() -> Helper.logoutNoRemoval(ManageInstancesActivity.this))); + }).start(); + } + } + } + + @Override + public void onAllInstancesRemoved() { + binding.noAction.setVisibility(View.VISIBLE); + binding.lvInstances.setVisibility(View.GONE); + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/MyAccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MyAccountActivity.java index 39f49f6..e554a8d 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MyAccountActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MyAccountActivity.java @@ -13,6 +13,7 @@ package app.fedilab.fedilabtube; * * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ + import android.Manifest; import android.app.Activity; import android.content.Context; @@ -59,10 +60,10 @@ import static app.fedilab.fedilabtube.worker.WorkHelper.NOTIFICATION_WORKER; public class MyAccountActivity extends AppCompatActivity { - ActivityMyAccountSettingsBinding binding; private static final int PICK_IMAGE = 466; + ActivityMyAccountSettingsBinding binding; private Uri inputData; - private String fileName; + private String fileName; private NotificationSettings notificationSettings; @Override @@ -74,11 +75,11 @@ public class MyAccountActivity extends AppCompatActivity { if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); - if( MainActivity.userMe == null) { - finish(); - return; + if (MainActivity.userMe == null) { + finish(); + return; } - setTitle(String.format("@%s",MainActivity.userMe.getUsername())); + setTitle(String.format("@%s", MainActivity.userMe.getUsername())); binding.displayname.setText(MainActivity.userMe.getAccount().getDisplayName()); binding.description.setText(MainActivity.userMe.getAccount().getDescription()); @@ -93,7 +94,7 @@ public class MyAccountActivity extends AppCompatActivity { initializeValues(notificationSettings.getNewCommentOnMyVideo(), binding.notifNewCommentApp, binding.notifNewCommentMail); initializeValues(notificationSettings.getNewVideoFromSubscription(), binding.notifNewVideoApp, binding.notifNewVideoMail); - Helper.loadGiF(MyAccountActivity.this, MainActivity.userMe.getAccount().getAvatar()!=null?MainActivity.userMe.getAccount().getAvatar().getPath():null, binding.profilePicture); + Helper.loadGiF(MyAccountActivity.this, MainActivity.userMe.getAccount().getAvatar() != null ? MainActivity.userMe.getAccount().getAvatar().getPath() : null, binding.profilePicture); String[] refresh_array = getResources().getStringArray(R.array.refresh_time); ArrayAdapter refreshArray = new ArrayAdapter<>(MyAccountActivity.this, @@ -132,7 +133,7 @@ public class MyAccountActivity extends AppCompatActivity { editor.putInt(Helper.NOTIFICATION_INTERVAL, time); editor.apply(); WorkManager.getInstance(getApplicationContext()).cancelAllWorkByTag(NOTIFICATION_WORKER); - if( time > 0 ) { + if (time > 0) { WorkHelper.fetchNotifications(getApplication(), time); } @@ -169,7 +170,7 @@ public class MyAccountActivity extends AppCompatActivity { } binding.refreshTime.setSelection(position, false); - binding.selectFile.setOnClickListener(v->{ + binding.selectFile.setOnClickListener(v -> { if (ContextCompat.checkSelfPermission(MyAccountActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MyAccountActivity.this, @@ -204,13 +205,13 @@ public class MyAccountActivity extends AppCompatActivity { new Thread(() -> { UserSettings userSettings = new UserSettings(); userSettings.setNotificationSettings(notificationSettings); - if( binding.displayname.getText() != null) { + if (binding.displayname.getText() != null) { userSettings.setDisplayName(binding.displayname.getText().toString().trim()); } - if( binding.description.getText() != null) { + if (binding.description.getText() != null) { userSettings.setDescription(binding.description.getText().toString().trim()); } - if( inputData != null ) { + if (inputData != null) { userSettings.setAvatarfile(inputData); userSettings.setFileName(fileName); } @@ -219,7 +220,7 @@ public class MyAccountActivity extends AppCompatActivity { UserMe.AvatarResponse avatarResponse = api.updateUser(userSettings); MainActivity.userMe.getAccount().setDisplayName(binding.displayname.getText().toString().trim()); MainActivity.userMe.getAccount().setDescription(binding.description.getText().toString().trim()); - if( avatarResponse != null && avatarResponse.getAvatar() != null ) { + if (avatarResponse != null && avatarResponse.getAvatar() != null) { MainActivity.userMe.getAccount().setAvatar(avatarResponse.getAvatar()); } @@ -329,29 +330,29 @@ public class MyAccountActivity extends AppCompatActivity { }); } - private int getNewAppCheckedValue(boolean checked, SwitchCompat email){ + private int getNewAppCheckedValue(boolean checked, SwitchCompat email) { int newValue; - if( checked && email.isChecked()) { + if (checked && email.isChecked()) { newValue = 3; - }else if( !checked && email.isChecked()) { + } else if (!checked && email.isChecked()) { newValue = 2; - } else if( checked && !email.isChecked()) { + } else if (checked && !email.isChecked()) { newValue = 1; - }else { + } else { newValue = 0; } return newValue; } - private int getNewMailCheckedValue(boolean checked, SwitchCompat app){ + private int getNewMailCheckedValue(boolean checked, SwitchCompat app) { int newValue; - if( checked && app.isChecked()) { + if (checked && app.isChecked()) { newValue = 3; - }else if( !checked && app.isChecked()) { + } else if (!checked && app.isChecked()) { newValue = 1; - } else if( checked && !app.isChecked()) { + } else if (checked && !app.isChecked()) { newValue = 2; - }else { + } else { newValue = 0; } return newValue; diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java index d802dc0..d30280c 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java @@ -39,7 +39,6 @@ import android.support.v4.media.session.MediaSessionCompat; import android.text.Html; import android.text.Spanned; import android.util.DisplayMetrics; -import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -62,6 +61,7 @@ import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.PopupMenu; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; @@ -153,6 +153,7 @@ import static com.google.android.exoplayer2.Player.MEDIA_ITEM_TRANSITION_REASON_ public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved, Player.EventListener, VideoListener, TorrentListener { public static String video_id; + public static List playedVideos = new ArrayList<>(); private String peertubeInstance, videoUuid; private FullScreenMediaController.fullscreen fullscreen; private ImageView fullScreenIcon; @@ -176,16 +177,26 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd private List commentsThread; private BroadcastReceiver mPowerKeyReceiver = null; private boolean isPlayInMinimized; - public static List playedVideos = new ArrayList<>(); private VideoData.Video nextVideo; private TorrentStream torrentStream; private String show_more_content; + private videoOrientation videoOrientationType; + private int initialOrientation; + + public static void hideKeyboard(Activity activity) { + if (activity != null && activity.getWindow() != null) { + activity.getWindow().getDecorView(); + InputMethodManager imm = (InputMethodManager) activity.getSystemService(INPUT_METHOD_SERVICE); + assert imm != null; + imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0); + } + } @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - if(width < height){ + if (width < height) { videoOrientationType = videoOrientation.PORTRAIT; - }else{ + } else { videoOrientationType = videoOrientation.LANDSCAPE; } } @@ -214,22 +225,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } @Override - public void onStreamStopped() {} - - enum videoOrientation { - LANDSCAPE, - PORTRAIT - } - - private videoOrientation videoOrientationType; - - public static void hideKeyboard(Activity activity) { - if (activity != null && activity.getWindow() != null) { - activity.getWindow().getDecorView(); - InputMethodManager imm = (InputMethodManager) activity.getSystemService(INPUT_METHOD_SERVICE); - assert imm != null; - imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0); - } + public void onStreamStopped() { } @Override @@ -258,7 +254,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd torrentStream = TorrentStream.init(torrentOptions); torrentStream.addListener(PeertubeActivity.this); - + initialOrientation = getResources().getConfiguration().orientation; if (Helper.isTablet(PeertubeActivity.this)) { LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( @@ -267,6 +263,15 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd 2.0f ); binding.videoContainer.setLayoutParams(param); + } else { + if (initialOrientation == Configuration.ORIENTATION_LANDSCAPE) { + LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_PARENT, + 0, + 3.0f + ); + binding.videoContainer.setLayoutParams(param); + } } isPlayInMinimized = false; if (getSupportActionBar() != null) @@ -287,12 +292,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd manageIntentUrl(intent); - binding.peertubeDescriptionMore.setOnClickListener(v->{ - if( show_more_content != null && peertube != null) { - if( binding.peertubeDescriptionMore.getText().toString().compareTo(getString(R.string.show_more)) == 0) { + binding.peertubeDescriptionMore.setOnClickListener(v -> { + if (show_more_content != null && peertube != null) { + if (binding.peertubeDescriptionMore.getText().toString().compareTo(getString(R.string.show_more)) == 0) { binding.peertubeDescriptionMore.setText(getString(R.string.show_less)); binding.peertubeDescription.setText(show_more_content); - }else{ + } else { binding.peertubeDescriptionMore.setText(getString(R.string.show_more)); binding.peertubeDescription.setText(peertube.getDescription()); } @@ -328,7 +333,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd binding.peertubeInformationContainer.setVisibility(View.GONE); if (videoOrientationType == videoOrientation.LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - }else { + } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } } else { @@ -372,11 +377,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd public void onAnimationEnd() { binding.mediaVideo.setVisibility(View.GONE); } - }) .playerView(binding.doubleTapPlayerView).seekSeconds(10); + }).playerView(binding.doubleTapPlayerView).seekSeconds(10); binding.doubleTapPlayerView.setPlayer(player); binding.doubleTapPlayerView.controller(binding.mediaVideo); - if( player != null) - binding.mediaVideo.player(player); + if (player != null) + binding.mediaVideo.player(player); } flag_loading = true; comments = new ArrayList<>(); @@ -412,26 +417,25 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd playVideo(); } registBroadcastReceiver(); - if( autoFullscreen && autoPlay) { + if (autoFullscreen && autoPlay) { openFullscreenDialog(); if (videoOrientationType == videoOrientation.LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - }else { + } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } } - binding.postCommentButton.setOnClickListener(v-> openPostComment(null, 0)); + binding.postCommentButton.setOnClickListener(v -> openPostComment(null, 0)); } - private void manageVIewVideos(APIResponse apiResponse) { if (apiResponse == null || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) { playVideo(); return; } peertube = apiResponse.getPeertubes().get(0); - if( peertube.getUserHistory() != null) { - player.seekTo(peertube.getUserHistory().getCurrentTime()*1000); + if (peertube.getUserHistory() != null) { + player.seekTo(peertube.getUserHistory().getCurrentTime() * 1000); } sepiaSearch = false; playVideo(); @@ -460,7 +464,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - public void manageVIewCommentReply(Comment comment, APIResponse apiResponse) { if (apiResponse == null || apiResponse.getError() != null || apiResponse.getCommentThreadData() == null) { if (apiResponse == null || apiResponse.getError() == null) @@ -505,7 +508,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd if (b != null) { peertubeInstance = b.getString("peertube_instance", Helper.getLiveInstance(PeertubeActivity.this)); videoUuid = b.getString("video_uuid", null); - if( comments != null && comments.size() > 0) { + if (comments != null && comments.size() > 0) { int number = comments.size(); comments.clear(); commentListAdapter.notifyItemRangeRemoved(0, number); @@ -516,14 +519,14 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } private void manageIntentUrl(Intent intent) { - if(intent.getData() != null) { //Comes from a link + if (intent.getData() != null) { //Comes from a link String url = intent.getData().toString(); Pattern link = Pattern.compile("(https?://[\\da-z.-]+\\.[a-z.]{2,10})/videos/watch/(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})$"); Matcher matcherLink = link.matcher(url); if (matcherLink.find()) { String instance = matcherLink.group(1); String uuid = matcherLink.group(2); - if(instance != null && uuid != null) { + if (instance != null && uuid != null) { peertubeInstance = instance.replace("https://", "").replace("http://", ""); sepiaSearch = true; // Sepia search flag is used because, at this time we don't know if the video is federated. videoUuid = uuid; @@ -532,11 +535,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd peertube.setEmbedUrl(url); SearchVM viewModelSearch = new ViewModelProvider(PeertubeActivity.this).get(SearchVM.class); viewModelSearch.getVideos("0", peertube.getEmbedUrl()).observe(PeertubeActivity.this, this::manageVIewVideos); - }else { + } else { Helper.forwardToAnotherApp(PeertubeActivity.this, intent); finish(); } - }else{ + } else { Helper.forwardToAnotherApp(PeertubeActivity.this, intent); finish(); } @@ -555,14 +558,14 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } show_more_content = null; binding.peertubeDescriptionMore.setVisibility(View.GONE); - if( autoFullscreen && autoPlay) { + if (autoFullscreen && autoPlay) { fullscreen = FullScreenMediaController.fullscreen.ON; setFullscreen(FullScreenMediaController.fullscreen.ON); fullScreenMode = true; openFullscreenDialog(); if (videoOrientationType == videoOrientation.LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - }else { + } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } } else { @@ -582,12 +585,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd VideoData.Description description = api.getVideoDescription(videoUuid); Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = () -> { - if( description == null) { + if (description == null) { binding.peertubeDescriptionMore.setVisibility(View.GONE); show_more_content = null; - }else{ - if( !PeertubeActivity.this.isFinishing()) { - if (peertube != null && peertube.getDescription() != null && description.getDescription().compareTo(peertube.getDescription()) > 0) { + } else { + if (!PeertubeActivity.this.isFinishing()) { + if (peertube != null && peertube.getDescription() != null && description.getDescription() != null && description.getDescription().compareTo(peertube.getDescription()) > 0) { binding.peertubeDescriptionMore.setVisibility(View.VISIBLE); show_more_content = description.getDescription(); } else { @@ -619,7 +622,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { @@ -677,7 +679,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd this.fullscreen = fullscreen; } - public void manageCaptions(APIResponse apiResponse) { if (apiResponse == null || (apiResponse.getError() != null) || apiResponse.getCaptions() == null || apiResponse.getCaptions().size() == 0) { return; @@ -685,14 +686,13 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd captions = apiResponse.getCaptions(); } - public void manageNextVideos(APIResponse apiResponse) { if (apiResponse == null || apiResponse.getError() != null || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) { return; } List suggestedVideos = apiResponse.getPeertubes(); - for(VideoData.Video video: suggestedVideos) { - if(!playedVideos.contains(video.getId())){ + for (VideoData.Video video : suggestedVideos) { + if (!playedVideos.contains(video.getId())) { TimelineVM feedsViewModel = new ViewModelProvider(PeertubeActivity.this).get(TimelineVM.class); feedsViewModel.getVideo(null, suggestedVideos.get(0).getUuid(), false).observe(PeertubeActivity.this, this::nextVideoDetails); return; @@ -706,7 +706,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd return; } int i = 0; - while (i < (apiResponse.getPeertubes().size()-1) && playedVideos.contains(apiResponse.getPeertubes().get(i).getId())) { + while (i < (apiResponse.getPeertubes().size() - 1) && playedVideos.contains(apiResponse.getPeertubes().get(i).getId())) { i++; } nextVideo = apiResponse.getPeertubes().get(i); @@ -714,7 +714,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd player.addMediaItem(mediaItem); } - @SuppressLint("ClickableViewAccessibility") public void manageVIewVideo(APIResponse apiResponse) { if (apiResponse == null || (apiResponse.getError() != null) || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) { @@ -728,12 +727,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd return; } long position = -1; - if( peertube.getUserHistory() != null) { + if (peertube.getUserHistory() != null) { position = peertube.getUserHistory().getCurrentTime() * 1000; } peertube = apiResponse.getPeertubes().get(0); - if( peertube.getTags() != null && peertube.getTags().size() > 0) { + if (peertube.getTags() != null && peertube.getTags().size() > 0) { SearchVM searchViewModel = new ViewModelProvider(PeertubeActivity.this).get(SearchVM.class); searchViewModel.searchNextVideos(peertube.getTags()).observe(PeertubeActivity.this, this::manageNextVideos); } @@ -755,6 +754,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd }); if (peertube.isCommentsEnabled()) { + if (Helper.isLoggedIn(PeertubeActivity.this)) { + binding.postCommentButton.setVisibility(View.VISIBLE); + } else { + binding.postCommentButton.setVisibility(View.GONE); + } CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class); commentViewModel.getThread(sepiaSearch ? peertubeInstance : null, videoUuid, max_id).observe(PeertubeActivity.this, this::manageVIewComment); if (Helper.isLoggedIn(PeertubeActivity.this) && !sepiaSearch) { @@ -762,6 +766,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } binding.peertubeComments.setVisibility(View.VISIBLE); } else { + binding.postCommentButton.setVisibility(View.GONE); binding.peertubeComments.setVisibility(View.GONE); binding.writeCommentContainer.setVisibility(View.GONE); binding.noActionText.setText(getString(R.string.comment_no_allowed_peertube)); @@ -778,8 +783,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd binding.peertubeDislikeCount.setText(Helper.withSuffix(peertube.getDislikes())); binding.peertubeLikeCount.setText(Helper.withSuffix(peertube.getLikes())); binding.peertubeViewCount.setText(Helper.withSuffix(peertube.getViews())); - loadGiF(PeertubeActivity.this,peertube.getChannel().getAvatar()!=null?peertube.getChannel().getAvatar().getPath():null, binding.ppChannel); - binding.ppChannel.setOnClickListener(v->{ + loadGiF(PeertubeActivity.this, peertube.getChannel().getAvatar() != null ? peertube.getChannel().getAvatar().getPath() : null, binding.ppChannel); + binding.ppChannel.setOnClickListener(v -> { Intent intent = new Intent(PeertubeActivity.this, ShowChannelActivity.class); Bundle b = new Bundle(); b.putParcelable("channel", peertube.getChannel()); @@ -858,8 +863,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd binding.loader.setVisibility(View.GONE); startStream( apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this), - apiResponse.getPeertubes().get(0).getStreamingPlaylists().size()>0?apiResponse.getPeertubes().get(0).getStreamingPlaylists().get(0).getPlaylistUrl():null, - autoPlay,position, null, null); + apiResponse.getPeertubes().get(0).getStreamingPlaylists().size() > 0 ? apiResponse.getPeertubes().get(0).getStreamingPlaylists().get(0).getPlaylistUrl() : null, + autoPlay, position, null, null); player.prepare(); player.setPlayWhenReady(autoPlay); } @@ -1006,11 +1011,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd private void startStream(String videoURL, String streamingPlaylistsURLS, boolean autoPlay, long position, Uri subtitles, String lang) { if (videoURL != null) { - if( videoURL.endsWith(".torrent")) { + if (videoURL.endsWith(".torrent")) { torrentStream.startStream(videoURL); return; - }else { + } else { SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); int video_cache = sharedpreferences.getInt(Helper.SET_VIDEO_CACHE, Helper.DEFAULT_VIDEO_CACHE_MB); ProgressiveMediaSource videoSource; @@ -1020,7 +1025,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd Util.getUserAgent(PeertubeActivity.this, null), null); if (subtitles != null) { - MediaItem.Subtitle mediaSubtitle = new MediaItem.Subtitle(subtitles, MimeTypes.TEXT_VTT, lang); + MediaItem.Subtitle mediaSubtitle = new MediaItem.Subtitle(subtitles, MimeTypes.TEXT_VTT, lang); subtitleSource = new SingleSampleMediaSource.Factory(dataSourceFactory).createMediaSource(mediaSubtitle, C.TIME_UNSET); } MediaItem mediaItem = new MediaItem.Builder().setUri(videoURL).build(); @@ -1031,7 +1036,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(mediaItem); if (subtitles != null) { - MediaItem.Subtitle mediaSubtitle = new MediaItem.Subtitle(subtitles, MimeTypes.TEXT_VTT, lang, Format.NO_VALUE); + MediaItem.Subtitle mediaSubtitle = new MediaItem.Subtitle(subtitles, MimeTypes.TEXT_VTT, lang, Format.NO_VALUE); subtitleSource = new SingleSampleMediaSource.Factory(cacheDataSourceFactory).createMediaSource(mediaSubtitle, C.TIME_UNSET); } } @@ -1039,7 +1044,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd MergingMediaSource mergedSource = new MergingMediaSource(videoSource, subtitleSource); player.setMediaSource(mergedSource); - }else { + } else { player.setMediaSource(videoSource); } } @@ -1050,7 +1055,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd player.setMediaSource(hlsMediaSource); } player.prepare(); - if( position > 0) { + if (position > 0) { player.seekTo(0, position); } player.setPlayWhenReady(autoPlay); @@ -1059,21 +1064,37 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd @Override public void onConfigurationChanged(@NotNull Configuration newConfig) { super.onConfigurationChanged(newConfig); + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { if (mode != Helper.VIDEO_MODE_WEBVIEW) { openFullscreenDialog(); } setFullscreen(FullScreenMediaController.fullscreen.ON); + if (initialOrientation == Configuration.ORIENTATION_LANDSCAPE) { + LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_PARENT, + 0, + 3.0f + ); + binding.videoContainer.setLayoutParams(param); + } } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { if (mode != Helper.VIDEO_MODE_WEBVIEW) { closeFullscreenDialog(); } setFullscreen(FullScreenMediaController.fullscreen.OFF); + if (initialOrientation == Configuration.ORIENTATION_LANDSCAPE) { + LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_PARENT, + 0, + 1.0f + ); + binding.videoContainer.setLayoutParams(param); + } } change(); } - @Override public void onDestroy() { super.onDestroy(); @@ -1081,7 +1102,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd if (player != null) { player.release(); } - if( torrentStream != null && torrentStream.isStreaming()) { + if (torrentStream != null && torrentStream.isStreaming()) { torrentStream.stopStream(); } unregisterReceiver(); @@ -1108,12 +1129,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd @Override protected void onPause() { super.onPause(); - if( player != null) { - updateHistory(player.getCurrentPosition()/1000); + if (player != null) { + updateHistory(player.getCurrentPosition() / 1000); } if (player != null && (!isPlayInMinimized || !playInMinimized)) { player.setPlayWhenReady(false); - }else if (playInMinimized) { + } else if (playInMinimized) { enterVideoMode(); } } @@ -1129,7 +1150,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd String strAction = intent.getAction(); if (strAction.equals(Intent.ACTION_SCREEN_OFF)) { if (player != null && isPlayInMinimized) { - if( !sharedpreferences.getBoolean(getString(R.string.set_play_screen_lock_choice), false)) { + if (!sharedpreferences.getBoolean(getString(R.string.set_play_screen_lock_choice), false)) { player.setPlayWhenReady(false); } } @@ -1154,7 +1175,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - @RequiresApi(api = Build.VERSION_CODES.N) @Override public void onUserLeaveHint() { @@ -1176,14 +1196,13 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - @Override public void onBackPressed() { - if(binding.postComment.getVisibility() == View.VISIBLE){ + if (binding.postComment.getVisibility() == View.VISIBLE) { closePostComment(); } else if (binding.replyThread.getVisibility() == View.VISIBLE) { closeCommentThread(); - } else { + } else { if (playInMinimized && player != null) { enterVideoMode(); } else { @@ -1192,7 +1211,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) { if (isInPictureInPictureMode) { @@ -1206,7 +1224,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - public void displayResolution() { AlertDialog.Builder builderSingle = new AlertDialog.Builder(PeertubeActivity.this); builderSingle.setTitle(R.string.pickup_resolution); @@ -1236,7 +1253,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd binding.loader.setVisibility(View.GONE); startStream( peertube.getFileUrl(res, PeertubeActivity.this), - peertube.getStreamingPlaylists().size()>0?peertube.getStreamingPlaylists().get(0).getPlaylistUrl():null, + peertube.getStreamingPlaylists().size() > 0 ? peertube.getStreamingPlaylists().get(0).getPlaylistUrl() : null, true, position, null, null); } @@ -1244,19 +1261,22 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd builderSingle.show(); } - private void initFullscreenDialog() { fullScreenDialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen) { public void onBackPressed() { - if( player != null && player.isPlaying() && fullScreenMode) { + if (player != null && player.isPlaying() && fullScreenMode) { player.setPlayWhenReady(false); } - if( fullScreenMode) { + if (fullScreenMode) { closeFullscreenDialog(); - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - Handler handler = new Handler(); - handler.postDelayed(() -> setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR), 2000); + if (!Helper.isTablet(PeertubeActivity.this) && initialOrientation != Configuration.ORIENTATION_LANDSCAPE) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + Handler handler = new Handler(); + handler.postDelayed(() -> setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR), 2000); + } else { + binding.peertubeInformationContainer.setVisibility(View.VISIBLE); + } } super.onBackPressed(); } @@ -1273,17 +1293,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd fullScreenDialog.show(); } - - - - public void openCommentThread(Comment comment) { - CommentVM commentViewModel = new ViewModelProvider(PeertubeActivity.this).get(CommentVM.class); binding.peertubeReply.setVisibility(View.GONE); - commentViewModel.getRepliesComment(videoUuid, comment.getId()).observe(PeertubeActivity.this, apiResponse->manageVIewCommentReply(comment, apiResponse)); - + commentViewModel.getRepliesComment(videoUuid, comment.getId()).observe(PeertubeActivity.this, apiResponse -> manageVIewCommentReply(comment, apiResponse)); binding.replyThread.setVisibility(View.VISIBLE); TranslateAnimation animate = new TranslateAnimation( @@ -1295,12 +1309,10 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd @Override public void onAnimationStart(Animation animation) { } - @Override public void onAnimationEnd(Animation animation) { binding.peertubeInformationContainer.setVisibility(View.GONE); } - @Override public void onAnimationRepeat(Animation animation) { } @@ -1311,21 +1323,22 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd private void sendComment(Comment comment, int position) { if (isLoggedIn(PeertubeActivity.this) && !sepiaSearch) { - if( comment == null) { - String commentStr = binding.addCommentWrite.getText().toString(); + if (comment == null) { + String commentStr = binding.addCommentWrite.getText() != null ? binding.addCommentWrite.getText().toString() : ""; if (commentStr.trim().length() > 0) { PostActionsVM viewModelComment = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class); viewModelComment.comment(ADD_COMMENT, peertube.getId(), null, commentStr).observe(PeertubeActivity.this, apiResponse1 -> manageVIewPostActions(ADD_COMMENT, 0, apiResponse1)); binding.addCommentWrite.setText(""); } - }else{ - String commentView = binding.addCommentWrite.getText().toString(); + } else { + String commentView = binding.addCommentWrite.getText() != null ? binding.addCommentWrite.getText().toString() : ""; if (commentView.trim().length() > 0) { PostActionsVM viewModelComment = new ViewModelProvider(PeertubeActivity.this).get(PostActionsVM.class); viewModelComment.comment(REPLY, peertube.getId(), comment.getId(), commentView).observe(PeertubeActivity.this, apiResponse1 -> manageVIewPostActions(REPLY, position, apiResponse1)); binding.addCommentWrite.setText(""); } } + closePostComment(); } else { if (sepiaSearch) { Toasty.info(PeertubeActivity.this, getString(R.string.federation_issue), Toasty.LENGTH_SHORT).show(); @@ -1337,6 +1350,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd private void closeCommentThread() { binding.peertubeInformationContainer.setVisibility(View.VISIBLE); + hideKeyboard(this); TranslateAnimation animate = new TranslateAnimation( 0, binding.replyThread.getWidth(), @@ -1360,9 +1374,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd binding.replyThread.startAnimation(animate); } - public void openPostComment(Comment comment, int position) { - if( comment != null) { + if (comment != null) { binding.replyContent.setVisibility(View.VISIBLE); Account account = comment.getAccount(); Helper.loadGiF(PeertubeActivity.this, account.getAvatar() != null ? account.getAvatar().getPath() : null, binding.commentAccountProfile); @@ -1375,7 +1388,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd commentSpan = Html.fromHtml(comment.getText()); binding.commentContent.setText(commentSpan); binding.commentDate.setText(Helper.dateDiff(PeertubeActivity.this, comment.getCreatedAt())); - }else{ + } else { binding.replyContent.setVisibility(View.GONE); } binding.postComment.setVisibility(View.VISIBLE); @@ -1386,7 +1399,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd 0, 0, height, - binding.mediaVideo.getHeight()); + 0); animateComment.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { @@ -1395,6 +1408,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd @Override public void onAnimationEnd(Animation animation) { binding.peertubeInformationContainer.setVisibility(View.GONE); + InputMethodManager inputMethodManager = + (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.toggleSoftInputFromWindow( + binding.addCommentWrite.getApplicationWindowToken(), + InputMethodManager.SHOW_FORCED, 0); + binding.addCommentWrite.requestFocus(); } @Override @@ -1403,13 +1422,13 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd }); animateComment.setDuration(500); binding.postComment.startAnimation(animateComment); - if( comment != null) { + if (comment != null) { binding.addCommentWrite.setText(String.format("@%s ", comment.getAccount().getAcct())); - binding.addCommentWrite.setSelection(binding.addCommentWrite.getText().length()); + binding.addCommentWrite.setSelection(binding.addCommentWrite.getText() != null ? binding.addCommentWrite.getText().length() : 0); } binding.send.setOnClickListener(null); - binding.send.setOnClickListener(v-> sendComment(comment, position)); + binding.send.setOnClickListener(v -> sendComment(comment, position)); } private void closePostComment() { @@ -1417,11 +1436,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); int height = displayMetrics.heightPixels; binding.peertubeInformationContainer.setVisibility(View.VISIBLE); - Log.v(Helper.TAG,"end: " + binding.mediaVideo.getHeight() + " - " + height); + hideKeyboard(this); TranslateAnimation animateComment = new TranslateAnimation( 0, 0, - binding.mediaVideo.getHeight(), + 0, height); animateComment.setAnimationListener(new Animation.AnimationListener() { @Override @@ -1480,7 +1499,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd openFullscreenDialog(); if (videoOrientationType == videoOrientation.LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - }else { + } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } } else { @@ -1492,12 +1511,12 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } }); ImageButton playButton = controlView.findViewById(R.id.exo_play); - playButton.setOnClickListener(v->{ - if(autoFullscreen && !fullScreenMode) { + playButton.setOnClickListener(v -> { + if (autoFullscreen && !fullScreenMode) { openFullscreenDialog(); if (videoOrientationType == videoOrientation.LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - }else { + } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } } @@ -1612,7 +1631,6 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } - public void addElement(String playlistId, String videoId, APIResponse apiResponse) { if (apiResponse != null && apiResponse.getActionReturn() != null) { @@ -1628,12 +1646,10 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - - private void updateHistory(long position) { SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); boolean storeInHistory = sharedpreferences.getBoolean(getString(R.string.set_store_in_history), true); - if( Helper.isLoggedIn(PeertubeActivity.this) && peertube != null && storeInHistory) { + if (Helper.isLoggedIn(PeertubeActivity.this) && peertube != null && storeInHistory) { new Thread(() -> { try { RetrofitPeertubeAPI api = new RetrofitPeertubeAPI(PeertubeActivity.this); @@ -1650,13 +1666,11 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd binding.noActionText.setVisibility(View.VISIBLE); } - - private void playNextVideo() { - if( nextVideo != null) { + if (nextVideo != null) { Intent intent = new Intent(PeertubeActivity.this, PeertubeActivity.class); Bundle b = new Bundle(); - b.putParcelable("video",nextVideo); + b.putParcelable("video", nextVideo); b.putString("video_id", nextVideo.getId()); b.putString("video_uuid", nextVideo.getUuid()); playedVideos.add(nextVideo.getId()); @@ -1666,22 +1680,24 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } } - - @Override public void onMediaItemTransition(MediaItem mediaItem, int reason) { SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); boolean autoplayNextVideo = sharedpreferences.getBoolean(getString(R.string.set_autoplay_next_video_choice), true); - if (reason == MEDIA_ITEM_TRANSITION_REASON_AUTO && autoplayNextVideo){ + if (reason == MEDIA_ITEM_TRANSITION_REASON_AUTO && autoplayNextVideo) { player.removeMediaItems(0, player.getMediaItemCount()); playNextVideo(); } } - - @Override public void onPlayerError(ExoPlaybackException error) { } + + + enum videoOrientation { + LANDSCAPE, + PORTRAIT + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java index a9e5af6..9c29462 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeRegisterActivity.java @@ -61,7 +61,6 @@ public class PeertubeRegisterActivity extends AppCompatActivity { getSupportActionBar().setDisplayHomeAsUpEnabled(true); - if (BuildConfig.full_instances) { binding.loginInstanceContainer.setVisibility(View.VISIBLE); binding.titleLoginInstance.setVisibility(View.VISIBLE); @@ -114,21 +113,21 @@ public class PeertubeRegisterActivity extends AppCompatActivity { setTextAgreement(); binding.signup.setOnClickListener(view -> { binding.errorMessage.setVisibility(View.GONE); - if ( binding.username.getText() == null || binding.email.getText() == null || binding.password.getText() == null || binding.passwordConfirm.getText() == null || binding.username.getText().toString().trim().length() == 0 || binding.email.getText().toString().trim().length() == 0 || - binding.password.getText().toString().trim().length() == 0 || binding.passwordConfirm.getText().toString().trim().length() == 0 || ! binding.agreement.isChecked()) { + if (binding.username.getText() == null || binding.email.getText() == null || binding.password.getText() == null || binding.passwordConfirm.getText() == null || binding.username.getText().toString().trim().length() == 0 || binding.email.getText().toString().trim().length() == 0 || + binding.password.getText().toString().trim().length() == 0 || binding.passwordConfirm.getText().toString().trim().length() == 0 || !binding.agreement.isChecked()) { Toasty.error(PeertubeRegisterActivity.this, getString(R.string.all_field_filled)).show(); return; } - if (! binding.password.getText().toString().trim().equals( binding.passwordConfirm.getText().toString().trim())) { + if (!binding.password.getText().toString().trim().equals(binding.passwordConfirm.getText().toString().trim())) { Toasty.error(PeertubeRegisterActivity.this, getString(R.string.password_error)).show(); return; } - if (!android.util.Patterns.EMAIL_ADDRESS.matcher( binding.email.getText().toString().trim()).matches()) { + if (!android.util.Patterns.EMAIL_ADDRESS.matcher(binding.email.getText().toString().trim()).matches()) { Toasty.error(PeertubeRegisterActivity.this, getString(R.string.email_error)).show(); return; } - String[] emailArray = binding.email.getText().toString().split("@"); + String[] emailArray = binding.email.getText().toString().split("@"); if (!BuildConfig.full_instances) { if (emailArray.length > 1 && !Arrays.asList(Helper.valideEmails).contains(emailArray[1])) { Toasty.error(PeertubeRegisterActivity.this, getString(R.string.email_error_domain, emailArray[1])).show(); @@ -136,19 +135,19 @@ public class PeertubeRegisterActivity extends AppCompatActivity { } } - if ( binding.password.getText().toString().trim().length() < 8) { + if (binding.password.getText().toString().trim().length() < 8) { Toasty.error(PeertubeRegisterActivity.this, getString(R.string.password_too_short)).show(); return; } - if ( binding.username.getText().toString().matches("[a-z0-9_]")) { + if (binding.username.getText().toString().matches("[a-z0-9_]")) { Toasty.error(PeertubeRegisterActivity.this, getString(R.string.username_error)).show(); return; } binding.signup.setEnabled(false); if (BuildConfig.full_instances) { - if ( binding.loginInstance.getText() != null) { - instance = binding.loginInstance.getText().toString(); + if (binding.loginInstance.getText() != null) { + instance = binding.loginInstance.getText().toString(); } else { instance = ""; } @@ -166,10 +165,10 @@ public class PeertubeRegisterActivity extends AppCompatActivity { } AccountCreation accountCreation = new AccountCreation(); - accountCreation.setEmail( binding.email.getText().toString().trim()); - accountCreation.setPassword( binding.password.getText().toString().trim()); - accountCreation.setPasswordConfirm( binding.passwordConfirm.getText().toString().trim()); - accountCreation.setUsername( binding.username.getText().toString().trim()); + accountCreation.setEmail(binding.email.getText().toString().trim()); + accountCreation.setPassword(binding.password.getText().toString().trim()); + accountCreation.setPasswordConfirm(binding.passwordConfirm.getText().toString().trim()); + accountCreation.setUsername(binding.username.getText().toString().trim()); accountCreation.setInstance(instance); new Thread(() -> { @@ -259,7 +258,7 @@ public class PeertubeRegisterActivity extends AppCompatActivity { agreement_text.setMovementMethod(null); agreement_text.setText(null); if (BuildConfig.full_instances) { - if ( binding.loginInstance.getText() != null) { + if (binding.loginInstance.getText() != null) { content_agreement = getString(R.string.agreement_check_peertube, "" + tos + "" ); diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java index 5b98d33..3bb3f3b 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java @@ -66,8 +66,8 @@ import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.DataType.MY_CHA public class PeertubeUploadActivity extends AppCompatActivity { - private final int PICK_IVDEO = 52378; public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724; + private final int PICK_IVDEO = 52378; private Button set_upload_file, set_upload_submit; private Spinner set_upload_privacy, set_upload_channel; private TextView set_upload_file_name; diff --git a/app/src/main/java/app/fedilab/fedilabtube/PlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PlaylistsActivity.java index 113bb94..299c751 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PlaylistsActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PlaylistsActivity.java @@ -14,6 +14,7 @@ package app.fedilab.fedilabtube; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.content.Intent; import android.os.Bundle; import android.view.MenuItem; import android.widget.Toast; @@ -24,12 +25,14 @@ import androidx.fragment.app.FragmentTransaction; import app.fedilab.fedilabtube.client.data.PlaylistData; import app.fedilab.fedilabtube.fragment.DisplayVideosFragment; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.helper.PlaylistExportHelper; import app.fedilab.fedilabtube.viewmodel.TimelineVM; import es.dmoral.toasty.Toasty; public class PlaylistsActivity extends AppCompatActivity { + private final int PICK_IMPORT = 5556; @Override protected void onCreate(Bundle savedInstanceState) { @@ -58,7 +61,7 @@ public class PlaylistsActivity extends AppCompatActivity { DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment(); Bundle bundle = new Bundle(); bundle.putSerializable(Helper.TIMELINE_TYPE, TimelineVM.TimelineType.VIDEOS_IN_PLAYLIST); - bundle.putSerializable("playlistId", playlist.getId()); + bundle.putSerializable("playlistId", playlist.getUuid()); displayVideosFragment.setArguments(bundle); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(R.id.nav_host_fragment, displayVideosFragment).commit(); @@ -66,6 +69,22 @@ public class PlaylistsActivity extends AppCompatActivity { } + @Override + protected void onActivityResult(int requestCode, int resultCode, + Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_IMPORT && resultCode == RESULT_OK) { + if (data == null || data.getData() == null) { + Toasty.error(PlaylistsActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + return; + } + PlaylistExportHelper.manageIntentUrl(PlaylistsActivity.this, data); + + } else if (requestCode == PICK_IMPORT) { + Toasty.error(PlaylistsActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java index df19899..e9f41ca 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java @@ -105,6 +105,7 @@ public class ShowAccountActivity extends AppCompatActivity { if (!Helper.isLoggedIn(ShowAccountActivity.this)) { menu.findItem(R.id.action_mute).setVisible(false); } + menu.findItem(R.id.action_display_account).setVisible(false); return true; } @@ -134,7 +135,7 @@ public class ShowAccountActivity extends AppCompatActivity { }); AlertDialog alertDialog = dialogBuilder.create(); alertDialog.show(); - }else if( item.getItemId() == R.id.action_share && account != null) { + } else if (item.getItemId() == R.id.action_share && account != null) { Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.shared_via)); String extra_text = account.getUrl(); diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java index 74c765e..faae6f7 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/ShowChannelActivity.java @@ -17,6 +17,7 @@ package app.fedilab.fedilabtube; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.ColorStateList; +import android.database.sqlite.SQLiteDatabase; import android.os.Build; import android.os.Bundle; import android.text.Html; @@ -54,10 +55,14 @@ import java.util.Map; import app.fedilab.fedilabtube.client.APIResponse; import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; +import app.fedilab.fedilabtube.client.data.AccountData; import app.fedilab.fedilabtube.client.data.ChannelData.Channel; +import app.fedilab.fedilabtube.drawer.OwnAccountsAdapter; import app.fedilab.fedilabtube.fragment.DisplayAccountsFragment; import app.fedilab.fedilabtube.fragment.DisplayVideosFragment; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.sqlite.AccountDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; import app.fedilab.fedilabtube.viewmodel.ChannelsVM; import app.fedilab.fedilabtube.viewmodel.PostActionsVM; import app.fedilab.fedilabtube.viewmodel.RelationshipVM; @@ -65,6 +70,7 @@ import app.fedilab.fedilabtube.viewmodel.TimelineVM; import es.dmoral.toasty.Toasty; import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY; +import static app.fedilab.fedilabtube.MainActivity.TypeOfConnection.SURFING; import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.FOLLOW; import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.MUTE; import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.REPORT_ACCOUNT; @@ -122,6 +128,57 @@ public class ShowChannelActivity extends AppCompatActivity { ChannelsVM viewModel = new ViewModelProvider(ShowChannelActivity.this).get(ChannelsVM.class); viewModel.get(sepiaSearch ? peertubeInstance : null, CHANNEL, channelAcct == null ? channel.getAcct() : channelAcct).observe(ShowChannelActivity.this, this::manageViewAccounts); manageChannel(); + + if (MainActivity.typeOfConnection == MainActivity.TypeOfConnection.SURFING) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + int[][] states = new int[][]{ + new int[]{android.R.attr.state_enabled}, // enabled + new int[]{-android.R.attr.state_enabled}, // disabled + new int[]{-android.R.attr.state_checked}, // unchecked + new int[]{android.R.attr.state_pressed} // pressed + }; + + int[] colors = new int[]{ + ContextCompat.getColor(ShowChannelActivity.this, Helper.getColorAccent()), + ContextCompat.getColor(ShowChannelActivity.this, Helper.getColorAccent()), + ContextCompat.getColor(ShowChannelActivity.this, Helper.getColorAccent()), + ContextCompat.getColor(ShowChannelActivity.this, Helper.getColorAccent()) + }; + account_follow.setBackgroundTintList(new ColorStateList(states, colors)); + } + account_follow.setText(getString(R.string.action_follow)); + account_follow.setEnabled(true); + new Thread(() -> { + try { + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + List accounts = new AccountDAO(ShowChannelActivity.this, db).getAllAccount(); + runOnUiThread(() -> { + account_follow.setVisibility(View.VISIBLE); + account_follow.setOnClickListener(v -> { + AlertDialog.Builder builderSingle = new AlertDialog.Builder(ShowChannelActivity.this); + builderSingle.setTitle(getString(R.string.list_of_accounts)); + if (accounts != null) { + final OwnAccountsAdapter accountsListAdapter = new OwnAccountsAdapter(ShowChannelActivity.this, accounts); + builderSingle.setAdapter(accountsListAdapter, (dialog, which) -> { + new Thread(() -> { + try { + RetrofitPeertubeAPI peertubeAPI = new RetrofitPeertubeAPI(ShowChannelActivity.this, accounts.get(which).getHost(), accounts.get(which).getToken()); + peertubeAPI.post(FOLLOW, channel.getAcct(), null); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + }); + } + builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + builderSingle.show(); + }); + }); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } } @Override @@ -159,7 +216,7 @@ public class ShowChannelActivity extends AppCompatActivity { }); androidx.appcompat.app.AlertDialog alertDialog = dialogBuilder.create(); alertDialog.show(); - } else if( item.getItemId() == R.id.action_share && channel != null) { + } else if (item.getItemId() == R.id.action_share && channel != null) { Intent sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.shared_via)); String extra_text = channel.getUrl(); @@ -170,6 +227,13 @@ public class ShowChannelActivity extends AppCompatActivity { } catch (Exception e) { Toasty.error(ShowChannelActivity.this, getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); } + } else if (item.getItemId() == R.id.action_display_account) { + Bundle b = new Bundle(); + Intent intent = new Intent(ShowChannelActivity.this, ShowAccountActivity.class); + b.putParcelable("account", channel.getOwnerAccount()); + b.putString("accountAcct", channel.getOwnerAccount().getAcct()); + intent.putExtras(b); + startActivity(intent); } return super.onOptionsItemSelected(item); } @@ -178,7 +242,7 @@ public class ShowChannelActivity extends AppCompatActivity { SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); String accountIdRelation = channel.getAcct(); - if (isLoggedIn(ShowChannelActivity.this) && !sepiaSearch) { + if (isLoggedIn(ShowChannelActivity.this)) { RelationshipVM viewModel = new ViewModelProvider(ShowChannelActivity.this).get(RelationshipVM.class); List uids = new ArrayList<>(); uids.add(accountIdRelation); @@ -305,7 +369,7 @@ public class ShowChannelActivity extends AppCompatActivity { //Manages the visibility of the button private void manageButtonVisibility() { - if (relationship == null) + if (relationship == null || MainActivity.typeOfConnection == SURFING) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { diff --git a/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java b/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java index 7a9e4d3..211b336 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/VideosTimelineActivity.java @@ -14,26 +14,45 @@ package app.fedilab.fedilabtube; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.app.AlertDialog; import android.os.Bundle; +import android.view.Menu; import android.view.MenuItem; +import android.view.View; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.ViewModelProvider; +import org.jetbrains.annotations.NotNull; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; + +import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.databinding.ActivitySearchResultBinding; import app.fedilab.fedilabtube.fragment.DisplayVideosFragment; import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.viewmodel.TimelineVM; +import static app.fedilab.fedilabtube.viewmodel.TimelineVM.TimelineType.HISTORY; + public class VideosTimelineActivity extends AppCompatActivity { private TimelineVM.TimelineType type; + private DisplayVideosFragment displayVideosFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_search_result); + ActivitySearchResultBinding binding = ActivitySearchResultBinding.inflate(getLayoutInflater()); + View mainView = binding.getRoot(); + setContentView(mainView); if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -41,23 +60,75 @@ public class VideosTimelineActivity extends AppCompatActivity { Bundle b = getIntent().getExtras(); if (b != null) type = (TimelineVM.TimelineType) b.get("type"); + displayVideosFragment = null; + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + if (savedInstanceState == null) { + displayVideosFragment = new DisplayVideosFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable(Helper.TIMELINE_TYPE, type); + displayVideosFragment.setArguments(bundle); + ft.add(R.id.container, displayVideosFragment).addToBackStack(null).commit(); + } if (type == TimelineVM.TimelineType.MY_VIDEOS) { setTitle(R.string.my_videos); - } else if (type == TimelineVM.TimelineType.HISTORY) { + } else if (type == HISTORY) { setTitle(R.string.my_history); + //TODO: uncomment when available + // binding.historyFilter.setVisibility(View.VISIBLE); + binding.historyFilterAll.setOnClickListener(v -> historyFilter(null)); + binding.historyFilterToday.setOnClickListener(v -> { + Calendar cal = GregorianCalendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.getTime(); + historyFilter(cal.getTime()); + }); + binding.historyFilterLast7Days.setOnClickListener(v -> { + Calendar cal = GregorianCalendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DAY_OF_YEAR, -7); + cal.getTime(); + historyFilter(cal.getTime()); + }); + } else if (type == TimelineVM.TimelineType.MOST_LIKED) { setTitle(R.string.title_most_liked); } - if (savedInstanceState == null) { - DisplayVideosFragment displayVideosFragment = new DisplayVideosFragment(); - Bundle bundle = new Bundle(); - bundle.putSerializable(Helper.TIMELINE_TYPE, type); - displayVideosFragment.setArguments(bundle); - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - ft.add(R.id.container, displayVideosFragment).commit(); + + } + + private void historyFilter(Date date) { + String startDate = null; + if (date != null) { + SimpleDateFormat fmtOut = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); + startDate = fmtOut.format(date); } + if (displayVideosFragment != null) { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + displayVideosFragment = new DisplayVideosFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable(Helper.TIMELINE_TYPE, HISTORY); + bundle.putSerializable("startDate", startDate); + displayVideosFragment.setArguments(bundle); + ft.replace(R.id.container, displayVideosFragment); + ft.addToBackStack(null); + ft.commit(); + } + } + + @Override + public boolean onCreateOptionsMenu(@NotNull Menu menu) { + if (type == HISTORY) { + getMenuInflater().inflate(R.menu.main_history, menu); + return true; + } else { + return super.onCreateOptionsMenu(menu); + } + } @@ -66,8 +137,34 @@ public class VideosTimelineActivity extends AppCompatActivity { if (item.getItemId() == android.R.id.home) { finish(); return true; + } else if (item.getItemId() == R.id.action_delete) { + AlertDialog.Builder builder = new AlertDialog.Builder(VideosTimelineActivity.this); + builder.setTitle(R.string.delete_history); + builder.setMessage(R.string.delete_history_confirm); + builder.setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.delete, (dialog, which) -> { + TimelineVM viewModelFeeds = new ViewModelProvider(VideosTimelineActivity.this).get(TimelineVM.class); + viewModelFeeds.deleterHistory().observe(VideosTimelineActivity.this, this::manageVIewVideos); + + dialog.dismiss(); + }) + .setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss()) + .show(); + return true; } return super.onOptionsItemSelected(item); } + private void manageVIewVideos(APIResponse apiResponse) { + if (type == HISTORY) { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + displayVideosFragment = new DisplayVideosFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable(Helper.TIMELINE_TYPE, HISTORY); + displayVideosFragment.setArguments(bundle); + ft.replace(R.id.container, displayVideosFragment); + ft.addToBackStack(null); + ft.commit(); + } + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java index 0a89718..7592ad8 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java @@ -66,6 +66,10 @@ public interface PeertubeService { @GET(".well-known/nodeinfo") Call getWellKnownNodeinfo(); + //Instance info + @GET("config/about") + Call configAbout(); + @GET("{nodeInfoPath}") Call getNodeinfo(@Path(value = "nodeInfoPath", encoded = true) String nodeInfoPath); @@ -136,7 +140,7 @@ public interface PeertubeService { @Field("description") String description, @Field("displayName") String displayName, @Field("nsfwPolicy") String nsfwPolicy - ); + ); @Multipart @POST("users/me/avatar/pick") @@ -171,7 +175,17 @@ public interface PeertubeService { //History @GET("users/me/history/videos") - Call getHistory(@Header("Authorization") String credentials, @Query("start") String maxId, @Query("count") String count); + Call getHistory( + @Header("Authorization") String credentials, + @Query("start") String maxId, + @Query("count") String count, + @Query("startDate") String startDate, + @Query("endDate") String endDate + ); + + @POST("users/me/history/videos/remove") + Call deleteHistory( + @Header("Authorization") String credentials); //Search @GET("search/videos") diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java index 588e06e..1e4f41b 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java @@ -166,9 +166,9 @@ public class RetrofitPeertubeAPI { } private String getToken() { - if( token != null) { + if (token != null) { return "Bearer " + token; - }else{ + } else { return null; } } @@ -347,6 +347,51 @@ public class RetrofitPeertubeAPI { return apiResponse; } + + public APIResponse deleteHistory() { + APIResponse apiResponse = new APIResponse(); + PeertubeService peertubeService = init(); + Call stringCall = peertubeService.deleteHistory(getToken()); + if (stringCall != null) { + try { + Response response = stringCall.execute(); + if (response.isSuccessful() && response.body() != null) { + apiResponse.setActionReturn(response.body()); + } else { + setError(apiResponse, response.code(), response.errorBody()); + } + } catch (IOException e) { + Error error = new Error(); + error.setError(_context.getString(R.string.toast_error)); + apiResponse.setError(error); + e.printStackTrace(); + } + } + return apiResponse; + } + + public APIResponse getHistory(String max_id, String startDate, String endDate) { + APIResponse apiResponse = new APIResponse(); + PeertubeService peertubeService = init(); + Call videoCall = peertubeService.getHistory(getToken(), max_id, count, startDate, endDate); + if (videoCall != null) { + try { + Response response = videoCall.execute(); + if (response.isSuccessful() && response.body() != null) { + apiResponse.setPeertubes(response.body().data); + } else { + setError(apiResponse, response.code(), response.errorBody()); + } + } catch (IOException e) { + Error error = new Error(); + error.setError(_context.getString(R.string.toast_error)); + apiResponse.setError(error); + e.printStackTrace(); + } + } + return apiResponse; + } + public APIResponse getTL(TimelineVM.TimelineType timelineType, String max_id, String forAccount) { APIResponse apiResponse = new APIResponse(); PeertubeService peertubeService = init(); @@ -376,7 +421,7 @@ public class RetrofitPeertubeAPI { videoCall = peertubeService.getTrendingVideos(getToken(), max_id, count, filter); break; case HISTORY: - videoCall = peertubeService.getHistory(getToken(), max_id, count); + videoCall = peertubeService.getHistory(getToken(), max_id, count, null, null); break; case RECENT: videoCall = peertubeService.getRecentlyAddedVideos(getToken(), max_id, count, filter); @@ -454,7 +499,7 @@ public class RetrofitPeertubeAPI { /** * Update history * - * @param videoId String + * @param videoId String * @param currentTime int */ public void updateHistory(String videoId, long currentTime) { @@ -525,10 +570,10 @@ public class RetrofitPeertubeAPI { } byte[] imageBytes = byteBuffer.toByteArray(); String mime = MimeTypeMap.getFileExtensionFromUrl(userSettings.getAvatarfile().toString()); - if( mime == null || mime.trim().length() == 0) { + if (mime == null || mime.trim().length() == 0) { mime = "png"; } - RequestBody requestFile = RequestBody.create(MediaType.parse("image/"+mime), imageBytes); + RequestBody requestFile = RequestBody.create(MediaType.parse("image/" + mime), imageBytes); MultipartBody.Part bodyThumbnail = MultipartBody.Part.createFormData("avatarfile", userSettings.getFileName(), requestFile); Call updateProfilePicture = peertubeService.updateProfilePicture(getToken(), bodyThumbnail); Response responseAvatar = updateProfilePicture.execute(); @@ -597,6 +642,26 @@ public class RetrofitPeertubeAPI { return apiResponse; } + /** + * About the instance + * + * @return AboutInstance + */ + public InstanceData.AboutInstance getAboutInstance() { + + PeertubeService peertubeService = init(); + Call about = peertubeService.configAbout(); + try { + Response response = about.execute(); + if (response.isSuccessful() && response.body() != null) { + return response.body().getInstance(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + /** * Returns informations about Peertube such privacies, licenses, etc. * @@ -781,7 +846,7 @@ public class RetrofitPeertubeAPI { */ public APIResponse searchNextVideos(List tags) { PeertubeService peertubeService = init(); - Call searchVideosCall = peertubeService.searchNextVideo(getToken(), tags, "0" , "20"); + Call searchVideosCall = peertubeService.searchNextVideo(getToken(), tags, "0", "20"); APIResponse apiResponse = new APIResponse(); try { Response response = searchVideosCall.execute(); @@ -1039,7 +1104,6 @@ public class RetrofitPeertubeAPI { } - /** * Get video description * @@ -1052,9 +1116,10 @@ public class RetrofitPeertubeAPI { try { Response response = videoDescription.execute(); if (response.isSuccessful() && response.body() != null) { - return response.body(); + return response.body(); } - } catch (IOException ignored) {} + } catch (IOException ignored) { + } return null; } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java b/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java index 69c4fb7..59eff4c 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/data/InstanceData.java @@ -1,9 +1,12 @@ package app.fedilab.fedilabtube.client.data; +import android.os.Parcel; +import android.os.Parcelable; import android.text.SpannableStringBuilder; import com.google.gson.annotations.SerializedName; +import java.io.Serializable; import java.util.Date; import java.util.List; @@ -239,5 +242,106 @@ public class InstanceData { } } + public static class InstanceInfo { + @SerializedName("instance") + private AboutInstance instance; + + public AboutInstance getInstance() { + return instance; + } + + public void setInstance(AboutInstance instance) { + this.instance = instance; + } + } + + public static class AboutInstance implements Parcelable, Serializable { + + public static final Creator CREATOR = new Creator() { + @Override + public AboutInstance createFromParcel(Parcel in) { + return new AboutInstance(in); + } + + @Override + public AboutInstance[] newArray(int size) { + return new AboutInstance[size]; + } + }; + @SerializedName("name") + private String name; + @SerializedName("shortDescription") + private String shortDescription; + @SerializedName("description") + private String description; + @SerializedName("terms") + private String terms; + private String host; + + public AboutInstance() { + } + + protected AboutInstance(Parcel in) { + name = in.readString(); + shortDescription = in.readString(); + description = in.readString(); + terms = in.readString(); + host = in.readString(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getShortDescription() { + return shortDescription; + } + + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getTerms() { + return terms; + } + + public void setTerms(String terms) { + this.terms = terms; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(name); + parcel.writeString(shortDescription); + parcel.writeString(description); + parcel.writeString(terms); + parcel.writeString(host); + } + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java b/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java index 782522f..2a8676e 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoData.java @@ -180,7 +180,7 @@ public class VideoData { this.trackerUrls = in.createStringArrayList(); long tmpUpdatedAt = in.readLong(); this.updatedAt = tmpUpdatedAt == -1 ? null : new Date(tmpUpdatedAt); - this.userHistory = in.readParcelable(UserHistory.class.getClassLoader()); + this.userHistory = in.readParcelable(UserHistory.class.getClassLoader()); this.uuid = in.readString(); this.views = in.readInt(); this.waitTranscoding = in.readByte() != 0; @@ -198,7 +198,7 @@ public class VideoData { return file.getMagnetUri(); } else if (mode == Helper.VIDEO_MODE_TORRENT) { return file.getTorrentUrl(); - }else { + } else { return file.getFileUrl(); } } @@ -698,7 +698,7 @@ public class VideoData { } - public static class UserHistory implements Parcelable{ + public static class UserHistory implements Parcelable { public static final Creator CREATOR = new Creator() { @Override @@ -743,7 +743,7 @@ public class VideoData { } - public static class Description{ + public static class Description { @SerializedName("description") private String description; @@ -755,4 +755,78 @@ public class VideoData { this.description = description; } } + + + public static class VideoExport implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public VideoExport createFromParcel(Parcel in) { + return new VideoExport(in); + } + + @Override + public VideoExport[] newArray(int size) { + return new VideoExport[size]; + } + }; + private int id; + private String uuid; + private Video videoData; + private int playlistDBid; + + public VideoExport() { + } + + protected VideoExport(Parcel in) { + id = in.readInt(); + uuid = in.readString(); + videoData = in.readParcelable(Video.class.getClassLoader()); + playlistDBid = in.readInt(); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Video getVideoData() { + return videoData; + } + + public void setVideoData(Video videoData) { + this.videoData = videoData; + } + + public int getPlaylistDBid() { + return playlistDBid; + } + + public void setPlaylistDBid(int playlistDBid) { + this.playlistDBid = playlistDBid; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(id); + parcel.writeString(uuid); + parcel.writeParcelable(videoData, i); + parcel.writeInt(playlistDBid); + } + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoPlaylistData.java b/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoPlaylistData.java index 4f21e13..9e2db1f 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoPlaylistData.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/data/VideoPlaylistData.java @@ -15,11 +15,15 @@ package app.fedilab.fedilabtube.client.data; * see . */ +import android.os.Parcel; +import android.os.Parcelable; + import com.google.gson.annotations.SerializedName; import java.util.List; + @SuppressWarnings({"unused", "RedundantSuppression"}) public class VideoPlaylistData { @@ -155,4 +159,90 @@ public class VideoPlaylistData { this.uuid = uuid; } } + + public static class VideoPlaylistExport implements Parcelable { + + public static final Creator CREATOR = new Creator() { + @Override + public VideoPlaylistExport createFromParcel(Parcel in) { + return new VideoPlaylistExport(in); + } + + @Override + public VideoPlaylistExport[] newArray(int size) { + return new VideoPlaylistExport[size]; + } + }; + private long playlistDBkey; + private String acct; + private String uuid; + private PlaylistData.Playlist playlist; + private List videos; + + + public VideoPlaylistExport() { + } + + protected VideoPlaylistExport(Parcel in) { + playlistDBkey = in.readLong(); + acct = in.readString(); + uuid = in.readString(); + playlist = in.readParcelable(PlaylistData.Playlist.class.getClassLoader()); + in.readList(this.videos, VideoPlaylistData.VideoPlaylist.class.getClassLoader()); + } + + public String getAcct() { + return acct; + } + + public void setAcct(String acct) { + this.acct = acct; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public PlaylistData.Playlist getPlaylist() { + return playlist; + } + + public void setPlaylist(PlaylistData.Playlist playlist) { + this.playlist = playlist; + } + + public long getPlaylistDBkey() { + return playlistDBkey; + } + + public void setPlaylistDBkey(long playlistDBkey) { + this.playlistDBkey = playlistDBkey; + } + + public List getVideos() { + return videos; + } + + public void setVideos(List videos) { + this.videos = videos; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeLong(playlistDBkey); + parcel.writeString(acct); + parcel.writeString(uuid); + parcel.writeParcelable(playlist, i); + parcel.writeList(videos); + } + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java index 1120da2..05582ad 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java @@ -9,6 +9,17 @@ import com.google.gson.annotations.SerializedName; @SuppressWarnings({"unused", "RedundantSuppression"}) public class File implements Parcelable { + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public File createFromParcel(Parcel source) { + return new File(source); + } + + @Override + public File[] newArray(int size) { + return new File[size]; + } + }; @SerializedName("fileDownloadUrl") private String fileDownloadUrl; @SerializedName("fileUrl") @@ -28,6 +39,21 @@ public class File implements Parcelable { @SerializedName("torrentUrl") private String torrentUrl; + public File() { + } + + protected File(Parcel in) { + this.fileDownloadUrl = in.readString(); + this.fileUrl = in.readString(); + this.fps = in.readInt(); + this.magnetUri = in.readString(); + this.metadataUrl = in.readString(); + this.resolutions = in.readParcelable(Item.class.getClassLoader()); + this.size = in.readLong(); + this.torrentDownloadUrl = in.readString(); + this.torrentUrl = in.readString(); + } + public String getFileDownloadUrl() { return fileDownloadUrl; } @@ -100,7 +126,6 @@ public class File implements Parcelable { this.torrentUrl = torrentUrl; } - @Override public int describeContents() { return 0; @@ -118,31 +143,4 @@ public class File implements Parcelable { dest.writeString(this.torrentDownloadUrl); dest.writeString(this.torrentUrl); } - - public File() { - } - - protected File(Parcel in) { - this.fileDownloadUrl = in.readString(); - this.fileUrl = in.readString(); - this.fps = in.readInt(); - this.magnetUri = in.readString(); - this.metadataUrl = in.readString(); - this.resolutions = in.readParcelable(Item.class.getClassLoader()); - this.size = in.readLong(); - this.torrentDownloadUrl = in.readString(); - this.torrentUrl = in.readString(); - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public File createFromParcel(Parcel source) { - return new File(source); - } - - @Override - public File[] newArray(int size) { - return new File[size]; - } - }; } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/StreamingPlaylists.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/StreamingPlaylists.java index f3ea3e2..dca4c6d 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/StreamingPlaylists.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/StreamingPlaylists.java @@ -14,13 +14,27 @@ package app.fedilab.fedilabtube.client.entities; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.os.Parcel; +import android.os.Parcelable; + import com.google.gson.annotations.SerializedName; import java.util.List; @SuppressWarnings({"unused", "RedundantSuppression"}) -public class StreamingPlaylists { +public class StreamingPlaylists implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public StreamingPlaylists createFromParcel(Parcel in) { + return new StreamingPlaylists(in); + } + + @Override + public StreamingPlaylists[] newArray(int size) { + return new StreamingPlaylists[size]; + } + }; @SerializedName("id") private String id; @SerializedName("type") @@ -34,6 +48,15 @@ public class StreamingPlaylists { @SerializedName("redundancies") private List redundancies; + protected StreamingPlaylists(Parcel in) { + id = in.readString(); + type = in.readInt(); + playlistUrl = in.readString(); + segmentsSha256Url = in.readString(); + files = in.createTypedArrayList(File.CREATOR); + redundancies = in.createTypedArrayList(Redundancies.CREATOR); + } + public String getId() { return id; } @@ -82,10 +105,41 @@ public class StreamingPlaylists { this.redundancies = redundancies; } - public static class Redundancies { + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(id); + parcel.writeInt(type); + parcel.writeString(playlistUrl); + parcel.writeString(segmentsSha256Url); + parcel.writeTypedList(files); + parcel.writeTypedList(redundancies); + } + + + public static class Redundancies implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public Redundancies createFromParcel(Parcel in) { + return new Redundancies(in); + } + + @Override + public Redundancies[] newArray(int size) { + return new Redundancies[size]; + } + }; @SerializedName("baseUrl") private String baseUrl; + protected Redundancies(Parcel in) { + baseUrl = in.readString(); + } + public String getBaseUrl() { return baseUrl; } @@ -93,5 +147,15 @@ public class StreamingPlaylists { public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(baseUrl); + } } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java index a6f8272..5da4280 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/UserSettings.java @@ -37,26 +37,14 @@ public class UserSettings { return videosHistoryEnabled; } - public void setVideosHistoryEnabled(Boolean videosHistoryEnabled) { - this.videosHistoryEnabled = videosHistoryEnabled; - } - public Boolean isAutoPlayVideo() { return autoPlayVideo; } - public void setAutoPlayVideo(Boolean autoPlayVideo) { - this.autoPlayVideo = autoPlayVideo; - } - public Boolean isWebTorrentEnabled() { return webTorrentEnabled; } - public void setWebTorrentEnabled(Boolean webTorrentEnabled) { - this.webTorrentEnabled = webTorrentEnabled; - } - public List getVideoLanguages() { return videoLanguages; } @@ -93,32 +81,44 @@ public class UserSettings { return videosHistoryEnabled; } + public void setVideosHistoryEnabled(Boolean videosHistoryEnabled) { + this.videosHistoryEnabled = videosHistoryEnabled; + } + public Boolean getAutoPlayVideo() { return autoPlayVideo; } + public void setAutoPlayVideo(Boolean autoPlayVideo) { + this.autoPlayVideo = autoPlayVideo; + } + public Boolean getWebTorrentEnabled() { return webTorrentEnabled; } + public void setWebTorrentEnabled(Boolean webTorrentEnabled) { + this.webTorrentEnabled = webTorrentEnabled; + } + public Boolean isAutoPlayNextVideo() { return autoPlayNextVideo; } + public Boolean getAutoPlayNextVideo() { + return autoPlayNextVideo; + } + public void setAutoPlayNextVideo(Boolean autoPlayNextVideo) { this.autoPlayNextVideo = autoPlayNextVideo; } - public Boolean getAutoPlayNextVideo() { - return autoPlayNextVideo; - } - public String getFileName() { return fileName; } public void setFileName(String fileName) { - if( fileName == null) { + if (fileName == null) { this.fileName = "avatar.png"; } else { this.fileName = fileName; diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/ViewsPerDay.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/ViewsPerDay.java index d1c372c..cba2d80 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/ViewsPerDay.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/ViewsPerDay.java @@ -14,18 +14,38 @@ package app.fedilab.fedilabtube.client.entities; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.os.Parcel; +import android.os.Parcelable; + import com.google.gson.annotations.SerializedName; import java.util.Date; @SuppressWarnings({"unused", "RedundantSuppression"}) -public class ViewsPerDay { +public class ViewsPerDay implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public ViewsPerDay createFromParcel(Parcel in) { + return new ViewsPerDay(in); + } + + @Override + public ViewsPerDay[] newArray(int size) { + return new ViewsPerDay[size]; + } + }; @SerializedName("date") private Date date; @SerializedName("views") private int views; + protected ViewsPerDay(Parcel in) { + long tmpDate = in.readLong(); + this.date = tmpDate == -1 ? null : new Date(tmpDate); + views = in.readInt(); + } + public Date getDate() { return date; } @@ -41,4 +61,15 @@ public class ViewsPerDay { public void setViews(int views) { this.views = views; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeLong(this.date != null ? this.date.getTime() : -1); + parcel.writeInt(views); + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/drawer/AboutInstanceAdapter.java b/app/src/main/java/app/fedilab/fedilabtube/drawer/AboutInstanceAdapter.java new file mode 100644 index 0000000..b918bc1 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/drawer/AboutInstanceAdapter.java @@ -0,0 +1,160 @@ +package app.fedilab.fedilabtube.drawer; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.text.Html; +import android.text.SpannableString; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.PopupMenu; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import app.fedilab.fedilabtube.R; +import app.fedilab.fedilabtube.client.data.InstanceData; +import app.fedilab.fedilabtube.databinding.DrawerAboutInstanceBinding; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.sqlite.Sqlite; +import app.fedilab.fedilabtube.sqlite.StoredInstanceDAO; + +import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY; + + +public class AboutInstanceAdapter extends RecyclerView.Adapter { + + + private final List aboutInstances; + public AllInstancesRemoved allInstancesRemoved; + private Context context; + + public AboutInstanceAdapter(List aboutInstances) { + this.aboutInstances = aboutInstances; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() { + return aboutInstances.size(); + } + + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + context = parent.getContext(); + DrawerAboutInstanceBinding itemBinding = DrawerAboutInstanceBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new ViewHolder(itemBinding); + } + + @SuppressLint("ApplySharedPref") + @Override + public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) { + + context = viewHolder.itemView.getContext(); + + final ViewHolder holder = (ViewHolder) viewHolder; + + final InstanceData.AboutInstance aboutInstance = aboutInstances.get(i); + + holder.binding.aboutInstanceHost.setText(aboutInstance.getHost()); + + SpannableString spannableString; + if (aboutInstance.getShortDescription() != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + spannableString = new SpannableString(Html.fromHtml(aboutInstance.getShortDescription(), FROM_HTML_MODE_LEGACY)); + else + spannableString = new SpannableString(Html.fromHtml(aboutInstance.getShortDescription())); + holder.binding.aboutInstanceDescription.setText(spannableString, TextView.BufferType.SPANNABLE); + } + + holder.binding.aboutInstanceName.setText(aboutInstance.getName()); + holder.binding.instanceContainer.setOnClickListener(v -> { + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.PREF_INSTANCE, aboutInstance.getHost()); + editor.commit(); + Helper.logoutNoRemoval((Activity) context); + }); + holder.binding.instanceMore.setOnClickListener(v -> { + PopupMenu popup = new PopupMenu(context, holder.binding.instanceMore); + popup.getMenuInflater() + .inflate(R.menu.instance_menu, popup.getMenu()); + popup.setOnMenuItemClickListener(item -> { + int itemId = item.getItemId(); + if (itemId == R.id.action_delete) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.delete_instance); + builder.setMessage(R.string.delete_instance_confirm); + builder.setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.delete, (dialog, which) -> { + new Thread(() -> { + SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + new StoredInstanceDAO(context, db).removeInstance(aboutInstance.getHost()); + aboutInstances.remove(aboutInstance); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + notifyItemRemoved(i); + if (aboutInstances.size() == 0) { + allInstancesRemoved.onAllInstancesRemoved(); + } + }; + mainHandler.post(myRunnable); + }).start(); + + dialog.dismiss(); + }) + .setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss()) + .show(); + } + return true; + }); + popup.show(); + }); + } + + public interface AllInstancesRemoved { + void onAllInstancesRemoved(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + + DrawerAboutInstanceBinding binding; + + ViewHolder(DrawerAboutInstanceBinding itemView) { + super(itemView.getRoot()); + binding = itemView; + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java b/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java index cfdf431..02069ad 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java +++ b/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java @@ -130,7 +130,7 @@ public class AccountsListAdapter extends RecyclerView.Adapter comments; private final CommentListAdapter commentListAdapter; + private final boolean isThread; public AllCommentRemoved allCommentRemoved; boolean isVideoOwner; private Context context; - private final boolean isThread; public CommentListAdapter(List comments, boolean isVideoOwner, boolean isThread) { this.comments = comments; @@ -125,11 +125,11 @@ public class CommentListAdapter extends RecyclerView.Adapter ((PeertubeActivity) context).openPostComment(comment, i)); @@ -375,8 +375,8 @@ public class CommentListAdapter extends RecyclerView.Adapter. */ +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; + +import androidx.annotation.NonNull; import androidx.appcompat.widget.PopupMenu; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStoreOwner; +import androidx.recyclerview.widget.RecyclerView; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.FutureTarget; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.util.List; +import java.util.concurrent.ExecutionException; import app.fedilab.fedilabtube.AllPlaylistsActivity; +import app.fedilab.fedilabtube.BuildConfig; +import app.fedilab.fedilabtube.LocalPlaylistsActivity; +import app.fedilab.fedilabtube.MainActivity; import app.fedilab.fedilabtube.PlaylistsActivity; import app.fedilab.fedilabtube.R; import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; import app.fedilab.fedilabtube.client.data.PlaylistData.Playlist; +import app.fedilab.fedilabtube.client.data.VideoPlaylistData; +import app.fedilab.fedilabtube.databinding.DrawerPlaylistBinding; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.helper.NotificationHelper; +import app.fedilab.fedilabtube.helper.PlaylistExportHelper; +import app.fedilab.fedilabtube.sqlite.ManagePlaylistsDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; import app.fedilab.fedilabtube.viewmodel.PlaylistsVM; +import es.dmoral.toasty.Toasty; + +import static app.fedilab.fedilabtube.viewmodel.PlaylistsVM.action.GET_LIST_VIDEOS; -public class PlaylistAdapter extends BaseAdapter { +public class PlaylistAdapter extends RecyclerView.Adapter { private final List playlists; - private final LayoutInflater layoutInflater; - private final Context context; - private final RelativeLayout textviewNoAction; + private final boolean locale; + public AllPlaylistRemoved allPlaylistRemoved; + private Context context; - public PlaylistAdapter(Context context, List lists, RelativeLayout textviewNoAction) { + public PlaylistAdapter(List lists, boolean locale) { this.playlists = lists; - layoutInflater = LayoutInflater.from(context); - this.context = context; - this.textviewNoAction = textviewNoAction; + this.locale = locale; } + @NonNull @Override - public int getCount() { - return playlists.size(); + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + context = parent.getContext(); + DrawerPlaylistBinding itemBinding = DrawerPlaylistBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new ViewHolder(itemBinding); } + @SuppressLint({"SetJavaScriptEnabled", "ClickableViewAccessibility"}) @Override - public Object getItem(int position) { - return playlists.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { + public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int position) { + context = viewHolder.itemView.getContext(); + final ViewHolder holder = (ViewHolder) viewHolder; final Playlist playlist = playlists.get(position); - final ViewHolder holder; - if (convertView == null) { - convertView = layoutInflater.inflate(R.layout.drawer_playlist, parent, false); - holder = new ViewHolder(); - holder.preview_title = convertView.findViewById(R.id.preview_title); - holder.preview_visibility = convertView.findViewById(R.id.preview_visibility); - holder.preview_description = convertView.findViewById(R.id.preview_description); - holder.playlist_container = convertView.findViewById(R.id.playlist_container); - holder.preview_playlist = convertView.findViewById(R.id.preview_playlist); - holder.playlist_more = convertView.findViewById(R.id.playlist_more); - convertView.setTag(holder); + String imgUrl; + + if (locale) { + imgUrl = "https://" + playlist.getOwnerAccount().getHost() + playlist.getThumbnailPath(); } else { - holder = (ViewHolder) convertView.getTag(); + imgUrl = playlist.getThumbnailPath(); } + Helper.loadGiF(context, imgUrl, holder.binding.previewPlaylist); - Helper.loadGiF(context, playlist.getThumbnailPath(), holder.preview_playlist); - - holder.preview_title.setText(playlist.getDisplayName()); + holder.binding.previewTitle.setText(playlist.getDisplayName()); if (playlist.getDescription() != null && playlist.getDescription().trim().compareTo("null") != 0 && playlist.getDescription().length() > 0) { - holder.preview_description.setText(playlist.getDescription()); - holder.preview_description.setVisibility(View.VISIBLE); + holder.binding.previewDescription.setText(playlist.getDescription()); + holder.binding.previewDescription.setVisibility(View.VISIBLE); } else { - holder.preview_description.setVisibility(View.GONE); + holder.binding.previewDescription.setVisibility(View.GONE); } - holder.preview_visibility.setText(playlist.getPrivacy().getLabel()); + holder.binding.previewVisibility.setText(playlist.getPrivacy().getLabel()); - holder.playlist_container.setOnClickListener(v -> { - Intent intent = new Intent(context, PlaylistsActivity.class); + holder.binding.playlistContainer.setOnClickListener(v -> { + Intent intent = new Intent(context, locale ? LocalPlaylistsActivity.class : PlaylistsActivity.class); Bundle b = new Bundle(); b.putParcelable("playlist", playlist); intent.putExtras(b); @@ -113,15 +129,22 @@ public class PlaylistAdapter extends BaseAdapter { }); if (playlist.getDisplayName().compareTo("Watch later") == 0) { - holder.playlist_more.setVisibility(View.GONE); + holder.binding.playlistMore.setVisibility(View.GONE); } else { - holder.playlist_more.setVisibility(View.VISIBLE); + holder.binding.playlistMore.setVisibility(View.VISIBLE); } - holder.playlist_more.setOnClickListener(v -> { - PopupMenu popup = new PopupMenu(context, holder.playlist_more); + holder.binding.playlistMore.setOnClickListener(v -> { + PopupMenu popup = new PopupMenu(context, holder.binding.playlistMore); popup.getMenuInflater() .inflate(R.menu.playlist_menu, popup.getMenu()); + if (!BuildConfig.full_instances) { + popup.getMenu().findItem(R.id.action_export).setVisible(true); + } + if (locale) { + popup.getMenu().findItem(R.id.action_export).setVisible(false); + popup.getMenu().findItem(R.id.action_edit).setVisible(false); + } popup.setOnMenuItemClickListener(item -> { int itemId = item.getItemId(); if (itemId == R.id.action_delete) { @@ -132,11 +155,18 @@ public class PlaylistAdapter extends BaseAdapter { .setPositiveButton(R.string.yes, (dialog, which) -> { playlists.remove(playlist); notifyDataSetChanged(); - PlaylistsVM viewModel = new ViewModelProvider((ViewModelStoreOwner) context).get(PlaylistsVM.class); - viewModel.manage(PlaylistsVM.action.DELETE_PLAYLIST, playlist, null).observe((LifecycleOwner) context, apiResponse -> manageVIewPlaylists(PlaylistsVM.action.DELETE_PLAYLIST, apiResponse)); - - if (playlists.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE) - textviewNoAction.setVisibility(View.VISIBLE); + if (!locale) { + PlaylistsVM viewModel = new ViewModelProvider((ViewModelStoreOwner) context).get(PlaylistsVM.class); + viewModel.manage(PlaylistsVM.action.DELETE_PLAYLIST, playlist, null).observe((LifecycleOwner) context, apiResponse -> manageVIewPlaylists(PlaylistsVM.action.DELETE_PLAYLIST, apiResponse)); + } else { + new Thread(() -> { + SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + new ManagePlaylistsDAO(context, db).removePlaylist(playlist.getUuid()); + }).start(); + } + if (playlists.size() == 0) { + allPlaylistRemoved.onAllPlaylistRemoved(); + } dialog.dismiss(); }) .setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss()) @@ -145,26 +175,116 @@ public class PlaylistAdapter extends BaseAdapter { if (context instanceof AllPlaylistsActivity) { ((AllPlaylistsActivity) context).manageAlert(playlist); } + } else if (itemId == R.id.action_export) { + if (Build.VERSION.SDK_INT >= 23) { + if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE); + } else { + doExport(playlist); + } + } else { + doExport(playlist); + } } return true; }); popup.show(); }); - return convertView; } + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() { + return playlists.size(); + } + + private void doExport(Playlist playlist) { + new Thread(() -> { + File file = null; + RetrofitPeertubeAPI retrofitPeertubeAPI = new RetrofitPeertubeAPI(context); + APIResponse apiResponse = retrofitPeertubeAPI.playlistAction(GET_LIST_VIDEOS, playlist.getId(), null, null, null); + if (apiResponse != null) { + List videos = apiResponse.getVideoPlaylist(); + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = new VideoPlaylistData.VideoPlaylistExport(); + videoPlaylistExport.setPlaylist(playlist); + videoPlaylistExport.setUuid(playlist.getUuid()); + videoPlaylistExport.setAcct(MainActivity.userMe.getAccount().getAcct()); + videoPlaylistExport.setVideos(videos); + + String data = PlaylistExportHelper.playlistToStringStorage(videoPlaylistExport); + + + File root = new File(Environment.getExternalStorageDirectory(), context.getString(R.string.app_name)); + if (!root.exists()) { + //noinspection ResultOfMethodCallIgnored + root.mkdirs(); + } + file = new File(root, "playlist_" + playlist.getUuid() + ".tubelab"); + FileWriter writer; + try { + writer = new FileWriter(file); + writer.append(data); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> Toasty.error(context, context.getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); + mainHandler.post(myRunnable); + return; + } + + + } + String urlAvatar = playlist.getThumbnailPath() != null ? Helper.getLiveInstance(context) + playlist.getThumbnailPath() : null; + FutureTarget futureBitmapChannel = Glide.with(context.getApplicationContext()) + .asBitmap() + .load(urlAvatar != null ? urlAvatar : R.drawable.missing_peertube).submit(); + Bitmap icon = null; + try { + icon = futureBitmapChannel.get(); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + } + if (file != null) { + Intent mailIntent = new Intent(Intent.ACTION_SEND); + mailIntent.setType("message/rfc822"); + Uri contentUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", file); + mailIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.export_notification_subjet)); + mailIntent.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.export_notification_body)); + mailIntent.putExtra(Intent.EXTRA_STREAM, contentUri); + NotificationHelper.notify_user(context.getApplicationContext(), + playlist.getOwnerAccount(), mailIntent, icon, + context.getString(R.string.export_notification_title), + context.getString(R.string.export_notification_content)); + } + + + }).start(); + } + + @SuppressWarnings({"unused", "RedundantSuppression"}) public void manageVIewPlaylists(PlaylistsVM.action actionType, APIResponse apiResponse) { } - private static class ViewHolder { - LinearLayout playlist_container; - ImageView preview_playlist; - TextView preview_title, preview_visibility, preview_description; - ImageButton playlist_more; + public interface AllPlaylistRemoved { + void onAllPlaylistRemoved(); } + static class ViewHolder extends RecyclerView.ViewHolder { + DrawerPlaylistBinding binding; + + ViewHolder(DrawerPlaylistBinding itemView) { + super(itemView.getRoot()); + binding = itemView; + } + } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java index 6021593..24b9f18 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java @@ -54,7 +54,6 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; private boolean firstLoad; private SwipeRefreshLayout swipeRefreshLayout; - private boolean swiped; private RecyclerView lv_accounts; private View rootView; private RetrofitPeertubeAPI.DataType accountFetch; @@ -75,7 +74,6 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda max_id = null; firstLoad = true; flag_loading = true; - swiped = false; swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); @@ -167,7 +165,6 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda if (apiResponse.getError() != null) { Toasty.error(context, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); swipeRefreshLayout.setRefreshing(false); - swiped = false; flag_loading = false; return; } @@ -181,21 +178,22 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda } } - if (!swiped && firstLoad && (accounts == null || accounts.size() == 0)) + if (firstLoad && (accounts == null || accounts.size() == 0)) textviewNoAction.setVisibility(View.VISIBLE); else textviewNoAction.setVisibility(View.GONE); max_id = apiResponse.getMax_id(); - if (swiped) { - accountsListAdapter = new AccountsListAdapter(accountFetch, this.accounts); - lv_accounts.setAdapter(accountsListAdapter); - swiped = false; - } if (accounts != null && accounts.size() > 0) { + int previousPosition = this.accounts.size(); int currentPosition = this.accounts.size(); this.accounts.addAll(accounts); - accountsListAdapter.notifyItemRangeChanged(currentPosition, accounts.size()); + if (previousPosition == 0) { + accountsListAdapter = new AccountsListAdapter(accountFetch, this.accounts); + accountsListAdapter.allAccountsRemoved = this; + lv_accounts.setAdapter(accountsListAdapter); + } else + accountsListAdapter.notifyItemRangeChanged(currentPosition, accounts.size()); } swipeRefreshLayout.setRefreshing(false); firstLoad = false; @@ -206,7 +204,6 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda accounts = new ArrayList<>(); firstLoad = true; flag_loading = true; - swiped = true; swipeRefreshLayout.setRefreshing(true); AccountsVM viewModel = new ViewModelProvider(this).get(AccountsVM.class); viewModel.getAccounts(RetrofitPeertubeAPI.DataType.MUTED, null).observe(DisplayAccountsFragment.this.requireActivity(), this::manageViewAccounts); diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayChannelsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayChannelsFragment.java index c4a9e10..8b59547 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayChannelsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayChannelsFragment.java @@ -63,7 +63,6 @@ public class DisplayChannelsFragment extends Fragment implements ChannelListAdap private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; private SwipeRefreshLayout swipeRefreshLayout; private String name; - private boolean swiped; private RecyclerView lv_channels; private View rootView; private FloatingActionButton action_button; @@ -83,7 +82,6 @@ public class DisplayChannelsFragment extends Fragment implements ChannelListAdap myChannels = bundle.getBoolean("myChannels", true); } - swiped = false; swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); @@ -165,26 +163,25 @@ public class DisplayChannelsFragment extends Fragment implements ChannelListAdap if (apiResponse.getError() != null) { Toasty.error(context, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); swipeRefreshLayout.setRefreshing(false); - swiped = false; return; } List channels = apiResponse.getChannels(); - if (!swiped && (channels == null || channels.size() == 0)) + if ((channels == null || channels.size() == 0)) textviewNoAction.setVisibility(View.VISIBLE); else textviewNoAction.setVisibility(View.GONE); - if (swiped) { - channelListAdapter = new ChannelListAdapter(this.channels, myChannels); - channelListAdapter.allChannelRemoved = DisplayChannelsFragment.this; - channelListAdapter.editAlertDialog = DisplayChannelsFragment.this; - lv_channels.setAdapter(channelListAdapter); - swiped = false; - } if (channels != null && channels.size() > 0) { int currentPosition = this.channels.size(); this.channels.addAll(channels); - channelListAdapter.notifyItemRangeChanged(currentPosition, channels.size()); + if (currentPosition == 0) { + channelListAdapter = new ChannelListAdapter(this.channels, myChannels); + channelListAdapter.allChannelRemoved = DisplayChannelsFragment.this; + channelListAdapter.editAlertDialog = DisplayChannelsFragment.this; + lv_channels.setAdapter(channelListAdapter); + } else { + channelListAdapter.notifyItemRangeChanged(currentPosition, channels.size()); + } } swipeRefreshLayout.setRefreshing(false); } @@ -192,7 +189,6 @@ public class DisplayChannelsFragment extends Fragment implements ChannelListAdap public void pullToRefresh() { channels = new ArrayList<>(); - swiped = true; swipeRefreshLayout.setRefreshing(true); ChannelsVM viewModel = new ViewModelProvider(this).get(ChannelsVM.class); if (name != null) { diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java index 933f3d8..0d3dbcf 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java @@ -72,9 +72,9 @@ public class DisplayNotificationsFragment extends Fragment { private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; private boolean firstLoad; private SwipeRefreshLayout swipeRefreshLayout; - private boolean swiped; private RecyclerView lv_notifications; private View rootView; + private NotificationsVM viewModel; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -86,10 +86,10 @@ public class DisplayNotificationsFragment extends Fragment { max_id = "0"; firstLoad = true; flag_loading = true; - swiped = false; swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); + viewModel = new ViewModelProvider(this).get(NotificationsVM.class); lv_notifications = rootView.findViewById(R.id.lv_elements); lv_notifications.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); @@ -115,7 +115,6 @@ public class DisplayNotificationsFragment extends Fragment { if (firstVisibleItem + visibleItemCount == totalItemCount) { if (!flag_loading) { flag_loading = true; - NotificationsVM viewModel = new ViewModelProvider(DisplayNotificationsFragment.this).get(NotificationsVM.class); viewModel.getNotifications(null, max_id).observe(DisplayNotificationsFragment.this.requireActivity(), apiResponse -> manageVIewNotifications(apiResponse)); nextElementLoader.setVisibility(View.VISIBLE); } @@ -127,8 +126,7 @@ public class DisplayNotificationsFragment extends Fragment { }); swipeRefreshLayout.setOnRefreshListener(this::pullToRefresh); - NotificationsVM viewModel = new ViewModelProvider(this).get(NotificationsVM.class); - viewModel.getNotifications(null, null).observe(DisplayNotificationsFragment.this.requireActivity(), this::manageVIewNotifications); + viewModel.getNotifications(null, "0").observe(DisplayNotificationsFragment.this.requireActivity(), this::manageVIewNotifications); return rootView; } @@ -138,9 +136,22 @@ public class DisplayNotificationsFragment extends Fragment { rootView = null; } + + @Override + public void onPause() { + super.onPause(); + if (swipeRefreshLayout != null) { + swipeRefreshLayout.setEnabled(false); + swipeRefreshLayout.setRefreshing(false); + swipeRefreshLayout.clearAnimation(); + } + } + + @Override public void onResume() { super.onResume(); + swipeRefreshLayout.setEnabled(true); if (getActivity() != null && getActivity() != null) { View action_button = getActivity().findViewById(R.id.action_button); if (action_button != null) { @@ -172,15 +183,15 @@ public class DisplayNotificationsFragment extends Fragment { public void pullToRefresh() { - max_id = "0"; + int size = notifications.size(); + notifications.clear(); notifications = new ArrayList<>(); + max_id = "0"; + peertubeNotificationsListAdapter.notifyItemRangeRemoved(0, size); firstLoad = true; flag_loading = true; - swiped = true; swipeRefreshLayout.setRefreshing(true); - NotificationsVM viewModel = new ViewModelProvider(this).get(NotificationsVM.class); - viewModel.getNotifications(null, null).observe(DisplayNotificationsFragment.this.requireActivity(), this::manageVIewNotifications); - + viewModel.getNotifications(null, "0").observe(DisplayNotificationsFragment.this.requireActivity(), this::manageVIewNotifications); } private void manageVIewNotifications(APIResponse apiResponse) { @@ -190,28 +201,25 @@ public class DisplayNotificationsFragment extends Fragment { Toasty.error(context, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); flag_loading = false; swipeRefreshLayout.setRefreshing(false); - swiped = false; return; } int previousPosition = notifications.size(); max_id = String.valueOf(Integer.parseInt(max_id) + 20); List notifications = apiResponse.getPeertubeNotifications(); - if (!swiped && firstLoad && (notifications == null || notifications.size() == 0)) + if (firstLoad && (notifications == null || notifications.size() == 0)) textviewNoAction.setVisibility(View.VISIBLE); else textviewNoAction.setVisibility(View.GONE); - if (swiped) { - if (previousPosition > 0) { - this.notifications.subList(0, previousPosition).clear(); - peertubeNotificationsListAdapter.notifyItemRangeRemoved(0, previousPosition); - } - swiped = false; - } + if (notifications != null && notifications.size() > 0) { this.notifications.addAll(notifications); - peertubeNotificationsListAdapter.notifyItemRangeInserted(previousPosition, notifications.size()); + if (previousPosition == 0) { + peertubeNotificationsListAdapter = new PeertubeNotificationsListAdapter(this.notifications); + lv_notifications.setAdapter(peertubeNotificationsListAdapter); + } else + peertubeNotificationsListAdapter.notifyItemRangeInserted(previousPosition, notifications.size()); } else { if (firstLoad) textviewNoAction.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java index 23c89c2..7fa0c0d 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java @@ -39,6 +39,7 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -93,14 +94,14 @@ public class DisplayPlaylistsFragment extends Fragment { playlists = new ArrayList<>(); - ListView lv_playlist = rootView.findViewById(R.id.lv_playlist); + RecyclerView lv_playlist = rootView.findViewById(R.id.lv_playlist); textviewNoAction = rootView.findViewById(R.id.no_action); mainLoader = rootView.findViewById(R.id.loader); RelativeLayout nextElementLoader = rootView.findViewById(R.id.loading_next_items); mainLoader.setVisibility(View.VISIBLE); nextElementLoader.setVisibility(View.GONE); playlists = new ArrayList<>(); - playlistAdapter = new PlaylistAdapter(context, playlists, textviewNoAction); + playlistAdapter = new PlaylistAdapter(playlists, false); lv_playlist.setAdapter(playlistAdapter); PlaylistsVM viewModel = new ViewModelProvider(this).get(PlaylistsVM.class); viewModel.manage(PlaylistsVM.action.GET_PLAYLISTS, null, null).observe(DisplayPlaylistsFragment.this.requireActivity(), apiResponse -> manageVIewPlaylists(PlaylistsVM.action.GET_PLAYLISTS, apiResponse)); diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java index 2bca763..20c2d81 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayVideosFragment.java @@ -65,6 +65,8 @@ import app.fedilab.fedilabtube.viewmodel.SearchVM; import app.fedilab.fedilabtube.viewmodel.TimelineVM; import es.dmoral.toasty.Toasty; +import static app.fedilab.fedilabtube.viewmodel.TimelineVM.TimelineType.VIDEOS_IN_LOCAL_PLAYLIST; + public class DisplayVideosFragment extends Fragment implements AccountsHorizontalListAdapter.EventListener, PeertubeAdapter.RelationShipListener, PeertubeAdapter.PlaylistListener { @@ -99,6 +101,7 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta private String playlistId; private String remoteInstance; private boolean sepiaSearch; + private String startDate, endDate; public DisplayVideosFragment() { } @@ -112,6 +115,8 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta peertubes = new ArrayList<>(); channels = new ArrayList<>(); context = getContext(); + startDate = null; + endDate = null; Bundle bundle = this.getArguments(); if (bundle != null) { search_peertube = bundle.getString("search_peertube", null); @@ -120,6 +125,8 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta sepiaSearch = bundle.getBoolean("sepia_search", false); type = (TimelineVM.TimelineType) bundle.get(Helper.TIMELINE_TYPE); playlistId = bundle.getString("playlistId", null); + startDate = bundle.getString("startDate", null); + endDate = bundle.getString("endDate", null); } max_id = "0"; forAccount = type == TimelineVM.TimelineType.ACCOUNT_VIDEOS ? channelId : null; @@ -182,57 +189,59 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta }); - lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() { - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - if (type == TimelineVM.TimelineType.SUBSCRIBTIONS) { - if (dy > 0) { - if (check_ScrollingUp) { - top_account_container.setVisibility(View.GONE); - final Handler handler = new Handler(); - handler.postDelayed(() -> check_ScrollingUp = false, 300); + if (type != VIDEOS_IN_LOCAL_PLAYLIST) { + lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + if (type == TimelineVM.TimelineType.SUBSCRIBTIONS) { + if (dy > 0) { + if (check_ScrollingUp) { + top_account_container.setVisibility(View.GONE); + final Handler handler = new Handler(); + handler.postDelayed(() -> check_ScrollingUp = false, 300); + } + } else { + if (!check_ScrollingUp) { + top_account_container.setVisibility(View.VISIBLE); + final Handler handler = new Handler(); + handler.postDelayed(() -> check_ScrollingUp = true, 300); + } } - } else { - if (!check_ScrollingUp) { - top_account_container.setVisibility(View.VISIBLE); - final Handler handler = new Handler(); - handler.postDelayed(() -> check_ScrollingUp = true, 300); + } + if (mLayoutManager != null) { + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (dy > 0) { + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { + if (!flag_loading) { + flag_loading = true; + loadTimeline(max_id); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } else if (gLayoutManager != null) { + int firstVisibleItem = gLayoutManager.findFirstVisibleItemPosition(); + if (dy > 0) { + int visibleItemCount = gLayoutManager.getChildCount(); + int totalItemCount = gLayoutManager.getItemCount(); + if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { + if (!flag_loading) { + flag_loading = true; + loadTimeline(max_id); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } } } } - if (mLayoutManager != null) { - int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); - if (dy > 0) { - int visibleItemCount = mLayoutManager.getChildCount(); - int totalItemCount = mLayoutManager.getItemCount(); - if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { - if (!flag_loading) { - flag_loading = true; - loadTimeline(max_id); - nextElementLoader.setVisibility(View.VISIBLE); - } - } else { - nextElementLoader.setVisibility(View.GONE); - } - } - } else if (gLayoutManager != null) { - int firstVisibleItem = gLayoutManager.findFirstVisibleItemPosition(); - if (dy > 0) { - int visibleItemCount = gLayoutManager.getChildCount(); - int totalItemCount = gLayoutManager.getItemCount(); - if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { - if (!flag_loading) { - flag_loading = true; - loadTimeline(max_id); - nextElementLoader.setVisibility(View.VISIBLE); - } - } else { - nextElementLoader.setVisibility(View.GONE); - } - } - } - } - }); + }); + } if (type == TimelineVM.TimelineType.SUBSCRIBTIONS) { AccountsVM viewModel = new ViewModelProvider(this).get(AccountsVM.class); viewModel.getAccounts(RetrofitPeertubeAPI.DataType.SUBSCRIBER, max_id).observe(DisplayVideosFragment.this.requireActivity(), this::manageViewAccounts); @@ -245,6 +254,12 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta return rootView; } + @Override + public void onResume() { + super.onResume(); + swipeRefreshLayout.setEnabled(true); + } + @Override public void onPause() { @@ -434,12 +449,6 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta rootView = null; } - @Override - public void onResume() { - super.onResume(); - swipeRefreshLayout.setEnabled(true); - } - public void scrollToTop() { if (mLayoutManager != null) { @@ -501,6 +510,10 @@ public class DisplayVideosFragment extends Fragment implements AccountsHorizonta viewModelFeeds.getVideosInChannel(sepiaSearch ? remoteInstance : null, channelId, max_id).observe(this.requireActivity(), this::manageVIewVideos); } else if (type == TimelineVM.TimelineType.VIDEOS_IN_PLAYLIST) { viewModelFeeds.loadVideosInPlaylist(playlistId, max_id).observe(this.requireActivity(), this::manageVIewVideos); + } else if (type == VIDEOS_IN_LOCAL_PLAYLIST) { + viewModelFeeds.loadVideosInLocalPlaylist(playlistId).observe(this.requireActivity(), this::manageVIewVideos); + } else if (type == TimelineVM.TimelineType.HISTORY) { + viewModelFeeds.getVideoHistory(max_id, startDate, endDate).observe(this.requireActivity(), this::manageVIewVideos); } else { viewModelFeeds.getVideos(type, max_id, forAccount).observe(this.requireActivity(), this::manageVIewVideos); } diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java index 47d5c6d..ab8d43d 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java @@ -21,21 +21,6 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SeekBarPreference; import androidx.preference.SwitchPreference; -/* Copyright 2020 Thomas Schneider - * - * This file is a part of TubeLab - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with TubeLab; if not, - * see . */ - import com.bumptech.glide.Glide; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; @@ -60,6 +45,21 @@ import es.dmoral.toasty.Toasty; import static app.fedilab.fedilabtube.MainActivity.peertubeInformation; import static app.fedilab.fedilabtube.MainActivity.userMe; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { @Override @@ -135,7 +135,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if (set_video_sensitive_choice != null) { editor.putString(getString(R.string.set_video_sensitive_choice), set_video_sensitive_choice.getValue()); editor.apply(); - if(Helper.isLoggedIn(getActivity())) { + if (Helper.isLoggedIn(getActivity())) { new Thread(() -> { UserSettings userSettings = new UserSettings(); userSettings.setNsfwPolicy(set_video_sensitive_choice.getValue()); @@ -182,7 +182,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared SwitchPreference set_autoplay_choice = findPreference(getString(R.string.set_autoplay_choice)); assert set_autoplay_choice != null; editor.putBoolean(getString(R.string.set_autoplay_choice), set_autoplay_choice.isChecked()); - if(Helper.isLoggedIn(getActivity())) { + if (Helper.isLoggedIn(getActivity())) { new Thread(() -> { UserSettings userSettings = new UserSettings(); userSettings.setAutoPlayVideo(set_autoplay_choice.isChecked()); @@ -204,7 +204,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared SwitchPreference set_autoplay_next_video_choice = findPreference(getString(R.string.set_autoplay_next_video_choice)); assert set_autoplay_next_video_choice != null; editor.putBoolean(getString(R.string.set_autoplay_next_video_choice), set_autoplay_next_video_choice.isChecked()); - if(Helper.isLoggedIn(getActivity())) { + if (Helper.isLoggedIn(getActivity())) { new Thread(() -> { UserSettings userSettings = new UserSettings(); userSettings.setAutoPlayNextVideo(set_autoplay_next_video_choice.isChecked()); @@ -233,7 +233,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared MultiSelectListPreference set_video_language_choice = findPreference(getString(R.string.set_video_language_choice)); assert set_video_language_choice != null; editor.putStringSet(getString(R.string.set_video_language_choice), set_video_language_choice.getValues()); - if(Helper.isLoggedIn(getActivity())) { + if (Helper.isLoggedIn(getActivity())) { new Thread(() -> { UserSettings userSettings = new UserSettings(); Set language_choiceValues = set_video_language_choice.getValues(); @@ -266,7 +266,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared Preference my_account = findPreference("my_account"); assert my_account != null; - if(!Helper.isLoggedIn(getActivity()) || userMe == null) { + if (!Helper.isLoggedIn(getActivity()) || userMe == null) { my_account.setVisible(false); } else { my_account.setTitle(userMe.getUsername()); @@ -274,19 +274,24 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared Resources resources = getResources(); Drawable defaultAvatar = ResourcesCompat.getDrawable(resources, R.drawable.missing_peertube, null); my_account.setIcon(defaultAvatar); + String avatarUrl = null; + if (userMe.getAccount().getAvatar() != null) { + avatarUrl = "https://" + Helper.getLiveInstance(context) + userMe.getAccount().getAvatar().getPath(); + } Glide.with(getActivity()) - .asDrawable() - .load("https://" + Helper.getLiveInstance(context) + userMe.getAccount().getAvatar().getPath()) - .into(new CustomTarget() { - @Override - public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { - my_account.setIcon(resource); - } - @Override - public void onLoadCleared(@Nullable Drawable placeholder) { + .asDrawable() + .load(avatarUrl != null ? avatarUrl : R.drawable.missing_peertube) + .into(new CustomTarget() { + @Override + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { + my_account.setIcon(resource); + } - } - }); + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); } @@ -307,7 +312,6 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared } - //****** Video mode ******* ListPreference set_video_mode_choice = findPreference(getString(R.string.set_video_mode_choice)); List array = Arrays.asList(getResources().getStringArray(R.array.settings_video_mode)); @@ -349,7 +353,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared SwitchPreference set_video_minimize_choice = findPreference(getString(R.string.set_video_minimize_choice)); assert set_video_minimize_choice != null; set_video_minimize_choice.setChecked(minimized); - if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.O + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) { set_video_minimize_choice.setVisible(false); } @@ -422,8 +426,8 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared entryValuesSensitive[1] = Helper.BLUR.toLowerCase(); entryValuesSensitive[2] = Helper.DISPLAY.toLowerCase(); int currentSensitivePosition = 0; - for(CharSequence val : entryValuesSensitive) { - if(val.equals(currentSensitive)) { + for (CharSequence val : entryValuesSensitive) { + if (val.equals(currentSensitive)) { break; } currentSensitivePosition++; diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/CommentDecorationHelper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/CommentDecorationHelper.java index 9122b61..f308f7c 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/helper/CommentDecorationHelper.java +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/CommentDecorationHelper.java @@ -13,29 +13,30 @@ package app.fedilab.fedilabtube.helper; * * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ + import java.util.List; import app.fedilab.fedilabtube.client.data.CommentData; public class CommentDecorationHelper { - public static int getIndentation(String replyToCommentId, List comments){ + public static int getIndentation(String replyToCommentId, List comments) { return numberOfIndentation(0, replyToCommentId, comments); } private static int numberOfIndentation(int currentIdentation, String replyToCommentId, List comments) { String targetedComment = null; - for(CommentData.Comment comment: comments) { - if( replyToCommentId.compareTo(comment.getId()) == 0) { + for (CommentData.Comment comment : comments) { + if (replyToCommentId.compareTo(comment.getId()) == 0) { targetedComment = comment.getInReplyToCommentId(); break; } } - if ( targetedComment != null) { + if (targetedComment != null) { currentIdentation++; return numberOfIndentation(currentIdentation, targetedComment, comments); - }else{ + } else { return Math.min(currentIdentation, 5); } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java index 6b60653..491c68d 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java @@ -121,6 +121,7 @@ public class Helper { public static final String PREF_KEY_ID = "userID"; public static final String PREF_KEY_NAME = "my_user_name"; public static final String PREF_INSTANCE = "instance"; + public static final String PREF_INSTANCE_SURF = "instance_surf"; public static final int EXTERNAL_STORAGE_REQUEST_CODE = 84; public static final String SET_VIDEOS_PER_PAGE = "set_videos_per_page"; public static final String VIDEO_ID = "video_id_update"; @@ -478,12 +479,12 @@ public class Helper { RequestBuilder requestBuilder = Glide.with(imageView.getContext()) .load(url) .thumbnail(0.1f); - if( blur ) { - requestBuilder.apply(new RequestOptions().transform(new BlurTransformation(50, 3), new CenterCrop(), new RoundedCorners(10))); - }else { - requestBuilder.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(round))); - } - requestBuilder.into(imageView); + if (blur) { + requestBuilder.apply(new RequestOptions().transform(new BlurTransformation(50, 3), new CenterCrop(), new RoundedCorners(10))); + } else { + requestBuilder.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(round))); + } + requestBuilder.into(imageView); } catch (Exception e) { try { Glide.with(imageView.getContext()) @@ -626,6 +627,26 @@ public class Helper { } + /** + * Log out without removing user in db + * + * @param activity Activity + */ + public static void logoutNoRemoval(Activity activity) { + SharedPreferences sharedpreferences = activity.getSharedPreferences(APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(PREF_KEY_OAUTH_TOKEN, null); + editor.putString(CLIENT_ID, null); + editor.putString(CLIENT_SECRET, null); + editor.putString(PREF_KEY_ID, null); + editor.putString(ID, null); + editor.apply(); + Intent loginActivity = new Intent(activity, MainActivity.class); + activity.startActivity(loginActivity); + activity.finish(); + } + + public static int getAttColor(Context context, int attColor) { TypedValue typedValue = new TypedValue(); context.getTheme().resolveAttribute(attColor, typedValue, true); @@ -684,7 +705,7 @@ public class Helper { SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); String userName = sharedpreferences.getString(Helper.PREF_KEY_NAME, ""); String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, ""); - if( video == null) { + if (video == null) { return false; } Account account = video.getAccount(); @@ -726,8 +747,9 @@ public class Helper { /** * Forward the intent (open an URL) to another app + * * @param activity Activity - * @param i Intent + * @param i Intent */ public static void forwardToAnotherApp(Activity activity, Intent i) { Intent intent = new Intent(); diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/NotificationHelper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/NotificationHelper.java index 8c46d68..2b0d2e0 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/helper/NotificationHelper.java +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/NotificationHelper.java @@ -14,6 +14,7 @@ package app.fedilab.fedilabtube.helper; * * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ + import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/PlaylistExportHelper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/PlaylistExportHelper.java new file mode 100644 index 0000000..582ff14 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/PlaylistExportHelper.java @@ -0,0 +1,117 @@ +package app.fedilab.fedilabtube.helper; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.provider.OpenableColumns; + +import com.google.gson.Gson; + +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Scanner; + +import app.fedilab.fedilabtube.AllLocalPlaylistsActivity; +import app.fedilab.fedilabtube.client.data.VideoPlaylistData; +import app.fedilab.fedilabtube.sqlite.ManagePlaylistsDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; + +public class PlaylistExportHelper { + + + /** + * Unserialized VideoPlaylistExport + * + * @param serializedVideoPlaylistExport String serialized VideoPlaylistExport + * @return VideoPlaylistExport + */ + public static VideoPlaylistData.VideoPlaylistExport restorePlaylistFromString(String serializedVideoPlaylistExport) { + Gson gson = new Gson(); + try { + return gson.fromJson(serializedVideoPlaylistExport, VideoPlaylistData.VideoPlaylistExport.class); + } catch (Exception e) { + return null; + } + } + + /** + * Serialized VideoPlaylistExport class + * + * @param videoPlaylistExport Playlist to serialize + * @return String serialized VideoPlaylistData.VideoPlaylistExport + */ + public static String playlistToStringStorage(VideoPlaylistData.VideoPlaylistExport videoPlaylistExport) { + Gson gson = new Gson(); + try { + return gson.toJson(videoPlaylistExport); + } catch (Exception e) { + return null; + } + } + + /** + * Manage intent for opening a tubelab file allowing to import a whole playlist and store it in db + * + * @param activity Activity + * @param intent Intent + */ + public static void manageIntentUrl(Activity activity, Intent intent) { + if (intent.getData() != null) { + String url = intent.getData().toString(); + + String filename = url; + + if (url.startsWith("content://")) { + Cursor cursor = null; + try { + cursor = activity.getContentResolver().query(intent.getData(), null, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + } + } finally { + assert cursor != null; + cursor.close(); + } + } + String text = null; + if (filename.endsWith(".tubelab")) { + try { + InputStream inputStream = activity.getContentResolver().openInputStream(intent.getData()); + Scanner s = new Scanner(inputStream).useDelimiter("\\A"); + text = s.hasNext() ? s.next() : ""; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + if (text != null && text.length() > 20) { + String finalText = text; + new Thread(() -> { + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = PlaylistExportHelper.restorePlaylistFromString(finalText); + if (videoPlaylistExport != null) { + SQLiteDatabase db = Sqlite.getInstance(activity.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + new ManagePlaylistsDAO(activity, db).insertPlaylist(videoPlaylistExport); + } + activity.runOnUiThread(() -> { + Intent intentPlaylist = new Intent(activity, AllLocalPlaylistsActivity.class); + activity.startActivity(intentPlaylist); + }); + }).start(); + } + } + } + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/SwitchAccountHelper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/SwitchAccountHelper.java new file mode 100644 index 0000000..111be3b --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/SwitchAccountHelper.java @@ -0,0 +1,79 @@ +package app.fedilab.fedilabtube.helper; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; + +import androidx.appcompat.app.AlertDialog; + +import java.util.List; + +import app.fedilab.fedilabtube.LoginActivity; +import app.fedilab.fedilabtube.MainActivity; +import app.fedilab.fedilabtube.R; +import app.fedilab.fedilabtube.client.data.AccountData; +import app.fedilab.fedilabtube.drawer.OwnAccountsAdapter; +import app.fedilab.fedilabtube.sqlite.AccountDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; + +import static android.content.Context.MODE_PRIVATE; + +public class SwitchAccountHelper { + + + public static void switchDialog(Activity activity, boolean withAddAccount) { + SQLiteDatabase db = Sqlite.getInstance(activity.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + List accounts = new AccountDAO(activity, db).getAllAccount(); + + AlertDialog.Builder builderSingle = new AlertDialog.Builder(activity); + builderSingle.setTitle(activity.getString(R.string.list_of_accounts)); + if (accounts != null) { + final OwnAccountsAdapter accountsListAdapter = new OwnAccountsAdapter(activity, accounts); + final AccountData.Account[] accountArray = new AccountData.Account[accounts.size()]; + int i = 0; + for (AccountData.Account account : accounts) { + accountArray[i] = account; + i++; + } + builderSingle.setAdapter(accountsListAdapter, (dialog, which) -> { + final AccountData.Account account = accountArray[which]; + SharedPreferences sharedpreferences = activity.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, account.getToken()); + editor.putString(Helper.PREF_INSTANCE, account.getHost()); + editor.putString(Helper.PREF_KEY_ID, account.getId()); + editor.putString(Helper.PREF_KEY_NAME, account.getUsername()); + editor.apply(); + dialog.dismiss(); + Intent intent = new Intent(activity, MainActivity.class); + activity.startActivity(intent); + activity.finish(); + }); + } + builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); + if (withAddAccount) { + builderSingle.setPositiveButton(R.string.add_account, (dialog, which) -> { + Intent intent = new Intent(activity, LoginActivity.class); + activity.startActivity(intent); + activity.finish(); + }); + } + + builderSingle.show(); + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/services/RetrieveInfoService.java b/app/src/main/java/app/fedilab/fedilabtube/services/RetrieveInfoService.java index 00561c4..5d1f471 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/services/RetrieveInfoService.java +++ b/app/src/main/java/app/fedilab/fedilabtube/services/RetrieveInfoService.java @@ -127,7 +127,7 @@ public class RetrieveInfoService extends Service implements NetworkStateReceiver @Override public void run() { EmojiHelper.fillMapEmoji(getApplicationContext()); - if( peertubeInformation == null || peertubeInformation.getCategories().size() == 0) { + if (peertubeInformation == null || peertubeInformation.getCategories().size() == 0) { peertubeInformation = new PeertubeInformation(); peertubeInformation.setCategories(new LinkedHashMap<>()); peertubeInformation.setLanguages(new LinkedHashMap<>()); diff --git a/app/src/main/java/app/fedilab/fedilabtube/sqlite/AccountDAO.java b/app/src/main/java/app/fedilab/fedilabtube/sqlite/AccountDAO.java index 5ed353f..7c1a3c7 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/sqlite/AccountDAO.java +++ b/app/src/main/java/app/fedilab/fedilabtube/sqlite/AccountDAO.java @@ -252,7 +252,7 @@ public class AccountDAO { /** * Returns an Account by id and instance * - * @param id String + * @param id String * @param instance String * @return Account */ @@ -266,6 +266,7 @@ public class AccountDAO { return null; } } + /** * Test if the current user is already stored in data base * diff --git a/app/src/main/java/app/fedilab/fedilabtube/sqlite/ManagePlaylistsDAO.java b/app/src/main/java/app/fedilab/fedilabtube/sqlite/ManagePlaylistsDAO.java new file mode 100644 index 0000000..27605c4 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/sqlite/ManagePlaylistsDAO.java @@ -0,0 +1,377 @@ +package app.fedilab.fedilabtube.sqlite; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.fedilabtube.client.data.PlaylistData; +import app.fedilab.fedilabtube.client.data.VideoData; +import app.fedilab.fedilabtube.client.data.VideoPlaylistData; + + +@SuppressWarnings("UnusedReturnValue") +public class ManagePlaylistsDAO { + + private final SQLiteDatabase db; + public Context context; + + + public ManagePlaylistsDAO(Context context, SQLiteDatabase db) { + //Creation of the DB with tables + this.context = context; + this.db = db; + } + + /** + * Unserialized Video + * + * @param serializedVideo String serialized Video + * @return Video + */ + public static VideoData.Video restoreVideoFromString(String serializedVideo) { + Gson gson = new Gson(); + try { + return gson.fromJson(serializedVideo, VideoData.Video.class); + } catch (Exception e) { + return null; + } + } + + /** + * Serialized Video class + * + * @param video Video to serialize + * @return String serialized video + */ + public static String videoToStringStorage(VideoData.Video video) { + Gson gson = new Gson(); + try { + return gson.toJson(video); + } catch (Exception e) { + return null; + } + } + + + /** + * Unserialized Playlist + * + * @param serializedPlaylist String serialized Playlist + * @return Playlist + */ + public static PlaylistData.Playlist restorePlaylistFromString(String serializedPlaylist) { + Gson gson = new Gson(); + try { + return gson.fromJson(serializedPlaylist, PlaylistData.Playlist.class); + } catch (Exception e) { + return null; + } + } + + /** + * Serialized Playlist class + * + * @param playlist Playlist to serialize + * @return String serialized playlist + */ + public static String playlistToStringStorage(PlaylistData.Playlist playlist) { + Gson gson = new Gson(); + try { + return gson.toJson(playlist); + } catch (Exception e) { + return null; + } + } + + /** + * Insert playlist info in database + * + * @param videoPlaylistExport VideoPlaylistExport + * @return boolean + */ + public boolean insertPlaylist(VideoPlaylistData.VideoPlaylistExport videoPlaylistExport) { + + if (videoPlaylistExport.getPlaylist() == null) { + return true; + } + ContentValues values = new ContentValues(); + values.put(Sqlite.COL_ACCT, videoPlaylistExport.getAcct()); + values.put(Sqlite.COL_UUID, videoPlaylistExport.getUuid()); + values.put(Sqlite.COL_PLAYLIST, playlistToStringStorage(videoPlaylistExport.getPlaylist())); + //Inserts playlist + try { + long id = checkExists(videoPlaylistExport.getPlaylist().getUuid()); + if (id != -1) { + videoPlaylistExport.setPlaylistDBkey(id); + removeAllVideosInPlaylist(id); + + } else { + long playlist_id = db.insertOrThrow(Sqlite.TABLE_LOCAL_PLAYLISTS, null, values); + videoPlaylistExport.setPlaylistDBkey(playlist_id); + } + for (VideoPlaylistData.VideoPlaylist videoPlaylist : videoPlaylistExport.getVideos()) { + //Insert videos + insertVideos(videoPlaylist.getVideo(), videoPlaylistExport); + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + return true; + } + + /** + * Insert videos for playlists in database + * + * @param video Video to insert + * @param playlist VideoPlaylistExport targeted + * @return boolean + */ + private boolean insertVideos(VideoData.Video video, VideoPlaylistData.VideoPlaylistExport playlist) { + + if (video == null || playlist == null) { + return true; + } + ContentValues values = new ContentValues(); + values.put(Sqlite.COL_UUID, video.getUuid()); + values.put(Sqlite.COL_PLAYLIST_ID, playlist.getPlaylistDBkey()); + values.put(Sqlite.COL_VIDEO_DATA, videoToStringStorage(video)); + //Inserts playlist + try { + db.insertOrThrow(Sqlite.TABLE_VIDEOS, null, values); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Check if playlist exists + * + * @param uuid String + * @return int + */ + private long checkExists(String uuid) { + try { + Cursor c = db.query(Sqlite.TABLE_LOCAL_PLAYLISTS, null, Sqlite.COL_UUID + " = \"" + uuid + "\"", null, null, null, null, "1"); + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = cursorToSingleVideoPlaylistExport(c); + c.close(); + return videoPlaylistExport != null ? videoPlaylistExport.getPlaylistDBkey() : -1; + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + + } + + /** + * Check if playlist exists + * + * @param videoUuid String + * @param playlistUuid String + * @return int + */ + private boolean checkVideoExists(String videoUuid, String playlistUuid) { + try { + String check_query = "SELECT * FROM " + Sqlite.TABLE_LOCAL_PLAYLISTS + " p INNER JOIN " + + Sqlite.TABLE_VIDEOS + " v ON p.id = v." + Sqlite.COL_PLAYLIST_ID + + " WHERE p." + Sqlite.COL_UUID + "=? AND v." + Sqlite.COL_UUID + "=? LIMIT 1"; + Cursor c = db.rawQuery(check_query, new String[]{playlistUuid, videoUuid}); + int count = c.getCount(); + c.close(); + return count > 0; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + } + + /** + * Remove all videos in playlist + * + * @param playlistDBid long db id + * @return int + */ + public int removeAllVideosInPlaylist(long playlistDBid) { + return db.delete(Sqlite.TABLE_VIDEOS, Sqlite.COL_PLAYLIST_ID + " = '" + playlistDBid + "'", null); + } + + + /** + * Remove a playlist with its uuid + * + * @param uuid String uuid of the Playlist + * @return int + */ + public int removePlaylist(String uuid) { + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = getSinglePlaylists(uuid); + db.delete(Sqlite.TABLE_VIDEOS, Sqlite.COL_PLAYLIST_ID + " = '" + videoPlaylistExport.getPlaylistDBkey() + "'", null); + return db.delete(Sqlite.TABLE_LOCAL_PLAYLISTS, Sqlite.COL_ID + " = '" + videoPlaylistExport.getPlaylistDBkey() + "'", null); + } + + + /** + * Returns a playlist from it's uid in db + * + * @return VideoPlaylistExport + */ + public VideoPlaylistData.VideoPlaylistExport getSinglePlaylists(String uuid) { + + try { + Cursor c = db.query(Sqlite.TABLE_LOCAL_PLAYLISTS, null, Sqlite.COL_UUID + "='" + uuid + "'", null, null, null, Sqlite.COL_ID + " DESC", null); + return cursorToSingleVideoPlaylistExport(c); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * Returns all playlists in db + * + * @return List + */ + public List getAllPlaylists() { + + try { + Cursor c = db.query(Sqlite.TABLE_LOCAL_PLAYLISTS, null, null, null, null, null, Sqlite.COL_ID + " DESC", null); + return cursorToVideoPlaylistExport(c); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * Returns all videos in a playlist + * + * @return List + */ + public List getAllVideosInPlaylist(VideoPlaylistData.VideoPlaylistExport videoPlaylistExport) { + + try { + Cursor c = db.query(Sqlite.TABLE_VIDEOS, null, Sqlite.COL_PLAYLIST_ID + "='" + videoPlaylistExport.getPlaylistDBkey() + "'", null, null, null, Sqlite.COL_ID + " DESC", null); + return cursorToVideoExport(c); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * Returns all videos in a playlist + * + * @return List + */ + public List getAllVideosInPlaylist(String uuid) { + try { + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = getSinglePlaylists(uuid); + Cursor c = db.query(Sqlite.TABLE_VIDEOS, null, Sqlite.COL_PLAYLIST_ID + "='" + videoPlaylistExport.getPlaylistDBkey() + "'", null, null, null, Sqlite.COL_ID + " DESC", null); + return cursorToVideoExport(c); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /*** + * Method to hydrate VideoPlaylistExport from database + * @param c Cursor + * @return VideoPlaylistData.VideoPlaylistExport + */ + private VideoPlaylistData.VideoPlaylistExport cursorToSingleVideoPlaylistExport(Cursor c) { + //No element found + if (c.getCount() == 0) { + c.close(); + return null; + } + c.moveToFirst(); + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = new VideoPlaylistData.VideoPlaylistExport(); + videoPlaylistExport.setAcct(c.getString(c.getColumnIndex(Sqlite.COL_ACCT))); + videoPlaylistExport.setUuid(c.getString(c.getColumnIndex(Sqlite.COL_UUID))); + videoPlaylistExport.setPlaylistDBkey(c.getInt(c.getColumnIndex(Sqlite.COL_ID))); + videoPlaylistExport.setPlaylist(restorePlaylistFromString(c.getString(c.getColumnIndex(Sqlite.COL_PLAYLIST)))); + //Close the cursor + c.close(); + return videoPlaylistExport; + } + + + /*** + * Method to hydrate VideoPlaylistExport from database + * @param c Cursor + * @return List + */ + private List cursorToVideoPlaylistExport(Cursor c) { + //No element found + if (c.getCount() == 0) { + c.close(); + return null; + } + List videoPlaylistExports = new ArrayList<>(); + while (c.moveToNext()) { + VideoPlaylistData.VideoPlaylistExport videoPlaylistExport = new VideoPlaylistData.VideoPlaylistExport(); + videoPlaylistExport.setAcct(c.getString(c.getColumnIndex(Sqlite.COL_ACCT))); + videoPlaylistExport.setUuid(c.getString(c.getColumnIndex(Sqlite.COL_UUID))); + videoPlaylistExport.setPlaylistDBkey(c.getInt(c.getColumnIndex(Sqlite.COL_ID))); + videoPlaylistExport.setPlaylist(restorePlaylistFromString(c.getString(c.getColumnIndex(Sqlite.COL_PLAYLIST)))); + videoPlaylistExports.add(videoPlaylistExport); + } + //Close the cursor + c.close(); + return videoPlaylistExports; + } + + + /*** + * Method to hydrate Video from database + * @param c Cursor + * @return List + */ + private List cursorToVideoExport(Cursor c) { + //No element found + if (c.getCount() == 0) { + c.close(); + return null; + } + List videoExports = new ArrayList<>(); + while (c.moveToNext()) { + VideoData.VideoExport videoExport = new VideoData.VideoExport(); + videoExport.setPlaylistDBid(c.getInt(c.getColumnIndex(Sqlite.COL_PLAYLIST_ID))); + videoExport.setUuid(c.getString(c.getColumnIndex(Sqlite.COL_UUID))); + videoExport.setId(c.getInt(c.getColumnIndex(Sqlite.COL_ID))); + videoExport.setVideoData(restoreVideoFromString(c.getString(c.getColumnIndex(Sqlite.COL_VIDEO_DATA)))); + videoExports.add(videoExport); + } + //Close the cursor + c.close(); + return videoExports; + } + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/sqlite/Sqlite.java b/app/src/main/java/app/fedilab/fedilabtube/sqlite/Sqlite.java index eff33b5..5503449 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/sqlite/Sqlite.java +++ b/app/src/main/java/app/fedilab/fedilabtube/sqlite/Sqlite.java @@ -21,7 +21,7 @@ import android.database.sqlite.SQLiteOpenHelper; public class Sqlite extends SQLiteOpenHelper { - public static final int DB_VERSION = 1; + public static final int DB_VERSION = 3; public static final String DB_NAME = "mastodon_etalab_db"; /*** * List of tables to manage users and data @@ -59,6 +59,14 @@ public class Sqlite extends SQLiteOpenHelper { static final String COL_UUID = "UUID"; static final String COL_CACHE = "CACHE"; static final String COL_DATE = "DATE"; + static final String COL_USER_INSTANCE = "USER_INSTANCE"; + static final String TABLE_BOOKMARKED_INSTANCES = "BOOKMARKED_INSTANCES"; + static final String COL_ABOUT = "ABOUT"; + static final String TABLE_LOCAL_PLAYLISTS = "LOCAL_PLAYLISTS"; + static final String COL_PLAYLIST = "PLAYLIST"; + static final String TABLE_VIDEOS = "VIDEOS"; + static final String COL_VIDEO_DATA = "VIDEO_DATA"; + static final String COL_PLAYLIST_ID = "PLAYLIST_ID"; private static final String CREATE_TABLE_USER_ACCOUNT = "CREATE TABLE " + TABLE_USER_ACCOUNT + " (" + COL_USER_ID + " TEXT, " + COL_USERNAME + " TEXT NOT NULL, " + COL_ACCT + " TEXT NOT NULL, " + COL_DISPLAYED_NAME + " TEXT NOT NULL, " + COL_LOCKED + " INTEGER NOT NULL, " @@ -82,7 +90,26 @@ public class Sqlite extends SQLiteOpenHelper { + COL_INSTANCE + " TEXT NOT NULL, " + COL_CACHE + " TEXT NOT NULL, " + COL_DATE + " TEXT NOT NULL)"; - + private final String CREATE_TABLE_STORED_INSTANCES = "CREATE TABLE " + + TABLE_BOOKMARKED_INSTANCES + "(" + + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + COL_INSTANCE + " TEXT NOT NULL, " + + COL_USER_ID + " TEXT NOT NULL, " + + COL_ABOUT + " TEXT NOT NULL, " + + COL_USER_INSTANCE + " TEXT NOT NULL)"; + private final String CREATE_TABLE_LOCAL_PLAYLISTS = "CREATE TABLE " + + TABLE_LOCAL_PLAYLISTS + "(" + + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + COL_ACCT + " TEXT NOT NULL, " + + COL_UUID + " TEXT NOT NULL, " + + COL_PLAYLIST + " TEXT NOT NULL)"; + private final String CREATE_TABLE_VIDEOS = "CREATE TABLE " + + TABLE_VIDEOS + "(" + + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + COL_UUID + " TEXT NOT NULL, " + + COL_VIDEO_DATA + " TEXT NOT NULL, " + + COL_PLAYLIST_ID + " INTEGER, " + + " FOREIGN KEY (" + COL_PLAYLIST_ID + ") REFERENCES " + COL_PLAYLIST + "(" + COL_ID + "));"; public Sqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); @@ -101,17 +128,31 @@ public class Sqlite extends SQLiteOpenHelper { public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_TABLE_USER_ACCOUNT); db.execSQL(CREATE_TABLE_PEERTUBE_FAVOURITES); + db.execSQL(CREATE_TABLE_STORED_INSTANCES); + db.execSQL(CREATE_TABLE_LOCAL_PLAYLISTS); + db.execSQL(CREATE_TABLE_VIDEOS); } @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + switch (oldVersion) { + case 3: + db.execSQL("DROP TABLE IF EXISTS " + TABLE_VIDEOS); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_LOCAL_PLAYLISTS); + case 2: + db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKED_INSTANCES); + } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { case 1: + db.execSQL(CREATE_TABLE_STORED_INSTANCES); + case 2: + db.execSQL(CREATE_TABLE_LOCAL_PLAYLISTS); + db.execSQL(CREATE_TABLE_VIDEOS); } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/sqlite/StoredInstanceDAO.java b/app/src/main/java/app/fedilab/fedilabtube/sqlite/StoredInstanceDAO.java new file mode 100644 index 0000000..aea97a1 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/sqlite/StoredInstanceDAO.java @@ -0,0 +1,216 @@ +package app.fedilab.fedilabtube.sqlite; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.content.ContentValues; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.fedilabtube.client.data.InstanceData; +import app.fedilab.fedilabtube.helper.Helper; + + +@SuppressWarnings("UnusedReturnValue") +public class StoredInstanceDAO { + + private final SQLiteDatabase db; + public Context context; + + + public StoredInstanceDAO(Context context, SQLiteDatabase db) { + //Creation of the DB with tables + this.context = context; + this.db = db; + } + + /** + * Unserialized AboutInstance + * + * @param serializedAboutInstance String serialized AboutInstance + * @return AboutInstance + */ + public static InstanceData.AboutInstance restoreAboutInstanceFromString(String serializedAboutInstance) { + Gson gson = new Gson(); + try { + return gson.fromJson(serializedAboutInstance, InstanceData.AboutInstance.class); + } catch (Exception e) { + return null; + } + } + + /** + * Serialized AboutInstance class + * + * @param aboutInstance AboutInstance to serialize + * @return String serialized AboutInstance + */ + public static String aboutInstanceToStringStorage(InstanceData.AboutInstance aboutInstance) { + Gson gson = new Gson(); + try { + return gson.toJson(aboutInstance); + } catch (Exception e) { + return null; + } + } + + /** + * Insert instance info in database + * + * @param aboutInstance AboutInstance + * @param targetedInstance String + * @return boolean + */ + public boolean insertInstance(InstanceData.AboutInstance aboutInstance, String targetedInstance) { + + if (checkExists(targetedInstance)) { + return true; + } + ContentValues values = new ContentValues(); + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + String instance = Helper.getLiveInstance(context); + + values.put(Sqlite.COL_USER_ID, userId != null ? userId : "_ALL_"); + values.put(Sqlite.COL_USER_INSTANCE, instance != null ? instance : "_ALL_"); + values.put(Sqlite.COL_ABOUT, aboutInstanceToStringStorage(aboutInstance)); + values.put(Sqlite.COL_INSTANCE, targetedInstance); + //Inserts instance + try { + db.insertOrThrow(Sqlite.TABLE_BOOKMARKED_INSTANCES, null, values); + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Check if instance exists + * + * @param targetedInstance String + * @return int + */ + private boolean checkExists(String targetedInstance) { + try { + Cursor c = db.query(Sqlite.TABLE_BOOKMARKED_INSTANCES, null, Sqlite.COL_INSTANCE + " = \"" + targetedInstance + "\"", null, null, null, null, "1"); + return cursorToInstance(c) != null; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + } + + /** + * Insert instance info in database + * + * @param aboutInstance AboutInstance + * @param targetedInstance String + * @return int + */ + @SuppressWarnings({"unused", "RedundantSuppression"}) + public int updateInstance(InstanceData.AboutInstance aboutInstance, String targetedInstance) { + ContentValues values = new ContentValues(); + values.put(Sqlite.COL_ABOUT, aboutInstanceToStringStorage(aboutInstance)); + try { + return db.update(Sqlite.TABLE_BOOKMARKED_INSTANCES, + values, Sqlite.COL_INSTANCE + " = ?", + new String[]{targetedInstance}); + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + + } + + + public int removeInstance(String instance) { + return db.delete(Sqlite.TABLE_BOOKMARKED_INSTANCES, Sqlite.COL_INSTANCE + " = '" + instance + "'", null); + } + + + /** + * Returns all Instance in db + * + * @return List + */ + public List getAllInstances() { + + try { + Cursor c = db.query(Sqlite.TABLE_BOOKMARKED_INSTANCES, null, null, null, null, null, Sqlite.COL_INSTANCE + " ASC", null); + return cursorToListInstances(c); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /*** + * Method to hydrate an AboutInstance from database + * @param c Cursor + * @return AboutInstance + */ + private InstanceData.AboutInstance cursorToInstance(Cursor c) { + //No element found + if (c.getCount() == 0) { + c.close(); + return null; + } + //Take the first element + c.moveToFirst(); + //New user + String aboutInstanceStr = c.getString(c.getColumnIndex(Sqlite.COL_ABOUT)); + InstanceData.AboutInstance aboutInstance = restoreAboutInstanceFromString(aboutInstanceStr); + //Close the cursor + c.close(); + return aboutInstance; + } + + + /*** + * Method to hydrate an AboutInstance from database + * @param c Cursor + * @return List + */ + private List cursorToListInstances(Cursor c) { + //No element found + if (c.getCount() == 0) { + c.close(); + return null; + } + List aboutInstances = new ArrayList<>(); + while (c.moveToNext()) { + String aboutInstanceStr = c.getString(c.getColumnIndex(Sqlite.COL_ABOUT)); + String instance = c.getString(c.getColumnIndex(Sqlite.COL_INSTANCE)); + InstanceData.AboutInstance aboutInstance = restoreAboutInstanceFromString(aboutInstanceStr); + aboutInstance.setHost(instance); + aboutInstances.add(aboutInstance); + } + //Close the cursor + c.close(); + return aboutInstances; + } + + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/InfoInstanceVM.java b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/InfoInstanceVM.java new file mode 100644 index 0000000..a6e5185 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/InfoInstanceVM.java @@ -0,0 +1,64 @@ +package app.fedilab.fedilabtube.viewmodel; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of TubeLab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with TubeLab; if not, + * see . */ + +import android.app.Application; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.os.Handler; +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import java.util.List; + +import app.fedilab.fedilabtube.client.data.InstanceData; +import app.fedilab.fedilabtube.sqlite.Sqlite; +import app.fedilab.fedilabtube.sqlite.StoredInstanceDAO; + + +public class InfoInstanceVM extends AndroidViewModel { + private MutableLiveData> aboutInstanceMutableLiveData; + + public InfoInstanceVM(@NonNull Application application) { + super(application); + } + + public LiveData> getInstances() { + aboutInstanceMutableLiveData = new MutableLiveData<>(); + loadInstances(); + return aboutInstanceMutableLiveData; + } + + + private void loadInstances() { + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + SQLiteDatabase db = Sqlite.getInstance(_mContext.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + List instances = new StoredInstanceDAO(_mContext, db).getAllInstances(); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> aboutInstanceMutableLiveData.setValue(instances); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/PlaylistsVM.java b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/PlaylistsVM.java index 78739d9..9675907 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/PlaylistsVM.java +++ b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/PlaylistsVM.java @@ -33,13 +33,16 @@ import app.fedilab.fedilabtube.client.APIResponse; import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; import app.fedilab.fedilabtube.client.data.AccountData.Account; import app.fedilab.fedilabtube.client.data.PlaylistData.Playlist; +import app.fedilab.fedilabtube.client.data.VideoPlaylistData; import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.sqlite.AccountDAO; +import app.fedilab.fedilabtube.sqlite.ManagePlaylistsDAO; import app.fedilab.fedilabtube.sqlite.Sqlite; public class PlaylistsVM extends AndroidViewModel { private MutableLiveData apiResponseMutableLiveData; + private MutableLiveData> videoPlaylistExportMutableLiveData; public PlaylistsVM(@NonNull Application application) { super(application); @@ -51,6 +54,13 @@ public class PlaylistsVM extends AndroidViewModel { return apiResponseMutableLiveData; } + public LiveData> localePlaylist() { + videoPlaylistExportMutableLiveData = new MutableLiveData<>(); + loadLocalePlaylist(); + return videoPlaylistExportMutableLiveData; + } + + public LiveData videoExists(List videoIds) { apiResponseMutableLiveData = new MutableLiveData<>(); checkVideosExist(videoIds); @@ -67,6 +77,22 @@ public class PlaylistsVM extends AndroidViewModel { }).start(); } + + private void loadLocalePlaylist() { + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + SQLiteDatabase db = Sqlite.getInstance(_mContext.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + List videoPlaylistExports = new ManagePlaylistsDAO(_mContext, db).getAllPlaylists(); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> videoPlaylistExportMutableLiveData.setValue(videoPlaylistExports); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + private void managePlaylists(action apiAction, Playlist playlist, String videoId) { Context _mContext = getApplication().getApplicationContext(); new Thread(() -> { diff --git a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/TimelineVM.java b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/TimelineVM.java index b50df63..1606d66 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/TimelineVM.java +++ b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/TimelineVM.java @@ -16,6 +16,7 @@ package app.fedilab.fedilabtube.viewmodel; import android.app.Application; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.os.Handler; import android.os.Looper; @@ -24,9 +25,15 @@ import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import java.util.ArrayList; +import java.util.List; + import app.fedilab.fedilabtube.client.APIResponse; import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; +import app.fedilab.fedilabtube.client.data.VideoData; import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.sqlite.ManagePlaylistsDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; import static app.fedilab.fedilabtube.viewmodel.PlaylistsVM.action.GET_LIST_VIDEOS; @@ -51,6 +58,18 @@ public class TimelineVM extends AndroidViewModel { } + public LiveData getVideoHistory(String max_id, String startDate, String endDate) { + apiResponseMutableLiveData = new MutableLiveData<>(); + loadHistory(max_id, startDate, endDate); + return apiResponseMutableLiveData; + } + + public LiveData deleterHistory() { + apiResponseMutableLiveData = new MutableLiveData<>(); + deleteHistory(); + return apiResponseMutableLiveData; + } + public LiveData getVideo(String instance, String videoId, boolean isMyVideo) { apiResponseMutableLiveData = new MutableLiveData<>(); getSingle(instance, videoId, isMyVideo); @@ -63,6 +82,12 @@ public class TimelineVM extends AndroidViewModel { return apiResponseMutableLiveData; } + public LiveData loadVideosInLocalPlaylist(String playlistUuid) { + apiResponseMutableLiveData = new MutableLiveData<>(); + loadVideosInLocalPlayList(playlistUuid); + return apiResponseMutableLiveData; + } + public LiveData getMyVideo(String instance, String videoId) { apiResponseMutableLiveData = new MutableLiveData<>(); getSingle(instance, videoId, true); @@ -138,6 +163,27 @@ public class TimelineVM extends AndroidViewModel { }).start(); } + private void loadVideosInLocalPlayList(String playlistUuid) { + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + SQLiteDatabase db = Sqlite.getInstance(_mContext.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + List videoExports = new ManagePlaylistsDAO(_mContext, db).getAllVideosInPlaylist(playlistUuid); + APIResponse apiResponse = new APIResponse(); + List videos = new ArrayList<>(); + for (VideoData.VideoExport videoExport : videoExports) { + videos.add(videoExport.getVideoData()); + } + apiResponse.setPeertubes(videos); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> apiResponseMutableLiveData.setValue(apiResponse); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + private void loadVideos(TimelineType timeline, String max_id, String forAccount) { Context _mContext = getApplication().getApplicationContext(); new Thread(() -> { @@ -156,6 +202,38 @@ public class TimelineVM extends AndroidViewModel { }).start(); } + private void loadHistory(String max_id, String startDate, String endDate) { + + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + RetrofitPeertubeAPI retrofitPeertubeAPI = new RetrofitPeertubeAPI(_mContext); + APIResponse apiResponse = retrofitPeertubeAPI.getHistory(max_id, startDate, endDate); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> apiResponseMutableLiveData.setValue(apiResponse); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + + private void deleteHistory() { + + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + RetrofitPeertubeAPI retrofitPeertubeAPI = new RetrofitPeertubeAPI(_mContext); + APIResponse apiResponse = retrofitPeertubeAPI.deleteHistory(); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> apiResponseMutableLiveData.setValue(apiResponse); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + private void loadOverviewVideos(String page) { Context _mContext = getApplication().getApplicationContext(); @@ -184,6 +262,7 @@ public class TimelineVM extends AndroidViewModel { HISTORY, RECENT, VIDEOS_IN_PLAYLIST, + VIDEOS_IN_LOCAL_PLAYLIST, SEPIA_SEARCH } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/webview/MastalabWebChromeClient.java b/app/src/main/java/app/fedilab/fedilabtube/webview/MastalabWebChromeClient.java index a22fd25..35a37b6 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/webview/MastalabWebChromeClient.java +++ b/app/src/main/java/app/fedilab/fedilabtube/webview/MastalabWebChromeClient.java @@ -37,17 +37,15 @@ import app.fedilab.fedilabtube.R; public class MastalabWebChromeClient extends WebChromeClient implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener { - private FrameLayout videoViewContainer; - private CustomViewCallback videoViewCallback; - - private ToggledFullscreenCallback toggledFullscreenCallback; - private final CustomWebview webView; private final View activityNonVideoView; private final ViewGroup activityVideoView; private final ProgressBar pbar; - private boolean isVideoFullscreen; private final Activity activity; + private FrameLayout videoViewContainer; + private CustomViewCallback videoViewCallback; + private ToggledFullscreenCallback toggledFullscreenCallback; + private boolean isVideoFullscreen; public MastalabWebChromeClient(Activity activity, CustomWebview webView, FrameLayout activityNonVideoView, ViewGroup activityVideoView) { @@ -113,7 +111,6 @@ public class MastalabWebChromeClient extends WebChromeClient implements MediaPla public void onShowCustomView(View view, CustomViewCallback callback) { if (view instanceof FrameLayout) { if (((AppCompatActivity) activity).getSupportActionBar() != null) - //noinspection ConstantConditions ((AppCompatActivity) activity).getSupportActionBar().hide(); // A video wants to be shown FrameLayout frameLayout = (FrameLayout) view; @@ -178,7 +175,6 @@ public class MastalabWebChromeClient extends WebChromeClient implements MediaPla @Override public void onHideCustomView() { if (((AppCompatActivity) activity).getSupportActionBar() != null) - //noinspection ConstantConditions ((AppCompatActivity) activity).getSupportActionBar().show(); // This method should be manually called on video end in all cases because it's not always called automatically. // This method must be manually called on back key press (from this class' onBackPressed() method). diff --git a/app/src/main/java/app/fedilab/fedilabtube/worker/NotificationsWorker.java b/app/src/main/java/app/fedilab/fedilabtube/worker/NotificationsWorker.java index b0c0095..96a1841 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/worker/NotificationsWorker.java +++ b/app/src/main/java/app/fedilab/fedilabtube/worker/NotificationsWorker.java @@ -61,9 +61,9 @@ import static android.content.Context.NOTIFICATION_SERVICE; public class NotificationsWorker extends Worker { - private final NotificationManager notificationManager; public static String FETCH_NOTIFICATION_CHANNEL_ID = "fetch_notification_peertube"; public static int pendingNotificationID = 1; + private final NotificationManager notificationManager; public NotificationsWorker( @NonNull Context context, @@ -80,7 +80,7 @@ public class NotificationsWorker extends Worker { Context applicationContext = getApplicationContext(); SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); List accounts = new AccountDAO(applicationContext, db).getAllAccount(); - if( accounts == null || accounts.size() == 0) { + if (accounts == null || accounts.size() == 0) { return Result.success(); } setForegroundAsync(createForegroundInfo()); @@ -95,28 +95,28 @@ public class NotificationsWorker extends Worker { List accounts = new AccountDAO(getApplicationContext(), db).getAllAccount(); SharedPreferences sharedpreferences = getApplicationContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedpreferences.edit(); - for(AccountData.Account account: accounts) { + for (AccountData.Account account : accounts) { RetrofitPeertubeAPI retrofitPeertubeAPI = new RetrofitPeertubeAPI(getApplicationContext(), account.getHost(), account.getToken()); APIResponse apiResponse = retrofitPeertubeAPI.getNotifications(); - if( apiResponse == null) { + if (apiResponse == null) { return; } try { UserMe userMe = retrofitPeertubeAPI.verifyCredentials(); - if( userMe != null) { + if (userMe != null) { List notifications = apiResponse.getPeertubeNotifications(); NotificationSettings notificationSettings = userMe.getNotificationSettings(); - if( apiResponse.getPeertubeNotifications() != null && apiResponse.getPeertubeNotifications().size() > 0 ) { + if (apiResponse.getPeertubeNotifications() != null && apiResponse.getPeertubeNotifications().size() > 0) { String last_read = sharedpreferences.getString(Helper.LAST_NOTIFICATION_READ + account.getId() + account.getHost(), null); editor.putString(Helper.LAST_NOTIFICATION_READ + account.getId() + account.getHost(), apiResponse.getPeertubeNotifications().get(0).getId()); editor.apply(); - if( last_read != null) { - for(NotificationData.Notification notification: notifications) { + if (last_read != null) { + for (NotificationData.Notification notification : notifications) { String title = ""; String message = ""; FutureTarget futureBitmap = Glide.with(getApplicationContext()) .asBitmap() - .load("https://"+account.getHost()+account.getAvatar()).submit(); + .load("https://" + account.getHost() + account.getAvatar()).submit(); Bitmap icon; try { icon = futureBitmap.get(); @@ -126,14 +126,14 @@ public class NotificationsWorker extends Worker { } Intent intent = null; - if(notification.getId().compareTo(last_read) > 0) { + if (notification.getId().compareTo(last_read) > 0) { switch (notification.getType()) { case DisplayNotificationsFragment.NEW_VIDEO_FROM_SUBSCRIPTION: - if(notificationSettings.getNewVideoFromSubscription() == 1 || notificationSettings.getNewVideoFromSubscription() == 3) { - if( notification.getVideo().getChannel().getAvatar() != null ) { + if (notificationSettings.getNewVideoFromSubscription() == 1 || notificationSettings.getNewVideoFromSubscription() == 3) { + if (notification.getVideo().getChannel().getAvatar() != null) { FutureTarget futureBitmapChannel = Glide.with(getApplicationContext()) .asBitmap() - .load("https://"+account.getHost()+notification.getVideo().getChannel().getAvatar().getPath()).submit(); + .load("https://" + account.getHost() + notification.getVideo().getChannel().getAvatar().getPath()).submit(); try { icon = futureBitmapChannel.get(); } catch (Exception e) { @@ -141,7 +141,7 @@ public class NotificationsWorker extends Worker { R.drawable.missing_peertube); } - }else{ + } else { icon = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.missing_peertube); } @@ -158,11 +158,11 @@ public class NotificationsWorker extends Worker { } break; case DisplayNotificationsFragment.NEW_COMMENT_ON_MY_VIDEO: - if(notificationSettings.getNewCommentOnMyVideo() == 1 || notificationSettings.getNewCommentOnMyVideo() == 3) { - if( notification.getComment().getAccount().getAvatar() != null ) { + if (notificationSettings.getNewCommentOnMyVideo() == 1 || notificationSettings.getNewCommentOnMyVideo() == 3) { + if (notification.getComment().getAccount().getAvatar() != null) { FutureTarget futureBitmapChannel = Glide.with(getApplicationContext()) .asBitmap() - .load("https://"+account.getHost()+ notification.getComment().getAccount().getAvatar().getPath()).submit(); + .load("https://" + account.getHost() + notification.getComment().getAccount().getAvatar().getPath()).submit(); try { icon = futureBitmapChannel.get(); } catch (Exception e) { @@ -170,7 +170,7 @@ public class NotificationsWorker extends Worker { R.drawable.missing_peertube); } - }else{ + } else { icon = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.missing_peertube); } @@ -191,31 +191,31 @@ public class NotificationsWorker extends Worker { break; case DisplayNotificationsFragment.BLACKLIST_ON_MY_VIDEO: - if(notificationSettings.getBlacklistOnMyVideo() == 1 || notificationSettings.getBlacklistOnMyVideo() == 3) { + if (notificationSettings.getBlacklistOnMyVideo() == 1 || notificationSettings.getBlacklistOnMyVideo() == 3) { title = getApplicationContext().getString(R.string.new_blacklist); message = getApplicationContext().getString(R.string.peertube_video_blacklist, notification.getVideo().getName()); } break; case DisplayNotificationsFragment.UNBLACKLIST_ON_MY_VIDEO: - if(notificationSettings.getBlacklistOnMyVideo() == 1 || notificationSettings.getBlacklistOnMyVideo() == 3) { + if (notificationSettings.getBlacklistOnMyVideo() == 1 || notificationSettings.getBlacklistOnMyVideo() == 3) { title = getApplicationContext().getString(R.string.new_blacklist); message = getApplicationContext().getString(R.string.peertube_video_unblacklist, notification.getVideo().getName()); } break; case DisplayNotificationsFragment.MY_VIDEO_PUBLISHED: - if(notificationSettings.getMyVideoPublished() == 1 || notificationSettings.getMyVideoPublished() == 3) { + if (notificationSettings.getMyVideoPublished() == 1 || notificationSettings.getMyVideoPublished() == 3) { title = getApplicationContext().getString(R.string.new_my_video_published); message = getApplicationContext().getString(R.string.peertube_video_published, notification.getVideo().getName()); } break; case DisplayNotificationsFragment.MY_VIDEO_IMPORT_SUCCESS: - if(notificationSettings.getMyVideoPublished() == 1 || notificationSettings.getMyVideoPublished() == 3) { + if (notificationSettings.getMyVideoPublished() == 1 || notificationSettings.getMyVideoPublished() == 3) { message = getApplicationContext().getString(R.string.peertube_video_import_success, notification.getVideo().getName()); title = getApplicationContext().getString(R.string.new_my_video_error); } break; case DisplayNotificationsFragment.MY_VIDEO_IMPORT_ERROR: - if(notificationSettings.getMyVideoPublished() == 1 || notificationSettings.getMyVideoPublished() == 3) { + if (notificationSettings.getMyVideoPublished() == 1 || notificationSettings.getMyVideoPublished() == 3) { message = getApplicationContext().getString(R.string.peertube_video_import_error, notification.getVideo().getName()); title = getApplicationContext().getString(R.string.new_my_video_error); } @@ -224,14 +224,14 @@ public class NotificationsWorker extends Worker { break; case DisplayNotificationsFragment.NEW_FOLLOW: - if(notificationSettings.getNewFollow() == 1 || notificationSettings.getNewFollow() == 3) { - if( notification.getVideo().getChannel().getAvatar() != null ) { + if (notificationSettings.getNewFollow() == 1 || notificationSettings.getNewFollow() == 3) { + if (notification.getVideo().getChannel().getAvatar() != null) { FutureTarget futureBitmapChannel = Glide.with(getApplicationContext()) .asBitmap() - .load("https://"+account.getHost()+notification.getVideo().getChannel().getAvatar().getPath()).submit(); + .load("https://" + account.getHost() + notification.getVideo().getChannel().getAvatar().getPath()).submit(); icon = futureBitmapChannel.get(); - }else{ + } else { icon = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.missing_peertube); } @@ -250,7 +250,7 @@ public class NotificationsWorker extends Worker { accountAction.setHost(actor.getHost()); accountAction.setUsername(actor.getName()); intent = new Intent(getApplicationContext(), ShowAccountActivity.class); - b.putParcelable("account", accountAction); + b.putParcelable("account", accountAction); b.putString("accountAcct", accountAction.getUsername() + "@" + accountAction.getHost()); intent.putExtras(b); } @@ -274,14 +274,14 @@ public class NotificationsWorker extends Worker { break; } - if( message != null && icon != null && title != null) { + if (message != null && icon != null && title != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) message = Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY).toString(); else message = Html.fromHtml(message).toString(); NotificationHelper.notify_user(getApplicationContext(), account, intent, icon, title, message); } - }else { + } else { break; } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/worker/WorkHelper.java b/app/src/main/java/app/fedilab/fedilabtube/worker/WorkHelper.java index 1d5b2f9..93b3d8a 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/worker/WorkHelper.java +++ b/app/src/main/java/app/fedilab/fedilabtube/worker/WorkHelper.java @@ -13,7 +13,9 @@ package app.fedilab.fedilabtube.worker; * * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ + import android.app.Application; + import androidx.work.BackoffPolicy; import androidx.work.Constraints; import androidx.work.ExistingPeriodicWorkPolicy; diff --git a/app/src/main/res/anim/slide_in_up.xml b/app/src/main/res/anim/slide_in_up.xml new file mode 100644 index 0000000..e54c8ca --- /dev/null +++ b/app/src/main/res/anim/slide_in_up.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_up_down.xml b/app/src/main/res/anim/slide_in_up_down.xml new file mode 100644 index 0000000..40e7688 --- /dev/null +++ b/app/src/main/res/anim/slide_in_up_down.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_up.xml b/app/src/main/res/anim/slide_out_up.xml new file mode 100644 index 0000000..9bd4cfa --- /dev/null +++ b/app/src/main/res/anim/slide_out_up.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_rounded_item.xml b/app/src/main/res/drawable/background_rounded_item.xml new file mode 100644 index 0000000..2ea72dd --- /dev/null +++ b/app/src/main/res/drawable/background_rounded_item.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_baseline_close_24.xml b/app/src/main/res/drawable/ic_baseline_close_24.xml new file mode 100644 index 0000000..7202749 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_close_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_import_export_24.xml b/app/src/main/res/drawable/ic_baseline_import_export_24.xml new file mode 100644 index 0000000..2418755 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_import_export_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_public_24.xml b/app/src/main/res/drawable/ic_baseline_public_24.xml index 2c9d4e3..19fb425 100644 --- a/app/src/main/res/drawable/ic_baseline_public_24.xml +++ b/app/src/main/res/drawable/ic_baseline_public_24.xml @@ -1,10 +1,10 @@ - + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml index 1b2c595..164c08f 100644 --- a/app/src/main/res/layout/activity_account.xml +++ b/app/src/main/res/layout/activity_account.xml @@ -61,13 +61,28 @@ + + - - + app:layout_constraintTop_toTopOf="parent"> - - + - - + + - + - - + + - +