From 256a1d84aef10564ed9bc9431326a1622bb78849 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 12 Dec 2020 18:40:15 -0500 Subject: [PATCH 001/101] New Crowdin updates (#368) * New translations strings.xml (French) * New translations arrays.xml (German) * New translations strings.xml (German) * New translations arrays.xml (Catalan) * New translations strings.xml (Catalan) * New translations arrays.xml (Portuguese, Brazilian) * New translations arrays.xml (Portuguese, Brazilian) * New translations arrays.xml (Russian) * New translations strings.xml (Russian) * New translations arrays.xml (Spanish) * New translations strings.xml (Spanish) * Update source file strings.xml * New translations strings.xml (Polish) * New translations strings.xml (Catalan) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (French) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Turkish) * New translations strings.xml (Czech) * New translations strings.xml (Spanish) * New translations strings.xml (Macedonian) * New translations strings.xml (Russian) * New translations strings.xml (Italian) * New translations strings.xml (German) * New translations strings.xml (Hindi) * New translations strings.xml (Odia) * New translations strings.xml (Persian) * New translations strings.xml (Indonesian) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Vietnamese) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Russian) * New translations strings.xml (Italian) * New translations arrays.xml (Indonesian) * New translations arrays.xml (Polish) * New translations strings.xml (Polish) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (German) * New translations strings.xml (German) * New translations strings.xml (German) * New translations arrays.xml (Odia) * New translations strings.xml (Odia) * New translations strings.xml (Odia) * New translations strings.xml (Odia) * New translations strings.xml (Odia) * New translations arrays.xml (Dutch) * New translations strings.xml (Dutch) * New translations strings.xml (Catalan) * New translations arrays.xml (Dutch) * New translations arrays.xml (Dutch) * New translations strings.xml (Dutch) * New translations strings.xml (Dutch) * New translations strings.xml (Spanish) * New translations strings.xml (Dutch) * New translations strings.xml (Dutch) * New translations strings.xml (Dutch) * New translations strings.xml (Dutch) * New translations arrays.xml (Kannada) * New translations strings.xml (Kannada) * New translations arrays.xml (Turkish) * New translations strings.xml (Turkish) * New translations strings.xml (Turkish) * New translations arrays.xml (Vietnamese) * New translations strings.xml (Vietnamese) --- app/src/main/res/values-ca/arrays.xml | 4 +- app/src/main/res/values-ca/strings.xml | 5 +- app/src/main/res/values-cs/strings.xml | 1 + app/src/main/res/values-de/arrays.xml | 4 +- app/src/main/res/values-de/strings.xml | 67 ++--- app/src/main/res/values-es/arrays.xml | 4 +- app/src/main/res/values-es/strings.xml | 3 +- app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 3 +- app/src/main/res/values-hi/strings.xml | 1 + app/src/main/res/values-in/arrays.xml | 4 +- app/src/main/res/values-in/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-kn/arrays.xml | 133 +++++++++ app/src/main/res/values-kn/strings.xml | 308 +++++++++++++++++++++ app/src/main/res/values-mk/strings.xml | 1 + app/src/main/res/values-nl/arrays.xml | 133 +++++++++ app/src/main/res/values-nl/strings.xml | 308 +++++++++++++++++++++ app/src/main/res/values-or/arrays.xml | 4 +- app/src/main/res/values-or/strings.xml | 17 +- app/src/main/res/values-pl/arrays.xml | 4 +- app/src/main/res/values-pl/strings.xml | 5 +- app/src/main/res/values-pt/arrays.xml | 4 +- app/src/main/res/values-pt/strings.xml | 3 +- app/src/main/res/values-ru/arrays.xml | 4 +- app/src/main/res/values-ru/strings.xml | 3 +- app/src/main/res/values-tr/arrays.xml | 6 +- app/src/main/res/values-tr/strings.xml | 65 ++--- app/src/main/res/values-vi/arrays.xml | 6 +- app/src/main/res/values-vi/strings.xml | 3 +- app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + 32 files changed, 1004 insertions(+), 104 deletions(-) create mode 100644 app/src/main/res/values-kn/arrays.xml create mode 100644 app/src/main/res/values-kn/strings.xml create mode 100644 app/src/main/res/values-nl/arrays.xml create mode 100644 app/src/main/res/values-nl/strings.xml diff --git a/app/src/main/res/values-ca/arrays.xml b/app/src/main/res/values-ca/arrays.xml index 597031bc..12040a55 100644 --- a/app/src/main/res/values-ca/arrays.xml +++ b/app/src/main/res/values-ca/arrays.xml @@ -16,8 +16,8 @@ Macedoni [Gràcies a @snajdovski] Vietnamita [Gràcies a @fouze555] Xinès tradicional [Gràcies a @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Català [Gràcies a @retiolus] + Rus [Gràcies a @rikishi0071] 0 diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index b56aaf81..525ecc2e 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -239,7 +239,7 @@ Visita la nostra pàgina web Obtén suport, parla, trobat amb altres i diverteix-te! Veure el nostre codi font a GitHub - Informa d\'errors, contribueix i diverteix-te (una altra vegada)! + Inspecta, segueix, informa d\'errors, contribueix i diverteix-te (una altra vegada)! Enviar comentaris per correu electrònic Reconeixements de tercers S\'utilitzen les següents biblioteques de codi obert: @@ -295,7 +295,8 @@ Mostrar la separació de la graella Desactivar l\'animació Espera primer que la tasca actual s\'hagi completat! - Post not found! + Publicació no trobada! + No s\'ha trobat cap aplicació que obri l\'enllaç %d m\'agrada %d m\'agrades diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 743529ee..bb0a00a0 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -296,6 +296,7 @@ Disable animation Please wait for the current task to complete first! Post not found! + No app found which opens urls %d like %d likes diff --git a/app/src/main/res/values-de/arrays.xml b/app/src/main/res/values-de/arrays.xml index 3a96e398..f193e227 100644 --- a/app/src/main/res/values-de/arrays.xml +++ b/app/src/main/res/values-de/arrays.xml @@ -16,8 +16,8 @@ Mazedonisch [Danke an @snajdovski] Vietnamesisch [Danke an @fouze555] Chinesische Traditionelle Sprache [Danke an @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Katalanisch [Danke an @retiolus] + Russisch [Danke an @rikishi0071] 0 diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 4a088279..e2905481 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -61,10 +61,10 @@ Abstimmung erfolgreich! Du hast bereits abgestimmt! Antworten - Answer… + Antworten… Antwort erfolgreich! Auf Story antworten - Reply… + Antworten… Quiz Du hast bereits geantwortet! Erwähnungen @@ -86,8 +86,8 @@ Gespeichert Markiert Nachricht - Like - Unlike + Gefällt mir + Gefällt mir nicht mehr Lesezeichen Lesezeichen entfernen Folgen @@ -157,7 +157,7 @@ Großer Erfolg! Verlassen Chat verlassen? - Kick + Entfernen Left users Direkt herunterladen Lade Posts direkt auf das Handy herunter! @@ -165,7 +165,7 @@ Bitte erteile die Berechtigung und versuche das Herunterladen erneut! Download gestartet Download abgeschlossen - Downloading post… + Beitrag wird heruntergeladen… Medien herunterladen Profilbild wird heruntergeladen Datei im Download-Verzeichnis heruntergeladen! @@ -189,19 +189,19 @@ Hat %s nicht abonniert Nicht von %s abonniert Fehler beim Laden der Cookies - Write a new comment… - Write a new message… + Schreibe einen neuen Kommentar… + Schreibe eine neue Nachricht… gefällt dein Foto. Hat deinen Beitrag kommentiert: folgt dir jetzt. Hat dich erwähnt: - Tagged you in a post + Hat dich in einem Beitrag getaggt Angefordert dir zu folgen Anfrage annehmen Anfrage ablehnen - Share this public post to… + Diesen öffentlichen Beitrag teilen mit… Dies ist ein privater Beitrag! Teile ihn mit denen, die ihn sehen können! - This category is somehow empty… + Diese Kategorie ist leer… Ein Update ist verfügbar! (%s) Erinnerung: Wenn du die App von F-Droid heruntergeladen hast, musst du sie dort aktualisieren! Das gilt auch für GitHub. Danke für die Aktualisierung von Barinsta! @@ -209,7 +209,7 @@ Hoppla.. die App ist abgestürzt, aber keine Sorge — du kannst Fehlerberichte an den Entwickler senden, um ihm zu helfen, das Problem zu beheben. (: Aktivität Bild auswählen - Uploading… + Hochladen… Du hast: %d Abonnenten %d Kommentare @@ -266,42 +266,43 @@ Wähle eine Sicherungsdatei (.zaai/.backup) Anwenden Speichern - Caption - Video player timeline + Bildunterschrift + Zeitleiste des Videoplayers Liking… Like unsuccessful Unlike unsuccessful Unliking… Controls - Saving… - Removing… - Save unsuccessful - Remove unsuccessful - Downloading… - Download item %d of %d - Delete - Comment + Speichern… + Wird entfernt… + Speichern fehlgeschlagen + Entfernen fehlgeschlagen + Herunterladen… + Element %d von %d herunterladen + Löschen + Kommentar Layout - Opening post... - Share + Öffne Beitrag... + Teilen Layoutstil Spaltenanzahl 2 3 Namen anzeigen Avatare anzeigen - Avatar size - Corners + Avatargröße + Ecken Rasterabstand anzeigen - Disable animation - Please wait for the current task to complete first! - Post not found! + Animationen deaktivieren + Bitte warte bis die aktuelle Aufgabe abgeschlossen ist! + Beitrag nicht gefunden! + Keine App gefunden, die URLs öffnet - %d like - %d likes + %d Person gefällt das + %d Personen gefällt das - %d comment - %d comments + %d Kommentar + %d Kommentare diff --git a/app/src/main/res/values-es/arrays.xml b/app/src/main/res/values-es/arrays.xml index 6d597809..13aedbf7 100755 --- a/app/src/main/res/values-es/arrays.xml +++ b/app/src/main/res/values-es/arrays.xml @@ -16,8 +16,8 @@ Macedonio [Gracias a @snajdovski] Vietnamita [Gracias a @fouze555] Chino tradicional [Gracias a @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Catalán [Gracias a @retiolus] + Ruso [Gracias a @rikishi0071] 0 diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9dee9c34..f998d155 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -295,7 +295,8 @@ Mostrar espaciado de cuadrícula Desactivar animaciones ¡Por favor, espera a que la tarea actual se complete primero! - Post not found! + ¡Publicación no encontrada! + No se encontró ninguna aplicación que abra los enlaces %d me gusta %d me gustas diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index daeb67c6..7f9aefc4 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -297,6 +297,7 @@ Disable animation Please wait for the current task to complete first! Post not found! + No app found which opens urls %d پسند %d پسند diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 99aa7aa4..3a22c8b4 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -295,7 +295,8 @@ Afficher les lacunes de la grille Désactiver les animations Veuillez d\'abord attendre que la tâche en cours soit terminée ! - Post not found! + Publication non trouvée! + Aucune application trouvée qui ouvre les urls %d j\'aime %d j\'aimes diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 5a598487..0fed4a76 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -297,6 +297,7 @@ Disable animation Please wait for the current task to complete first! Post not found! + No app found which opens urls %d like %d likes diff --git a/app/src/main/res/values-in/arrays.xml b/app/src/main/res/values-in/arrays.xml index 97192bb2..b55e6ae4 100644 --- a/app/src/main/res/values-in/arrays.xml +++ b/app/src/main/res/values-in/arrays.xml @@ -16,8 +16,8 @@ Makedonia [Terima kasih @snajdovski] Vietnam Tiongkok Tradisional [Terima kasih @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Katalan [Terima kasih @retiolus] + Rusia [Terima kasih @rikishi0071] 0 diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 6102db09..db18f42e 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -296,6 +296,7 @@ Matikan animasi Harap tunggu hingga tugas saat ini selesai! Post not found! + No app found which opens urls %d suka diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 632cd150..5f22338a 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -296,6 +296,7 @@ Disabilita animazione Prima, sei pregato di attendere che l\'attività corrente sia completata! Post non trovato! + Nessuna applicazione trovata che apre gli urls %d Mi piace %d Mi piace diff --git a/app/src/main/res/values-kn/arrays.xml b/app/src/main/res/values-kn/arrays.xml new file mode 100644 index 00000000..141aef55 --- /dev/null +++ b/app/src/main/res/values-kn/arrays.xml @@ -0,0 +1,133 @@ + + + + System Default + English + French [Thanks to @kernoeb] + Spanish [Thanks to @sguinetti] + Chinese Simplified + Indonesian [Thanks to @Galang23] + Italian [Thanks to @RAR_Ramar] + German [Thanks to @peterge1998] + Polish [Thanks to @Lego8486] + Turkish [Thanks to @faydin90] + Brazilian Portuguese [Thanks to @wagnim] + Persian [Thanks to @farzadx] + Macedonian [Thanks to @snajdovski] + Vietnamese [Thanks to @fouze555] + Chinese Traditional [Thanks to @Still34] + Catalan [Thanks to @retiolus] + Russian [Thanks to @rikishi0071] + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + + + Auto / Follow System + Auto / Follow Battery + Dark + Light + + + 0 + 1 + 2 + 3 + + + None + \@ + at + on + \| + - + + + Loading... + + + dd-MM-yyyy + dd/MM/yyyy + dd.MM.yyyy + dd-MM-yy + dd/MM/yy + dd.MM.yy + dd-MMM-yyyy + dd/MMM/yyyy + dd.MMM.yyyy + dd-MMM-yy + dd/MMM/yy + dd.MMM.yy + MM-dd-yyyy + MM/dd/yyyy + MM.dd.yyyy + yyyy-MM-dd + yyyy/MM/dd + yyyy.MM.dd + MM-dd-yy + MM/dd/yy + MM.dd.yy + yy-MM-dd + yy/MM/dd + yy.MM.dd + MMM-dd-yyyy + MMM/dd/yyyy + MMM.dd.yyyy + yyyy-MMM-dd + yyyy/MMM/dd + yyyy.MMM.dd + MMM-dd-yy + MMM/dd/yy + MMM.dd.yy + yy-MMM-dd + yy/MMM/dd + yy.MMM.dd + + + hh:mm:ss a + h:mm:ss a + HH:mm:ss + H:mm:ss + + + @string/title_dm + @string/feed + @string/profile + @string/title_discover + @string/more + + + @string/light_white_theme + @string/light_barinsta_theme + @string/light_bibliogram_theme + + + @style/AppTheme.Light.White + @style/AppTheme.Light.Barinsta + @style/AppTheme.Light.Bibliogram + + + @string/dark_black_theme + @string/dark_material_dark_theme + + + @style/AppTheme.Dark.Black + @style/AppTheme.Dark.MaterialDark + + diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml new file mode 100644 index 00000000..15be9f26 --- /dev/null +++ b/app/src/main/res/values-kn/strings.xml @@ -0,0 +1,308 @@ + + + About + Direct Messages + Settings + Download + Search username… + Compare + Error copying text + Copied to clipboard! + Report + Password (Max 32 chars) + Set a password (max 32 chars) + Password + OK + Yes + Cancel + No + Confirm + Up + Don\'t Show Again + Current directory + Favorites + Discover + Comments + Notifications + Highlight: %s + Check for updates at startup + Download posts to username folders + Mark stories as seen after viewing + Story author will know you viewed it + Mark DM as seen after viewing + Other members will know you viewed it + Enable activity notifications + Error loading profile!\nTry logging in and search again. + Error creating Download folder(s). + Save to custom folder + Select folder + Theme + Only affects logged-in users: + Only affects anonymous users: + Use Instadp for high definition profile pictures + Import/Export + Language + %s\nPosts + %s Posts + %s\nFollowers + %s\nFollowing + Autoplay videos + Always mute videos + Select what to download + Current + Whole Album + Show stories + No more stories! + Be patient! + View Post + View Post + Spotify + Vote + Vote successful! + You have already voted! + Respond + Answer… + Answer successful! + Reply to story + Reply… + Quiz + You have already answered! + Mentions + This Account is Private + You won\'t be able to access posts after unfollowing! Are you sure? + You can log in via More -> Account on the bottom-right corner or you can view public accounts without login! + You can swipe left/right for explore/feed, or search something below! + This Account has No Posts + No Such Posts! + Current version: v%s + read more… + Login + Logout + Browse Instagram anonymously + Remove all accounts + This will remove all added accounts from the app!\nTo remove just one account, long tap the account from the account switcher dialog.\nDo you want to continue? + Date format + Liked + Saved + Tagged + Message + Like + Unlike + Bookmark + Unbookmark + Follow + Unfollow + Favorite + Unfavorite + Block + Unblock + Restrict + Unrestrict + Map + Export + Import + Export Logins + Accounts + Settings + Favorites + Import settings + Import Logins + Import accounts + Import favorites + Successfully imported! + Failed to import! + Successfully exported! + Failed to export! + Password is empty! + Refresh + Get cookies + Desktop Mode + Use custom format + Separator + Time Format + Date Format + Preview + Swap Time and Date positions + Cannot delete currently in use account + Are you sure you want to delete \'%s\'? + Open profile + View profile picture + You + Shared a link + Shared a media + Shared a timed message + Replied to a story + Reacted on a story + Mentioned in a story + Unsupported message type + Open link + Copy text + Download attachment + Like message + Unlike message + Unsend message + View author profile + Post shared from %s + Unknown media type + Media expired! + Delivered + Sent + Opened + Replayed + Sending… + Blocked + Suggested + Screenshotted + Cannot deliver + Great success! + Leave + Leave this chat? + Kick + Left users + Download directly + Downloads posts directly to the phone! + Fetching post(s) + Please grant permissions and try downloading again! + Download started + Download completed + Downloading post… + Downloading media + Downloading profile picture + File downloaded in Downloads folder! + Unknown error occurred!!! + Error creating folder! + Error downloading file + You can only download 100 posts at a time. Don\'t be too greedy! + Copy username + Copy comment + Reply to comment + Like comment + Unlike comment + Delete comment + No empty comments! + Do you want to search the username? + Do you want to search the hashtag? + Followers + Following + Comparing followers & following + Both following each other + not following %s + %s is not following + Error loading cookies + Write a new comment… + Write a new message… + Liked your post + Commented on your post: + Started following you + Mentioned you: + Tagged you in a post + Requested following you + Approve request + Reject request + Share this public post to… + This is a private post! Share to those who can view them! + This category is somehow empty… + An update is available! (%s) + Reminder: If you downloaded from F-Droid, you must update from it! Same applies for GitHub. + Thank you for updating Barinsta! + App crashed + Oops.. the app crashed, but don\'t worry you can send error report to the developer to help him fix the issue. (: + Activity + Select Picture + Uploading… + You have: + %d follows + %d comments + %d comment likes + %d usertags + %d likes + You logged out before clicking this notification?! + Feed + Profile + More + DM + %d selected + Successfully logged out! + Info + Mark as seen + Do not show again until next update + Version + Start screen + General + Theme + Downloads + Locale + Account + Current login not working? Simply add the account again. + Add account + License (English only) + Visit our website + Get support, discuss, meet others, and have fun! + See our source code on GitHub + Audit, star, report bugs, contribute, and have fun (again)! + Send feedback by email + Third-Party Attributions + The following third-party open-source libraries are used: + Reminder + Please use this app responsibly. Downloaded images should only be used for purposes allowed by applicable laws. + White + Black + Light theme + Dark theme + Barista + Material Dark + Added to Favorites + Add to favorites + Accounts + Hashtags + Locations + Unknown + Removed from Favourites + Backup & Restore + Create + Restore + File: + Enter password + Select a backup file (.zaai/.backup) + Apply + Save + Caption + Video player timeline + Liking… + Like unsuccessful + Unlike unsuccessful + Unliking… + Controls + Saving… + Removing… + Save unsuccessful + Remove unsuccessful + Downloading… + Download item %d of %d + Delete + Comment + Layout + Opening post... + Share + Layout style + Column count + 2 + 3 + Show names + Show avatars + Avatar size + Corners + Show grid gap + Disable animation + Please wait for the current task to complete first! + Post not found! + No app found which opens urls + + %d like + %d likes + + + %d comment + %d comments + + diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 50e213ba..14995f48 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -296,6 +296,7 @@ Disable animation Please wait for the current task to complete first! Post not found! + No app found which opens urls %d like %d likes diff --git a/app/src/main/res/values-nl/arrays.xml b/app/src/main/res/values-nl/arrays.xml new file mode 100644 index 00000000..f5d75d04 --- /dev/null +++ b/app/src/main/res/values-nl/arrays.xml @@ -0,0 +1,133 @@ + + + + Systeemstandaard + Engels + Frans [Met dank aan @kernoeb] + Spaans [Met dank aan @sguinetti] + Chinees (vereenvoudigd) + Indonesisch [Met dank aan @Galang23] + Italiaans [Met dank aan @RAR_Ramar] + Duits [Met dank aan @peterge1998] + Pools [Met dank aan @Lego8486] + Turks [Met dank aan @faydin90] + Braziliaans Portugees [Met dank aan @wagnim] + Perzisch [Met dank aan @farzadx] + Macedonisch [Met dank aan @snajdovski] + Vietnamees [Met dank aan @fouze555] + Chinees traditioneel [Met dank aan @Still34] + Catalaans [Met dank aan @retiolus] + Russisch [Met dank aan @rikishi0071] + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + + + Automatisch / Volgsysteem + Automatisch / Volg batterij + Donker + Licht + + + 0 + 1 + 2 + 3 + + + Geen + \@ + bij + op + \| + - + + + Aan het laden... + + + dd-MM-yyyy + dd/MM/yyyy + dd.MM.yyyy + dd-MM-yy + dd/MM/yy + dd.MM.yy + dd-MMM-yyyy + dd/MMM/yyyy + dd.MMM.yyyy + dd-MMM-yy + dd/MMM/yy + dd.MMM.yy + MM-dd-yyyy + MM/dd/yyyy + MM.dd.yyyy + yyyy-MM-dd + yyyy/MM/dd + yyyy.MM.dd + MM-dd-yy + MM/dd/yy + MM.dd.yy + yy-MM-dd + yy/MM/dd + yy.MM.dd + MMM-dd-yyyy + MMM/dd/yyyy + MMM.dd.yyyy + yyyy-MMM-dd + yyyy/MMM/dd + yyyy.MMM.dd + MMM-dd-yy + MMM/dd/yy + MMM.dd.yy + yy-MMM-dd + yy/MMM/dd + yy.MMM.dd + + + hh:mm:ss a + h:mm:ss a + HH:mm:ss + H:mm:ss + + + @string/title_dm + @string/feed + @string/profile + @string/title_discover + @string/more + + + @string/light_white_theme + @string/light_barinsta_theme + @string/light_bibliogram_theme + + + @style/AppTheme.Light.White + @style/AppTheme.Light.Barinsta + @style/AppTheme.Light.Bibliogram + + + @string/dark_black_theme + @string/dark_material_dark_theme + + + @style/AppTheme.Dark.Black + @style/AppTheme.Dark.MaterialDark + + diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 00000000..de20b842 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,308 @@ + + + Over + Privé berichten + Instellingen + Download + Zoek gebruikersnaam… + Vergelijk + Fout bij kopiëren van tekst + Gekopiëerd naar klembord! + Melden + Wachtwoord (Max 32 tekens) + Stel een wachtwoord in (max 32 tekens) + Wachtwoord + Oké + Ja + Annuleren + Nee + Bevestigen + Boven + Niet meer tonen + Huidige map + Favorieten + Ontdekken + Opmerkingen + Meldingen + Hoogtepunt: %s + Controleer op updates bij het opstarten + Download berichten naar gebruikersnaam mappen + Markeer verhalen als gelezen na bekijken + Verhaalmaker zal het weten als je het bekeken hebt + Markeer privéberichten als gelezen na bekijken + Andere gebruikers zullen het weten als je het hebt bekeken + Activiteitmeldingen inschakelen + Fout tijdens het laden van profiel!\nProbeer opnieuw in te loggen en te zoeken. + Fout bij maken download map(en). + Opslaan in aangepaste map + Selecteer map + Thema + Heeft alleen invloed op ingelogde gebruikers: + Heeft alleen invloed op anonieme gebruikers: + Instadp gebruiken voor hoge definitie profielfoto\'s + Importeren/Exporteren + Taal + %s\nBerichten + %s Berichten + %s\nVolgers + %s\nVolgend + Video\'s automatisch afspelen + Video\'s altijd dempen + Selecteer wat je wil downloaden + Huidige + Volledige Album + Toon verhalen + Geen verhalen meer! + Wees geduldig! + Bekijk Bericht + Bekijk Bericht + Spotify + Stem + Stem succesvol! + Je hebt al gestemd! + Reageer + Antwoord… + Antwoord gelukt! + Reageer op het verhaal + Reageer… + Quiz + Je hebt al geantwoord! + Vermeldingen + Dit Account is Privé + Je zal geen toegang meer hebben tot berichten na het ontvolgen! Weet je het zeker? + Je kunt inloggen via Meer -> Rechtsonder in je account, of je kunt openbare accounts bekijken zonder in te loggen! + Je kunt naar links/rechts vegen voor ontdekken/feed of hieronder iets zoeken! + Dit Account heeft Geen Berichten + Geen dergelijke berichten! + Huidige versie: v%s + lees meer… + Aanmelden + Uitloggen + Anoniem Instagram browsen + Verwijder alle accounts + Dit zal alle toegevoegde accounts van de app verwijderen\nOm alleen één account te verwijderen, houdt het account lang ingedrukt bij het account-wisselscherm\nWil je doorgaan? + Datumnotatie + Leuk gevonden + Opgeslagen + Getagd + Bericht + Vind ik leuk + Vind ik niet meer leuk + Toevoegen aan favorieten + Verwijderen uit favorieten + Volg + Ontvolg + Toevoegen aan favorieten + Verwijderen uit favorieten + Blokkeer + Deblokkeer + Beperk + De-restrict + Kaart + Exporteer + Importeer + Exporteer Logins + Accounts + Instellingen + Favorieten + Importeer instellingen + Importeer Logins + Importeer accounts + Importeer favorieten + Succesvol geïmporteerd! + Importeren mislukt! + Succesvol geëxporteerd! + Exporteren mislukt! + Wachtwoord is leeg! + Ververs + Cookies ophalen + Desktop Modus + Aangepaste indeling gebruiken + Scheidingsteken + Tijdnotatie + Datumindeling + Voorbeeld + Wissel tijd- en datumposities + Kan momenteel niet het account verwijderen dat in gebruik is + Weet je zeker dat je \'%s\' wilt verwijderen? + Open profiel + Bekijk profielfoto + Jij + Heeft een link gedeeld + Heeft media gedeeld + Heeft een tijdelijk bericht gedeeld + Heeft gereageerd op een verhaal + Heeft gereageerd op een verhaal + Heeft genoemd in een verhaal + Niet ondersteund berichttype + Koppeling openen + Kopieer tekst + Bijlage downloaden + Like bericht + Unlike bericht + Maak bericht ongedaan + Bekijk profiel van auteur DM + Post gedeeld van %s + Onbekend mediatype + Media verlopen! + Afgeleverd + Verzonden + Geopend + Opnieuw afgespeeld + Bezig met verzenden… + Geblokkeerd + Voorgesteld + Screenshot genomen + Kan niet afleveren + Geweldig succes! + Verlaten + Deze chat verlaten? + Kick + Gebruikers verlaten + Rechtstreeks downloaden + Download rechtstreeks naar het apparaat! + Post(s) ophalen + Geef toestemming en probeer opnieuw te downloaden! + Download is gestart + Download voltooid + Bericht downloaden… + Media downloaden + Profielfoto downloaden + Bestand gedownload in Downloads map! + Er is een onbekende fout opgetreden!!! + Fout bij aanmaken map! + Fout bij downloaden bestand + Je kunt slechts 100 berichten per keer downloaden. Wees niet te hebberig! + Kopieer gebruikersnaam + Kopieer reactie + Reageer op opmerking + Vind reactie leuk + Vind reactie niet meer leuk + Verwijder opmerking + Geen lege reacties! + Wil je de gebruikersnaam zoeken? + Wil je de hashtag zoeken? + Volgers + Volgend + Vergelijk volgers & volgend + Beide volgen elkaar + niet volgend %s + %s is niet aan het volgen + Fout bij laden van cookies + Schrijf een nieuwer reactie… + Schrijf een nieuw bericht… + Vond je bericht leuk + Reageerde op je bericht: + Volgt je nu + Vermeldde jou: + Heeft je getagd in een bericht + Heeft een volgverzoek ingediend + Verzoek accepteren + Verzoek afwijzen + Deel dit openbare bericht met… + Dit is een privébericht! Deel het met mensen die hem kunnen zien! + Deze categorie is op de een of andere manier leeg… + Een update is beschikbaar(%s) + Herinnering: Als je via F-Droid hebt gedownload, moet je ook updaten via F-Droid! Hetzelfde geldt voor GitHub. + Bedankt voor het bijwerken van Barinsta! + App is gecrasht + Oeps.. de app is gecrasht, maar geen zorgen. Je kan een foutrapportage naar de ontwikkelaar sturen om hem te helpen met oplossen. (: + Activiteit + Selecteer Afbeelding + Bezig met uploaden… + Je hebt: + %d volgers + %d opmerkingen + %d opmerking-likes + %d gebruikerstags + %d likes + Bent u uitgelogd voordat u op deze melding klikt?! + Feed + Profiel + Meer + DM + %d geselecteerd + Je bent succesvol uitgelogd! + Informatie + Markeer als gelezen + Niet meer weergeven tot de volgende update + Versie + Startscherm + Algemeen + Thema + Downloads + Lokaal + Account + Huidige login werkt niet? Voeg gewoon opnieuw het account toe. + Account toevoegen + Licentie (alleen Engels) + Bezoek onze website + Krijg ondersteuning, discussieer, ontmoet anderen en veel plezier! + Bekijk onze broncode op GitHub + Audit, ster, meld bugs, bijdragen en veel plezier (nog een keer)! + Stuur feedback per e-mail + Attributen van derden + De volgende open-source-bibliotheken van derden worden gebruikt: + Herinnering + Gebruik deze app verantwoordelijk. Gedownloade afbeeldingen mogen alleen worden gebruikt voor doeleinden die zijn toegestaan door toepasselijke wetten. + Wit + Zwart + Licht thema + Donker thema + Barista + Materiaal Donker + Toegevoegd aan favorieten + Voeg toe aan Favorieten + Accounts + Hashtags + Locaties + Onbekend + Verwijderd uit Favorieten + Back-up & Terugzetten + Maak + Herstel + Bestand: + Voer wachtwoord in + Backup-bestand selecteren (.zaai/.backup) + Toepassen + Opslaan + Bijschrift + Videospeler tijdlijn + Liken… + Like niet gelukt + Unlike niet gelukt + Unliken… + Besturing + Opslaan… + Verwijderen… + Opslaan mislukt + Verwijderen mislukt + Downloaden… + Download item %d van %d + Verwijder + Reageeer + Lay-out + Bericht openen... + Delen + Lay-out stijl + Aantal kolommen + 2 + 3 + Toon namen + Toon avatars + Avatar grootte + Hoeken + Rasterruimte weergeven + Animatie uitschakelen + Wacht eerst tot de huidige taak voltooid is! + Bericht niet gevonden! + Geen app gevonden om URL\'s te openen + + %d vind-ik-leuk + %d vind-ik-leuks + + + %d opmerking + %d opmerkingen + + diff --git a/app/src/main/res/values-or/arrays.xml b/app/src/main/res/values-or/arrays.xml index b958e832..12020c43 100644 --- a/app/src/main/res/values-or/arrays.xml +++ b/app/src/main/res/values-or/arrays.xml @@ -16,8 +16,8 @@ ମାସେଡ଼ୋନିୟ [@snajdovski ଙ୍କ ଦ୍ୱାରା] ଭିଏତନାମୀୟ [@fouze555 ଙ୍କ ଦ୍ୱାରା] ଚୀନୀ ପାରମ୍ପରିକ [@Still34 ଙ୍କ ଦ୍ୱାରା] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + କାଟାଲାନ୍[@retiolus ଙ୍କ ଦ୍ୱାରା] + ରୁଷୀୟ[@rikishi0071 ଙ୍କ ଦ୍ୱାରା] 0 diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index 66162f53..7e36b6d6 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -24,14 +24,14 @@ ଖୋଜିବା ଟିପ୍ପଣୀ ସୂଚନା - Highlight: %s - Check for updates at startup - Download posts to username folders - Mark stories as seen after viewing - Story author will know you viewed it - Mark DM as seen after viewing - Other members will know you viewed it - Enable activity notifications + ବିଶେଷତା: %s + ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ + ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ + କାହାଣୀଗୁଡିକ ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ | + କାହାଣୀ ପ୍ରେରକ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ + ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ | + ଅନ୍ୟ ସଦସ୍ୟମାନେ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ। + କାର୍ଯ୍ୟକଳାପ ସୂଚନା ଦେଖାନ୍ତୁ Error loading profile!\nTry logging in and search again. Error creating Download folder(s). Save to custom folder @@ -296,6 +296,7 @@ Disable animation Please wait for the current task to complete first! Post not found! + No app found which opens urls %d like %d likes diff --git a/app/src/main/res/values-pl/arrays.xml b/app/src/main/res/values-pl/arrays.xml index 2ce6e558..1572e8b0 100644 --- a/app/src/main/res/values-pl/arrays.xml +++ b/app/src/main/res/values-pl/arrays.xml @@ -16,8 +16,8 @@ Macedoński [Podziękowania dla @snajdovski] Wietnamski [Podziękowania dla @fouze555] Chiński Tradycyjny [Podziękowania dla @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Kataloński [Podziękowania dla @retiolus] + Rosyjski [Podziękowania dla @rikishi0071] 0 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index bc5d7c0f..17f87e4c 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -84,7 +84,7 @@ Format daty Polubiono Zapisano - Oznaczony + Oznaczono Message Polub Cofnij polubienie @@ -295,7 +295,8 @@ Pokaż widok siatki Wyłączenie animacji Poczekaj aż bieżące zadanie zostanie ukończone! - Post not found! + Nie znaleziono posta! + Nie znaleziono aplikacji, która otwiera adresy URL %d polubienie %d polubień diff --git a/app/src/main/res/values-pt/arrays.xml b/app/src/main/res/values-pt/arrays.xml index 0b575e2e..61f30811 100644 --- a/app/src/main/res/values-pt/arrays.xml +++ b/app/src/main/res/values-pt/arrays.xml @@ -16,8 +16,8 @@ Македонски [Благодарност до @snajdovski] Tiếng Việt [bởi @fouze555] 繁體中文 [感謝 @Still34] - Catalão [Obrigado @retiolus] - Russo [Obrigado @rikishi0071] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] 0 diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 0ff032df..5c9c07b5 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -125,7 +125,7 @@ Trocar posições de Data e Hora Não é possível excluir a conta atualmente em uso Tem certeza que deseja excluir %s\'? - Perfil aberto + Abrir perfil Ver foto de perfil Você Compartilhou um link @@ -296,6 +296,7 @@ Desativar animação Por favor, espere a tarefa atual ser concluída primeiro! Publicação não encontrada! + Nenhum aplicativo para abrir urls encontrado %d curtida %d curtidas diff --git a/app/src/main/res/values-ru/arrays.xml b/app/src/main/res/values-ru/arrays.xml index 83031d1d..e5c09704 100644 --- a/app/src/main/res/values-ru/arrays.xml +++ b/app/src/main/res/values-ru/arrays.xml @@ -16,8 +16,8 @@ Македонский [Спасибо @snajdovski] Вьетнамский [Спасибо @fouze555] Китайский традиционный [Спасибо @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Каталонский + Русский 0 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index dd45a00f..a4e410c7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -295,7 +295,8 @@ Показать разрыв сетки Отключить анимацию Пожалуйста, дождитесь сначала выполнения текущей задачи! - Post not found! + Публикация не найдена! + Нет приложения, чтоб открыть ссылку %d нравится %d нравится diff --git a/app/src/main/res/values-tr/arrays.xml b/app/src/main/res/values-tr/arrays.xml index 1b6eca36..e04150ef 100644 --- a/app/src/main/res/values-tr/arrays.xml +++ b/app/src/main/res/values-tr/arrays.xml @@ -15,9 +15,9 @@ Farsça [@farzadx tarafından] Makedonyaca [@snajdovski tarafından] Vietnamca [@fouze555 sayesinde] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Geleneksel Çince [@Still34 tarafından] + Katalanca [@retiolus tarafından] + Rusça [@rikishi0071 tarafından] 0 diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 3ac0ac43..199af33a 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -265,43 +265,44 @@ Şifreyi gir Yedekleme dosyası seç (.zaai/.backup) Uygula - Save - Caption - Video player timeline - Liking… - Like unsuccessful - Unlike unsuccessful - Unliking… - Controls - Saving… - Removing… - Save unsuccessful - Remove unsuccessful - Downloading… - Download item %d of %d - Delete - Comment - Layout - Opening post... - Share - Layout style - Column count + Kaydet + Başlık + Video oynatıcı zaman çizelgesi + Beğeniliyor… + Beğenme başarısız oldu + Beğenmekten vazgeçme başarısız oldu + Beğenmekten vazgeçiliyor… + Kontroller + Kaydediliyor… + Siliniyor… + Kaydetme işlemi başarısız oldu + Silme işlemi başarısız oldu + İndiriliyor… + İndiriliyor (%d / %d) + Sil + Yorum yap + Yerleşim + Gönderi açılıyor... + Paylaş + Yerleşim biçimi + Sütun sayısı 2 3 - Show names - Show avatars - Avatar size - Corners - Show grid gap - Disable animation - Please wait for the current task to complete first! - Post not found! + İsimleri göster + Avatarları göster + Avatar boyutu + Köşeler + Izgara boşluklarını göster + Animasyonları devre dışı bırak + Lütfen önce aktif görevin tamamlanmasını bekle! + Gönderi bulunamadı! + Linki açabilecek uygulama bulunamadı %d like - %d likes + %d beğeni - %d comment - %d comments + %d yorum + %d yorum diff --git a/app/src/main/res/values-vi/arrays.xml b/app/src/main/res/values-vi/arrays.xml index f441af77..1a37b5e8 100644 --- a/app/src/main/res/values-vi/arrays.xml +++ b/app/src/main/res/values-vi/arrays.xml @@ -15,9 +15,9 @@ Tiếng Ba Tư [bởi @farzadx] Tiếng Macedonia [bởi @snajdovski] Tiếng Việt [bởi @fouze555] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + Tiếng Trung truyền thống [bởi @Still34] + Tiếng Catalan [bởi @retiolus] + Tiếng Nga [bởi @rikishi0071] 0 diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index d226d5d2..fa6842a8 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -61,7 +61,7 @@ Bình chọn thành công! Bạn đã bình chọn rồi! Trả lời - Answer… + Phản hồi… Trả lời thành công! Trả lời story Reply… @@ -296,6 +296,7 @@ Disable animation Please wait for the current task to complete first! Post not found! + No app found which opens urls %d likes diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cb173e89..7efbe335 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -296,6 +296,7 @@ 禁用动画 请等待当前任务完成! 找不到该帖! + 没有找到打开网址的应用 %d 个赞 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4713530e..0fb9fc67 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -296,6 +296,7 @@ 停用動畫 Please wait for the current task to complete first! Post not found! + No app found which opens urls %d 個讚 From b72b3211d56e7423862361a62c42b119d54c42bb Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 12 Dec 2020 19:01:23 -0500 Subject: [PATCH 002/101] locale chores --- .../awais/instagrabber/utils/LocaleUtils.java | 2 + app/src/main/res/values/arrays.xml | 47 ++++++++++--------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java b/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java index 4d5644f4..f9b83225 100755 --- a/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/LocaleUtils.java @@ -76,6 +76,8 @@ public final class LocaleUtils { if (appLanguageIndex == 14) return "zh_TW"; if (appLanguageIndex == 15) return "ca"; if (appLanguageIndex == 16) return "ru"; + if (appLanguageIndex == 17) return "hi"; + if (appLanguageIndex == 18) return "nl"; return null; } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 7970918c..7a28f075 100755 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -2,24 +2,26 @@ System Default - English - French [Thanks to @kernoeb] - Spanish [Thanks to @sguinetti] - Chinese Simplified - Indonesian [Thanks to @Galang23] - Italian [Thanks to @RAR_Ramar] - German [Thanks to @peterge1998] - Polish [Thanks to @Lego8486] - Turkish [Thanks to @faydin90] - Brazilian Portuguese [Thanks to @wagnim] - Persian [Thanks to @farzadx] - Macedonian [Thanks to @snajdovski] - Vietnamese [Thanks to @fouze555] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] - + 0 1 2 @@ -37,6 +39,8 @@ 14 15 16 + 17 + 18 Auto / Follow System @@ -44,7 +48,7 @@ Dark Light - + 0 1 2 @@ -58,10 +62,7 @@ \| - - - Loading... - - + dd-MM-yyyy dd/MM/yyyy dd.MM.yyyy @@ -99,7 +100,7 @@ yy/MMM/dd yy.MMM.dd - + hh:mm:ss a h:mm:ss a HH:mm:ss From e39c129b610002cb04f9283dac3c2b84684abcb3 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 17 Dec 2020 11:33:04 -0500 Subject: [PATCH 003/101] New Crowdin updates (#414) * New translations arrays.xml (French) * New translations arrays.xml (Odia) * New translations arrays.xml (Indonesian) * New translations arrays.xml (Persian) * New translations arrays.xml (Hindi) * New translations arrays.xml (Catalan) * New translations arrays.xml (Russian) * New translations arrays.xml (Dutch) * New translations arrays.xml (Kannada) * New translations arrays.xml (Portuguese, Brazilian) * New translations arrays.xml (Vietnamese) * New translations arrays.xml (Spanish) * New translations arrays.xml (Czech) * New translations arrays.xml (German) * New translations arrays.xml (Italian) * New translations arrays.xml (Macedonian) * New translations arrays.xml (Polish) * New translations arrays.xml (Turkish) * New translations arrays.xml (Chinese Simplified) * New translations arrays.xml (Chinese Traditional) * Update source file arrays.xml * New translations arrays.xml (French) * New translations arrays.xml (Indonesian) * New translations arrays.xml (Spanish) * New translations arrays.xml (Italian) * New translations arrays.xml (Chinese Simplified) * New translations arrays.xml (Chinese Traditional) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Kannada) * New translations strings.xml (Chinese Traditional) --- app/src/main/res/values-ca/arrays.xml | 106 ++++----------------- app/src/main/res/values-cs/arrays.xml | 106 ++++----------------- app/src/main/res/values-de/arrays.xml | 106 ++++----------------- app/src/main/res/values-es/arrays.xml | 106 ++++----------------- app/src/main/res/values-fa/arrays.xml | 106 ++++----------------- app/src/main/res/values-fr/arrays.xml | 106 ++++----------------- app/src/main/res/values-hi/arrays.xml | 106 ++++----------------- app/src/main/res/values-in/arrays.xml | 106 ++++----------------- app/src/main/res/values-it/arrays.xml | 106 ++++----------------- app/src/main/res/values-kn/arrays.xml | 106 ++++----------------- app/src/main/res/values-kn/strings.xml | 10 +- app/src/main/res/values-mk/arrays.xml | 106 ++++----------------- app/src/main/res/values-nl/arrays.xml | 106 ++++----------------- app/src/main/res/values-or/arrays.xml | 106 ++++----------------- app/src/main/res/values-pl/arrays.xml | 106 ++++----------------- app/src/main/res/values-pt/arrays.xml | 106 ++++----------------- app/src/main/res/values-ru/arrays.xml | 106 ++++----------------- app/src/main/res/values-tr/arrays.xml | 106 ++++----------------- app/src/main/res/values-vi/arrays.xml | 106 ++++----------------- app/src/main/res/values-zh-rCN/arrays.xml | 106 ++++----------------- app/src/main/res/values-zh-rTW/arrays.xml | 106 ++++----------------- app/src/main/res/values-zh-rTW/strings.xml | 6 +- 22 files changed, 368 insertions(+), 1768 deletions(-) diff --git a/app/src/main/res/values-ca/arrays.xml b/app/src/main/res/values-ca/arrays.xml index 12040a55..39224cd2 100644 --- a/app/src/main/res/values-ca/arrays.xml +++ b/app/src/main/res/values-ca/arrays.xml @@ -2,41 +2,24 @@ Predeterminat del sistema - Anglès - Francès [Gràcies a @kernoeb] - Castellà [Gràcies a @sguinetti] - Chinès si - Indonès [Gràcies a @Galang23] - Italià [Gràcies a @RAR_Ramar] - Alemany [Gràcies a @peterge1998] - Polonès [Gràcies a @Lego8486] - Turc [Gràcies a @faydin90] - Portuguès brasiler [Gràcies a @wagnim] - Persa [Gràcies a @farzadx] - Macedoni [Gràcies a @snajdovski] - Vietnamita [Gràcies a @fouze555] - Xinès tradicional [Gràcies a @Still34] - Català [Gràcies a @retiolus] - Rus [Gràcies a @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Anglès + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Automàtic / Predeterminat del sistema @@ -44,12 +27,6 @@ Fosc Clar - - 0 - 1 - 2 - 3 - Ningún \@ @@ -58,53 +35,6 @@ \| - - - S\'està carregant... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-cs/arrays.xml b/app/src/main/res/values-cs/arrays.xml index 141aef55..4c75009e 100644 --- a/app/src/main/res/values-cs/arrays.xml +++ b/app/src/main/res/values-cs/arrays.xml @@ -2,41 +2,24 @@ System Default - English - French [Thanks to @kernoeb] - Spanish [Thanks to @sguinetti] - Chinese Simplified - Indonesian [Thanks to @Galang23] - Italian [Thanks to @RAR_Ramar] - German [Thanks to @peterge1998] - Polish [Thanks to @Lego8486] - Turkish [Thanks to @faydin90] - Brazilian Portuguese [Thanks to @wagnim] - Persian [Thanks to @farzadx] - Macedonian [Thanks to @snajdovski] - Vietnamese [Thanks to @fouze555] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Auto / Follow System @@ -44,12 +27,6 @@ Dark Light - - 0 - 1 - 2 - 3 - None \@ @@ -58,53 +35,6 @@ \| - - - Loading... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-de/arrays.xml b/app/src/main/res/values-de/arrays.xml index f193e227..845a4b87 100644 --- a/app/src/main/res/values-de/arrays.xml +++ b/app/src/main/res/values-de/arrays.xml @@ -2,41 +2,24 @@ Systemstandard - Englisch - Französisch [Danke an @kernoeb] - Spanisch [Danke an @sguinetti] - Chinesisch (Vereinfacht) - Indonesisch [Danke an @Galang23] - Italienisch [Danke an @RAR_Ramar] - Deutsch [Danke an @peterge1998] - Polnisch [Danke an @Lego8486] - Türkisch [Danke an @faydin90] - Brasilianisches Portugiesisch [Danke an @wagnim] - Persisch [Danke an @farzadx] - Mazedonisch [Danke an @snajdovski] - Vietnamesisch [Danke an @fouze555] - Chinesische Traditionelle Sprache [Danke an @Still34] - Katalanisch [Danke an @retiolus] - Russisch [Danke an @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Englisch + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Auto / Systemstandard @@ -44,12 +27,6 @@ Dunkel Hell - - 0 - 1 - 2 - 3 - Kein(e) \@ @@ -58,53 +35,6 @@ \| - - - Lädt... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-es/arrays.xml b/app/src/main/res/values-es/arrays.xml index 13aedbf7..4ac1a8ac 100755 --- a/app/src/main/res/values-es/arrays.xml +++ b/app/src/main/res/values-es/arrays.xml @@ -2,41 +2,24 @@ Predeterminado del sistema - Inglés - Francés [Gracias a @kernoeb] - Español [Gracias a @akrai] - Chino Simplificado - Indonesio [Gracias a @Galang23] - Italiano [Gracias a @RAR_Ramar] - Alemán [Gracias a @peterge1998] - Polaco [Gracias a @Lego8486] - Turco [Gracias a @faydin90] - Portugués brasileño [Gracias a @wagnim] - Persa [Gracias a @farzadx] - Macedonio [Gracias a @snajdovski] - Vietnamita [Gracias a @fouze555] - Chino tradicional [Gracias a @Still34] - Catalán [Gracias a @retiolus] - Ruso [Gracias a @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Auto / Seguir al sistema @@ -44,12 +27,6 @@ Oscuro Claro - - 0 - 1 - 2 - 3 - Ninguno \@ @@ -58,53 +35,6 @@ \| - - - Cargando... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-fa/arrays.xml b/app/src/main/res/values-fa/arrays.xml index 9583530a..8cc33d59 100644 --- a/app/src/main/res/values-fa/arrays.xml +++ b/app/src/main/res/values-fa/arrays.xml @@ -2,41 +2,24 @@ پیشگزیده سامانه - انگلیسی - فرانسوی [ با سپاس از kernoeb@ ] - اسپانیایی [ با سپاس از sguinetti@ ] - چینی ساده شده - اندونزیایی [ با سپاس از Galang23@ ] - ایتالیایی [ با سپاس از RAR_Ramar@ ] - آلمانی [ با سپاس از peterge1998@ ] - لهستانی [ با سپاس از Lego8486@ ] - ترکی [ با سپاس از faydin90@ ] - برزیلی پرتغالی [ با سپاس از wagnim@ ] - پارسی [ با سپاس از Frzking@ ] - مقدونی [ با تشکر از snajdovski@ ] - ویتنامی [ با سپاس از fouze555@ ] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] - - - ۰ - ۱ - ۲ - ۳ - ۴ - ۵ - ۶ - ۷ - ۸ - ۹ - ۱۰ - 11 - 12 - 13 - 14 - 15 - 16 + انگلیسی + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] خودکار / پیروی از سامانه @@ -44,12 +27,6 @@ تیره روشن - - ۰ - ۱ - ۲ - ۳ - هیچکدام \@ @@ -58,53 +35,6 @@ \| - - - در بارگیری... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-fr/arrays.xml b/app/src/main/res/values-fr/arrays.xml index ad7fe84b..ee3cd341 100755 --- a/app/src/main/res/values-fr/arrays.xml +++ b/app/src/main/res/values-fr/arrays.xml @@ -2,41 +2,24 @@ Par défaut (Système) - Anglais - Français [Merci à @kernoeb] - Espagnol [Merci à @sguinetti] - Chinois Simplifié - Indonésien [Merci à @Galang23] - Italien [Merci à @RAR_Ramar] - Allemand [Merci à @peterge1998] - Polonais [Merci à @Lego8486] - Turc [Merci à @faydin90] - Portugais brésilien [Merci à @wagnim] - Perse [Merci à @farzadx] - Macédonien [merci à @snajdovski] - Vietnamien [merci à @fouze555] - Chinois traditionnel [Merci à @Still34] - Catalan [Merci à @retiolus] - Russe [Merci à @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Automatique (Système) @@ -44,12 +27,6 @@ Sombre Clair - - 0 - 1 - 2 - 3 - Aucun \@ @@ -58,53 +35,6 @@ \| - - - Chargement ... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-hi/arrays.xml b/app/src/main/res/values-hi/arrays.xml index d31549be..8534c2cc 100644 --- a/app/src/main/res/values-hi/arrays.xml +++ b/app/src/main/res/values-hi/arrays.xml @@ -2,41 +2,24 @@ सिस्टम निर्धारित - अंग्रेजी - फ़्रान्सीसी [@kernoeb के द्वारा] - स्पेनी भाषा [@sguinetti के द्बारा] - चीनी (सरलीकृत) - इंडोनेशियाई भाषा [@Galang23 के द्बारा] - इटालवी [@RAR_Ramar के द्बारा] - जर्मन [@peterge1998 के द्बारा] - पोलिश भाषा [@Lego8486 के द्बारा] - तुर्की भाषा [@faydin90 के द्बारा] - ब्राजीलियाई पुर्तगाली [@wagnim के द्बारा] - फ़ारसी [@farzadx के द्बारा] - मेसिडोनियन [@snajdovski के द्बारा] - वियतनामी [@fouze555 के द्बारा] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] - - - 0 - - - - - - - - - - १० - ११ - १२ - १३ - 14 - 15 - 16 + अंग्रेजी + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] सिस्टम के अनुसार @@ -44,12 +27,6 @@ काला हल्का - - - - - - कुछ नहीं \@ @@ -58,53 +35,6 @@ \| - - - खुल रहा है... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-in/arrays.xml b/app/src/main/res/values-in/arrays.xml index b55e6ae4..de82049b 100644 --- a/app/src/main/res/values-in/arrays.xml +++ b/app/src/main/res/values-in/arrays.xml @@ -2,41 +2,24 @@ Bawaan Sistem - Inggris - Prancis [Terima kasih @kernoeb] - Spanyol [Terima kasih @sguinetti] - Tiongkok Sederhana - Bahasa Indonesia [Terima kasih @Galang23] - Italia [Terima kasih @RAR_Ramar] - Jerman [Teirma kasih @peterge1998] - Polandia [Terima kasih @Lego8486] - Turki [Terima kasih @faydin90] - Portugis Brazil [Terima kasih @wagnim] - Persia [Terima kasih @farzadx] - Makedonia [Terima kasih @snajdovski] - Vietnam - Tiongkok Tradisional [Terima kasih @Still34] - Katalan [Terima kasih @retiolus] - Rusia [Terima kasih @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Otomatis / Ikuti Sistem @@ -44,12 +27,6 @@ Gelap Terang - - 0 - 1 - 2 - 3 - Tidak ada \@ @@ -58,53 +35,6 @@ tanggal - - - Memuat... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-it/arrays.xml b/app/src/main/res/values-it/arrays.xml index d602168d..a90c61c5 100755 --- a/app/src/main/res/values-it/arrays.xml +++ b/app/src/main/res/values-it/arrays.xml @@ -2,41 +2,24 @@ Predefinito di Sistema - Inglese - Francese [Grazie a @kernoeb] - Spagnolo [Grazie a @sguinetti] - Cinese Semplificato - Indonesiano [Grazie a @Galang23] - Italiano [Grazie a @RAR_Ramar e Giorgio Arbato] - Tedesco [Grazie a @peterge1998] - Polacco [Grazie a @Lego8486] - Turco [Grazie a @faydin90] - Portoghese Brasiliano [Grazie a @wagnim] - Persiano [Grazie a @farzadx] - Macedone [Grazie a @snajdovski] - Vietnamita [Grazie a @fouze555] - Cinese Tradizionale [Grazie a @Still34] - Catalano [Grazie a @retiolus] - Russo [Grazie a @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Automatico / Basato sul Sistema @@ -44,12 +27,6 @@ Scuro Chiaro - - 0 - 1 - 2 - 3 - Nessuno \@ @@ -58,53 +35,6 @@ \| - - - Caricamento... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-kn/arrays.xml b/app/src/main/res/values-kn/arrays.xml index 141aef55..4c75009e 100644 --- a/app/src/main/res/values-kn/arrays.xml +++ b/app/src/main/res/values-kn/arrays.xml @@ -2,41 +2,24 @@ System Default - English - French [Thanks to @kernoeb] - Spanish [Thanks to @sguinetti] - Chinese Simplified - Indonesian [Thanks to @Galang23] - Italian [Thanks to @RAR_Ramar] - German [Thanks to @peterge1998] - Polish [Thanks to @Lego8486] - Turkish [Thanks to @faydin90] - Brazilian Portuguese [Thanks to @wagnim] - Persian [Thanks to @farzadx] - Macedonian [Thanks to @snajdovski] - Vietnamese [Thanks to @fouze555] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Auto / Follow System @@ -44,12 +27,6 @@ Dark Light - - 0 - 1 - 2 - 3 - None \@ @@ -58,53 +35,6 @@ \| - - - Loading... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index 15be9f26..17b0f4ee 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -1,10 +1,10 @@ - About - Direct Messages - Settings - Download - Search username… + ಬಗ್ಗೆ + ನೇರ ಸಂದೇಶಗಳು + ಸಿದ್ಧತೆಗಳು + ಡೌನ್‌ಲೋಡ್ + ಬಳಕೆದಾರರನ್ನು ಹುಡುಕಿ… Compare Error copying text Copied to clipboard! diff --git a/app/src/main/res/values-mk/arrays.xml b/app/src/main/res/values-mk/arrays.xml index eeec44ac..19203a1a 100644 --- a/app/src/main/res/values-mk/arrays.xml +++ b/app/src/main/res/values-mk/arrays.xml @@ -2,41 +2,24 @@ Системски одбрано - Англиски - Француски [Благодарност до @kernoeb] - Шпански [Благодарност до @sguinetti] - Кинески - Индонезиски [Благодарност до @Galang23] - Италијански [Благодарност до @RAR_Ramar] - Германски [Благодарност до @peterge1998] - Полски [Благодарност до @Lego8486] - Турски [Благодарност до @faydin90] - Бразилски Португалски [Благодарност до @wagnim] - Персиски [Благодарност до @farzadx] - Македонски [Благодарност до @snajdovski] - Виетнамски[Благодарност до @fouze555] - Chinese Traditional [Thanks to @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Англиски + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Автоматска тема @@ -44,12 +27,6 @@ Темно Светло - - 0 - 1 - 2 - 3 - Ништо \@ @@ -58,53 +35,6 @@ \| - - - Вчитување... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-nl/arrays.xml b/app/src/main/res/values-nl/arrays.xml index f5d75d04..54fe7725 100644 --- a/app/src/main/res/values-nl/arrays.xml +++ b/app/src/main/res/values-nl/arrays.xml @@ -2,41 +2,24 @@ Systeemstandaard - Engels - Frans [Met dank aan @kernoeb] - Spaans [Met dank aan @sguinetti] - Chinees (vereenvoudigd) - Indonesisch [Met dank aan @Galang23] - Italiaans [Met dank aan @RAR_Ramar] - Duits [Met dank aan @peterge1998] - Pools [Met dank aan @Lego8486] - Turks [Met dank aan @faydin90] - Braziliaans Portugees [Met dank aan @wagnim] - Perzisch [Met dank aan @farzadx] - Macedonisch [Met dank aan @snajdovski] - Vietnamees [Met dank aan @fouze555] - Chinees traditioneel [Met dank aan @Still34] - Catalaans [Met dank aan @retiolus] - Russisch [Met dank aan @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Engels + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Automatisch / Volgsysteem @@ -44,12 +27,6 @@ Donker Licht - - 0 - 1 - 2 - 3 - Geen \@ @@ -58,53 +35,6 @@ \| - - - Aan het laden... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-or/arrays.xml b/app/src/main/res/values-or/arrays.xml index 12020c43..8a3b45aa 100644 --- a/app/src/main/res/values-or/arrays.xml +++ b/app/src/main/res/values-or/arrays.xml @@ -2,41 +2,24 @@ ସିଷ୍ଟମ ନିର୍ଧାରିତ - ଇଂରାଜୀ - ଫରାସୀ [@kernoeb ଙ୍କ‌ ଦ୍ୱାରା] - ସ୍ପେନୀୟ [@sguinetti ଙ୍କ ଦ୍ୱାରା] - ଚୀନିୟ ସରଳୀକୃତ - ଇନ୍ଦୋନେସିୟ [@Galang23 ଙ୍କ ଦ୍ୱାରା] - ଇତାଲିୟ [@RAR_Ramar ଙ୍କ‌ ଦ୍ୱାରା] - ଜର୍ମାନ [@peterge1998 ଙ୍କ ଦ୍ୱାରା] - ପୋଲିସ [@Lego8486 ଙ୍କ ଦ୍ୱାରା] - ତୁର୍କୀୟ [@faydin90 ଙ୍କ ଦ୍ୱାରା] - ବ୍ରାଜିଲିୟ ପ‍ର୍ତ୍ତୁଗୀଜ [@wagnim ଙ୍କ ଦ୍ୱାରା] - ପାରସୀ [@farzadx ଙ୍କ ଦ୍ୱାରା] - ମାସେଡ଼ୋନିୟ [@snajdovski ଙ୍କ ଦ୍ୱାରା] - ଭିଏତନାମୀୟ [@fouze555 ଙ୍କ ଦ୍ୱାରା] - ଚୀନୀ ପାରମ୍ପରିକ [@Still34 ଙ୍କ ଦ୍ୱାରା] - କାଟାଲାନ୍[@retiolus ଙ୍କ ଦ୍ୱାରା] - ରୁଷୀୟ[@rikishi0071 ଙ୍କ ଦ୍ୱାରା] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + ଇଂରାଜୀ + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] ସ୍ୱୟଂକ୍ରିୟ /ସିସ୍ଟମ ଅନୁସାରେ @@ -44,12 +27,6 @@ ଗାଢ ହାଲୁକା - - 0 - 1 - 2 - 3 - କିଛି ନୁହେଁ \@ @@ -58,53 +35,6 @@ \| - - - ଖୋଲୁଅଛି... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-pl/arrays.xml b/app/src/main/res/values-pl/arrays.xml index 1572e8b0..a66e5a7f 100644 --- a/app/src/main/res/values-pl/arrays.xml +++ b/app/src/main/res/values-pl/arrays.xml @@ -2,41 +2,24 @@ Język urządzenia - Angielski - Francuski [Podziękowania dla @kernoeb] - Hiszpański [Podziękowania dla @sguinetti] - Chiński uproszczony - Indonezyjski [Podziękowania dla @Galang23] - Włoski [Podziękowania dla @RAR_Ramar] - Niemiecki [Podziękowania dla @peterge1998] - Polski [Podziękowania dla @Lego8486] - Turecki [Podziękowania dla @faydin90] - Portugalski [Podziękowania dla @wagnim] - Perski [Podziękowania dla @farzadx] - Macedoński [Podziękowania dla @snajdovski] - Wietnamski [Podziękowania dla @fouze555] - Chiński Tradycyjny [Podziękowania dla @Still34] - Kataloński [Podziękowania dla @retiolus] - Rosyjski [Podziękowania dla @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Angielski + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Auto / Ustawienia systemu @@ -44,12 +27,6 @@ Ciemny Jasny - - 0 - 1 - 2 - 3 - Brak \@ @@ -58,53 +35,6 @@ \| - - - Ładowanie... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-pt/arrays.xml b/app/src/main/res/values-pt/arrays.xml index 61f30811..c4691bec 100644 --- a/app/src/main/res/values-pt/arrays.xml +++ b/app/src/main/res/values-pt/arrays.xml @@ -2,41 +2,24 @@ Padrão do Sistema - English - Français [Merci à @kernoeb] - Español [Gracias a @sguinetti y @akrai] - 简体中文 - Bahasa Indonesia [Terima kasih @Galang23] - Italiano [Grazie a @RAR_Ramar e Giorgio Arbato] - Deutsch [Danke an @peterge1998] - Polski [Podziękowania dla @Lego8486] - Türkçe [@faydin90 tarafından] - Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] - پارسی [ با سپاس از Frzking@ ] - Македонски [Благодарност до @snajdovski] - Tiếng Việt [bởi @fouze555] - 繁體中文 [感謝 @Still34] - Català [Gràcies a @retiolus] - Русский [Спасибо @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Automático (Definido pelo sistema) @@ -44,12 +27,6 @@ Escuro Claro - - 0 - 1 - 2 - 3 - Nenhum \@ @@ -58,53 +35,6 @@ \| - - - Carregando... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-ru/arrays.xml b/app/src/main/res/values-ru/arrays.xml index e5c09704..343c631f 100644 --- a/app/src/main/res/values-ru/arrays.xml +++ b/app/src/main/res/values-ru/arrays.xml @@ -2,41 +2,24 @@ Системный по умолчанию - Английский - Французский [Спасибо @kernoeb] - Испанский [Спасибо @sguinetti] - Китайский упрощённый - Индонезийский [Спасибо @Galang23] - Итальянский [Спасибо @RAR_Ramar] - Немецкий [Спасибо @peterge1998] - Польский [Спасибо @Lego8486] - Турецкий [Спасибо @faydin90] - Португальский (Бразилия) [Спасибо @wagnim] - Персидский [Спасибо @farzadx] - Македонский [Спасибо @snajdovski] - Вьетнамский [Спасибо @fouze555] - Китайский традиционный [Спасибо @Still34] - Каталонский - Русский - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Английский + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Автоматически / Оглядка на систему @@ -44,12 +27,6 @@ Тёмная Светлая - - 0 - 1 - 2 - 3 - Нет \@ @@ -58,53 +35,6 @@ \| - - - Загрузка... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-tr/arrays.xml b/app/src/main/res/values-tr/arrays.xml index e04150ef..b9028585 100644 --- a/app/src/main/res/values-tr/arrays.xml +++ b/app/src/main/res/values-tr/arrays.xml @@ -2,41 +2,24 @@ Sistem Varsayılanı - İngilizce - Fransızca [@kernoeb tarafından] - İspanyolca [@sguinetti tarafından] - Basitleştirilmiş Çince - Endonezyaca [@Galang23 tarafından] - İtalyaca [@RAR_Ramar tarafından] - Almanca [@peterge1998 tarafından] - Lehçe [@Lego8486 tarafından] - Türkçe [@faydin90 tarafından] - Brezilya Portekizce [@wagnim tarafından] - Farsça [@farzadx tarafından] - Makedonyaca [@snajdovski tarafından] - Vietnamca [@fouze555 sayesinde] - Geleneksel Çince [@Still34 tarafından] - Katalanca [@retiolus tarafından] - Rusça [@rikishi0071 tarafından] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + İngilizce + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Otomatik / Sistemi Takip Et @@ -44,12 +27,6 @@ Koyu Açık - - 0 - 1 - 2 - 3 - Hiçbiri \@ @@ -58,53 +35,6 @@ \| - - - Yükleniyor... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-vi/arrays.xml b/app/src/main/res/values-vi/arrays.xml index 1a37b5e8..c26f143f 100644 --- a/app/src/main/res/values-vi/arrays.xml +++ b/app/src/main/res/values-vi/arrays.xml @@ -2,41 +2,24 @@ Mặc định hệ thống - Tiếng Anh - Tiếng Pháp [bởi @kernoeb] - Tiếng Tây Ban Nha [bởi @sguinetti] - Tiếng Trung Giản thể - Tiếng Indonesia [bởi @Galang23] - Tiếng Ý [bởi @RAR_Ramar] - Tiếng Đức [bởi @peterge1998] - Tiếng Ba Lan [bởi @Lego8486] - Tiếng Thổ Nhĩ Kì [bởi @faydin90] - Tiếng Bồ Đào Nha [bởi @wagnim] - Tiếng Ba Tư [bởi @farzadx] - Tiếng Macedonia [bởi @snajdovski] - Tiếng Việt [bởi @fouze555] - Tiếng Trung truyền thống [bởi @Still34] - Tiếng Catalan [bởi @retiolus] - Tiếng Nga [bởi @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + Tiếng Anh + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] Tự động / Theo hệ thống @@ -44,12 +27,6 @@ Tối Sáng - - 0 - 1 - 2 - 3 - Không \@ @@ -58,53 +35,6 @@ \| - - - Đang tải... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-zh-rCN/arrays.xml b/app/src/main/res/values-zh-rCN/arrays.xml index f661ef76..81dda7b0 100644 --- a/app/src/main/res/values-zh-rCN/arrays.xml +++ b/app/src/main/res/values-zh-rCN/arrays.xml @@ -2,41 +2,24 @@ 系统默认 - 英文 - 法文 [感谢 @kernoeb] - 西班牙文 [感谢 @sguinetti] - 简体中文 - 印尼文 [感谢 @Galang23] - 意大利文 [感谢 @RAR_Ramar] - 德文 [感谢 @peterge1998] - 波兰文 [感谢 @Lego8486] - 土耳其文 [感谢 @faydin90] - 巴西葡文 [感谢 @wagnim] - 波斯文 [感谢 @farzadx] - 马其顿文 [感谢 @snajdovski] - 越南文 [感谢 @fouze555] - 繁体中文 [感谢 @Still34] - 加泰罗尼亚文 [感谢 @retiolus] - 俄文 [感谢 @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] 自动 / 跟随系统 @@ -44,12 +27,6 @@ 暗黑 明亮 - - 0 - 1 - 2 - 3 - \@ @@ -58,53 +35,6 @@ \| - - - 正在载入... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-zh-rTW/arrays.xml b/app/src/main/res/values-zh-rTW/arrays.xml index 06357b8e..e452576d 100644 --- a/app/src/main/res/values-zh-rTW/arrays.xml +++ b/app/src/main/res/values-zh-rTW/arrays.xml @@ -2,41 +2,24 @@ 系統預設 - 英文 - 法文 [感謝 @kernoeb] - 西班牙文 [感謝 @sguinetti] - 簡體中文 - 印尼文 [感謝 @Galang23] - 義大利文 [感謝 @RAR_Ramar] - 德文 [感謝 @peterge1998] - 波蘭文 [感謝 @Lego8486] - 土耳其文 [感謝 @faydin90] - 巴西葡萄牙文 [感謝 @wagnim] - 波斯文 [感謝 @farzadx] - 馬其頓文 [感謝 @snajdovski] - 越南文 [感謝 @fouze555] - 繁體中文 [感謝 @Still34] - Catalan [Thanks to @retiolus] - Russian [Thanks to @rikishi0071] - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 + English + Français [Merci à @kernoeb et @PierreM0] + Español [Gracias a @sguinetti, @akrai y @retiolus] + 简体中文 + Bahasa Indonesia [Terima kasih @Galang23] + Italiano [Grazie a @RAR_Ramar e GiorgioHerbie] + Deutsch [Danke an @peterge1998] + Polski [Podziękowania dla @Lego8486] + Türkçe [@faydin90 tarafından] + Português (Brasil) [Obrigado @wagnim, @RickyM7 e @cizordj] + پارسی [ با سپاس از farzadx@ ] + Македонски [Благодарност до @snajdovski] + Tiếng Việt [bởi Yato Fouze] + 繁體中文 [感謝 @Still34] + Català [Gràcies a @retiolus] + Русский [Спасибо @rikishi0071] + हिन्दी + Nederlands [Met dank aan Lesley Natrop] 自動/跟隨系統 @@ -44,12 +27,6 @@ 暗黑 明亮 - - 0 - 1 - 2 - 3 - \@ @@ -58,53 +35,6 @@ \| - - - 讀取中… - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - @string/title_dm @string/feed diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0fb9fc67..2089844b 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -292,10 +292,10 @@ 顯示大頭貼 大頭貼大小 邊角 - Show grid gap + 網格間保留間距 停用動畫 - Please wait for the current task to complete first! - Post not found! + 請先等候目前的工作完成! + 貼文不存在! No app found which opens urls %d 個讚 From c24fd016b14a64202f47bc3198ee50e6c1af7471 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 17 Dec 2020 15:13:41 -0500 Subject: [PATCH 004/101] rewrite stories backend, close #319, close #372, close #405 --- .../awais/instagrabber/asyncs/QuizAction.java | 89 -------- .../instagrabber/asyncs/RespondAction.java | 88 -------- .../awais/instagrabber/asyncs/VoteAction.java | 69 ------ .../fragments/StoryViewerFragment.java | 201 +++++++++++++++--- .../fragments/main/FeedFragment.java | 5 +- .../awais/instagrabber/models/StoryModel.java | 10 + .../models/stickers/SliderModel.java | 53 +++++ .../repositories/StoriesRepository.java | 20 +- .../responses/StoryStickerResponse.java | 20 ++ .../webservices/StoriesService.java | 129 +++++++++-- .../main/res/layout/fragment_story_viewer.xml | 10 + app/src/main/res/values/strings.xml | 6 + 12 files changed, 408 insertions(+), 292 deletions(-) delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/QuizAction.java delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/RespondAction.java delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/VoteAction.java create mode 100755 app/src/main/java/awais/instagrabber/models/stickers/SliderModel.java create mode 100644 app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java diff --git a/app/src/main/java/awais/instagrabber/asyncs/QuizAction.java b/app/src/main/java/awais/instagrabber/asyncs/QuizAction.java deleted file mode 100644 index 4042b875..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/QuizAction.java +++ /dev/null @@ -1,89 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import org.json.JSONObject; - -import java.io.DataOutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.UUID; - -import awais.instagrabber.models.StoryModel; -import awais.instagrabber.models.stickers.QuizModel; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.CookieUtils; -import awais.instagrabber.utils.Utils; - -import static awais.instagrabber.utils.Utils.settingsHelper; - -public class QuizAction extends AsyncTask { - private static final String TAG = "QuizAction"; - - private final StoryModel storyModel; - private final QuizModel quizModel; - private final String cookie; - private final OnTaskCompleteListener onTaskCompleteListener; - - public QuizAction(final StoryModel storyModel, - final QuizModel quizModel, - final String cookie, - final OnTaskCompleteListener onTaskCompleteListener) { - this.storyModel = storyModel; - this.quizModel = quizModel; - this.cookie = cookie; - this.onTaskCompleteListener = onTaskCompleteListener; - } - - protected Integer doInBackground(Integer... rawChoice) { - int choice = rawChoice[0]; - final String url = "https://i.instagram.com/api/v1/media/" + storyModel.getStoryMediaId().split("_")[0] + "/" + quizModel.getId() + "/story_quiz_answer/"; - HttpURLConnection urlConnection = null; - try { - JSONObject ogBody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString() - + "\",\"mutation_token\":\"" + UUID.randomUUID().toString() - + "\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] - + "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie) - + "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) - + "\"}"); - ogBody.put("answer", String.valueOf(choice)); - String urlParameters = Utils.sign(ogBody.toString()); - urlConnection = (HttpURLConnection) new URL(url).openConnection(); - urlConnection.setRequestMethod("POST"); - urlConnection.setUseCaches(false); - urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); - urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - if (urlParameters != null) { - urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); - } - urlConnection.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); - wr.writeBytes(urlParameters); - wr.flush(); - wr.close(); - Log.d(TAG, "quiz: " + url + " " + cookie + " " + urlParameters); - urlConnection.connect(); - if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - return choice; - } - } catch (Throwable ex) { - Log.e(TAG, "quiz: " + ex); - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - } - return -1; - } - - @Override - protected void onPostExecute(final Integer choice) { - if (onTaskCompleteListener == null || choice == null) return; - onTaskCompleteListener.onTaskComplete(choice); - } - - public interface OnTaskCompleteListener { - void onTaskComplete(final int choice); - } -} diff --git a/app/src/main/java/awais/instagrabber/asyncs/RespondAction.java b/app/src/main/java/awais/instagrabber/asyncs/RespondAction.java deleted file mode 100644 index 836d6b76..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/RespondAction.java +++ /dev/null @@ -1,88 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import org.json.JSONObject; - -import java.io.DataOutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.UUID; - -import awais.instagrabber.models.StoryModel; -import awais.instagrabber.models.stickers.QuestionModel; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.CookieUtils; -import awais.instagrabber.utils.Utils; - -import static awais.instagrabber.utils.Utils.settingsHelper; - -public class RespondAction extends AsyncTask { - - private final StoryModel storyModel; - private final QuestionModel questionModel; - private final String cookie; - private final OnTaskCompleteListener onTaskCompleteListener; - - public RespondAction(final StoryModel storyModel, - final QuestionModel questionModel, - final String cookie, - final OnTaskCompleteListener onTaskCompleteListener) { - this.storyModel = storyModel; - this.questionModel = questionModel; - this.cookie = cookie; - this.onTaskCompleteListener = onTaskCompleteListener; - } - - protected Boolean doInBackground(String... rawChoice) { - final String url = "https://i.instagram.com/api/v1/media/" - + storyModel.getStoryMediaId().split("_")[0] + "/" + questionModel.getId() + "/story_question_response/"; - HttpURLConnection urlConnection = null; - try { - final JSONObject ogbody = new JSONObject("{\"client_context\":\"" + UUID.randomUUID().toString() - + "\",\"mutation_token\":\"" + UUID.randomUUID().toString() - + "\",\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] - + "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie) - + "\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) - + "\"}"); - String choice = rawChoice[0].replaceAll("\"", ("\\\"")); - ogbody.put("response", choice); - String urlParameters = Utils.sign(ogbody.toString()); - urlConnection = (HttpURLConnection) new URL(url).openConnection(); - urlConnection.setRequestMethod("POST"); - urlConnection.setUseCaches(false); - urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); - urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); - urlConnection.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); - wr.writeBytes(urlParameters); - wr.flush(); - wr.close(); - urlConnection.connect(); - if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - return true; - } - - } catch (Throwable ex) { - Log.e("austin_debug", "respond: " + ex); - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - } - return null; - } - - @Override - protected void onPostExecute(final Boolean ok) { - if (onTaskCompleteListener == null) return; - onTaskCompleteListener.onTaskComplete(ok); - - } - - public interface OnTaskCompleteListener { - void onTaskComplete(final boolean result); - } -} diff --git a/app/src/main/java/awais/instagrabber/asyncs/VoteAction.java b/app/src/main/java/awais/instagrabber/asyncs/VoteAction.java deleted file mode 100644 index cfa91c77..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/VoteAction.java +++ /dev/null @@ -1,69 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import java.io.DataOutputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -import awais.instagrabber.models.StoryModel; -import awais.instagrabber.models.stickers.PollModel; -import awais.instagrabber.utils.Constants; - -public class VoteAction extends AsyncTask { - - private static final String TAG = "VoteAction"; - - private final StoryModel storyModel; - private final PollModel pollModel; - private final String cookie; - private final OnTaskCompleteListener onTaskCompleteListener; - - public VoteAction(final StoryModel storyModel, - final PollModel pollModel, - final String cookie, - final OnTaskCompleteListener onTaskCompleteListener) { - this.storyModel = storyModel; - this.pollModel = pollModel; - this.cookie = cookie; - this.onTaskCompleteListener = onTaskCompleteListener; - } - - protected Integer doInBackground(Integer... rawChoice) { - int choice = rawChoice[0]; - final String url = "https://www.instagram.com/media/" + storyModel.getStoryMediaId().split("_")[0] + "/" + pollModel.getId() + "/story_poll_vote/"; - try { - final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); - urlConnection.setRequestMethod("POST"); - urlConnection.setUseCaches(false); - urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT); - urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]); - urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - urlConnection.setRequestProperty("Content-Length", "6"); - urlConnection.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); - wr.writeBytes("vote=" + choice); - wr.flush(); - wr.close(); - urlConnection.connect(); - if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - return choice; - } - urlConnection.disconnect(); - } catch (Exception ex) { - Log.e(TAG, "Error", ex); - } - return -1; - } - - @Override - protected void onPostExecute(final Integer result) { - if (result == null || onTaskCompleteListener == null) return; - onTaskCompleteListener.onTaskComplete(result); - } - - public interface OnTaskCompleteListener { - void onTaskComplete(final int choice); - } -} diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 40f04fd3..1a90128c 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -11,6 +11,7 @@ import android.os.Handler; import android.util.Log; import android.util.Pair; import android.view.GestureDetector; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -20,6 +21,9 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -55,6 +59,7 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.text.NumberFormat; import java.util.Collections; import java.util.Date; import java.util.List; @@ -63,10 +68,7 @@ import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.adapters.StoriesAdapter; import awais.instagrabber.asyncs.PostFetcher; -import awais.instagrabber.asyncs.QuizAction; -import awais.instagrabber.asyncs.RespondAction; import awais.instagrabber.asyncs.SeenAction; -import awais.instagrabber.asyncs.VoteAction; import awais.instagrabber.asyncs.direct_messages.CreateThreadAction; import awais.instagrabber.asyncs.direct_messages.DirectThreadBroadcaster; import awais.instagrabber.customviews.helpers.SwipeGestureListener; @@ -80,7 +82,10 @@ import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.stickers.PollModel; import awais.instagrabber.models.stickers.QuestionModel; import awais.instagrabber.models.stickers.QuizModel; +import awais.instagrabber.models.stickers.SliderModel; +import awais.instagrabber.repositories.responses.StoryStickerResponse; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; @@ -117,13 +122,15 @@ public class StoryViewerFragment extends Fragment { private QuestionModel question; private String[] mentions; private QuizModel quiz; + private SliderModel slider; private MenuItem menuDownload; private MenuItem menuDm; private SimpleExoPlayer player; private boolean isHashtag, isLoc; private String highlight; - private boolean fetching = false; + private boolean fetching = false, sticking = false; private int currentFeedStoryIndex; + private double sliderValue; private StoriesViewModel storiesViewModel; private boolean shouldRefresh = true; private StoryViewerFragmentArgs fragmentArgs; @@ -190,7 +197,7 @@ public class StoryViewerFragment extends Fragment { new AlertDialog.Builder(context) .setTitle(R.string.reply_story) .setView(input) - .setPositiveButton(R.string.ok, (d, w) -> new CreateThreadAction(cookie, currentStory.getUserId(), threadId -> { + .setPositiveButton(R.string.confirm, (d, w) -> new CreateThreadAction(cookie, currentStory.getUserId(), threadId -> { try { final DirectThreadBroadcaster.StoryReplyBroadcastOptions options = new DirectThreadBroadcaster.StoryReplyBroadcastOptions( input.getText().toString(), @@ -273,6 +280,7 @@ public class StoryViewerFragment extends Fragment { @SuppressLint("ClickableViewAccessibility") private void setupListeners() { + final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); final boolean hasFeedStories; List models = null; if (currentFeedStoryIndex >= 0) { @@ -297,6 +305,10 @@ public class StoryViewerFragment extends Fragment { swipeEvent = isRightSwipe -> { final List storyModels = storiesViewModel.getList().getValue(); final int storiesLen = storyModels == null ? 0 : storyModels.size(); + if (sticking) { + Toast.makeText(context, R.string.follower_wait_to_load, Toast.LENGTH_SHORT).show(); + return; + } if (storiesLen <= 0) return; final boolean isLeftSwipe = !isRightSwipe; final boolean endOfCurrentStories = slidePos + 1 >= storiesLen; @@ -407,15 +419,30 @@ public class StoryViewerFragment extends Fragment { poll.getLeftChoice() + " (" + poll.getLeftCount() + ")", poll.getRightChoice() + " (" + poll.getRightCount() + ")" }), (d, w) -> { - if (!TextUtils.isEmpty(cookie)) - new VoteAction(currentStory, poll, cookie, choice -> { - if (choice > -1) { - poll.setMyChoice(choice); - Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show(); - return; - } - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - }).execute(w); + if (!TextUtils.isEmpty(cookie)) { + sticking = true; + storiesService.respondToPoll( + currentStory.getStoryMediaId().split("_")[0], + poll.getId(), + w, + userIdFromCookie, + CookieUtils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final StoryStickerResponse result) { + sticking = false; + poll.setMyChoice(w); + Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onFailure(final Throwable t) { + sticking = false; + Log.e(TAG, "Error responding", t); + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + } + }); + } }) .setPositiveButton(R.string.cancel, null) .show(); @@ -427,12 +454,29 @@ public class StoryViewerFragment extends Fragment { new AlertDialog.Builder(context) .setTitle(question.getQuestion()) .setView(input) - .setPositiveButton(R.string.ok, (d, w) -> new RespondAction(currentStory, question, cookie, result -> { - if (result) { - Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); - } else - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - }).execute(input.getText().toString())) + .setPositiveButton(R.string.confirm, (d, w) -> { + sticking = true; + storiesService.respondToQuestion( + currentStory.getStoryMediaId().split("_")[0], + question.getId(), + input.getText().toString(), + userIdFromCookie, + CookieUtils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final StoryStickerResponse result) { + sticking = false; + Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onFailure(final Throwable t) { + sticking = false; + Log.e(TAG, "Error responding", t); + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + } + }); + }) .setNegativeButton(R.string.cancel, null) .show(); } else if (tag instanceof String[]) { @@ -452,24 +496,119 @@ public class StoryViewerFragment extends Fragment { new AlertDialog.Builder(context) .setTitle(quiz.getMyChoice() > -1 ? getString(R.string.story_quizzed) : quiz.getQuestion()) .setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, choices), (d, w) -> { - if (quiz.getMyChoice() == -1 && !TextUtils.isEmpty(cookie)) - new QuizAction(currentStory, quiz, cookie, choice -> { - if (choice > -1) { - quiz.setMyChoice(choice); - Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); - return; - } - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - }).execute(w); + if (quiz.getMyChoice() == -1 && !TextUtils.isEmpty(cookie)) { + sticking = true; + storiesService.respondToQuiz( + currentStory.getStoryMediaId().split("_")[0], + quiz.getId(), + w, + userIdFromCookie, + CookieUtils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final StoryStickerResponse result) { + sticking = false; + quiz.setMyChoice(w); + Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onFailure(final Throwable t) { + sticking = false; + Log.e(TAG, "Error responding", t); + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + } + }); + } }) .setPositiveButton(R.string.cancel, null) .show(); + } else if (tag instanceof SliderModel) { + slider = (SliderModel) tag; + NumberFormat percentage = NumberFormat.getPercentInstance(); + percentage.setMaximumFractionDigits(2); + LinearLayout sliderView = new LinearLayout(context); + sliderView.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT)); + sliderView.setOrientation(LinearLayout.VERTICAL); + TextView tv = new TextView(context); + tv.setGravity(Gravity.CENTER_HORIZONTAL); + final SeekBar input = new SeekBar(context); + Double avg = slider.getAverage() * 100; + input.setProgress(avg.intValue()); + sliderView.addView(input); + sliderView.addView(tv); + if (slider.getMyChoice().isNaN() && slider.canVote()) { + input.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + sliderValue = progress / 100.0; + tv.setText(percentage.format(sliderValue)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + new AlertDialog.Builder(context) + .setTitle(TextUtils.isEmpty(slider.getQuestion()) ? slider.getEmoji() : slider.getQuestion()) + .setMessage(getResources().getQuantityString(R.plurals.slider_info, + slider.getVoteCount(), + slider.getVoteCount(), + percentage.format(slider.getAverage()))) + .setView(sliderView) + .setPositiveButton(R.string.confirm, (d, w) -> { + sticking = true; + storiesService.respondToSlider( + currentStory.getStoryMediaId().split("_")[0], + slider.getId(), + sliderValue, + userIdFromCookie, + CookieUtils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final StoryStickerResponse result) { + sticking = false; + slider.setMyChoice(sliderValue); + Toast.makeText(context, R.string.answered_story, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onFailure(final Throwable t) { + sticking = false; + Log.e(TAG, "Error responding", t); + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + } + }); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + } + else { + input.setEnabled(false); + tv.setText(getString(R.string.slider_answer, percentage.format(slider.getMyChoice()))); + new AlertDialog.Builder(context) + .setTitle(TextUtils.isEmpty(slider.getQuestion()) ? slider.getEmoji() : slider.getQuestion()) + .setMessage(getResources().getQuantityString(R.plurals.slider_info, + slider.getVoteCount(), + slider.getVoteCount(), + percentage.format(slider.getAverage()))) + .setView(sliderView) + .setPositiveButton(R.string.ok, null) + .show(); + } } }; binding.poll.setOnClickListener(storyActionListener); binding.answer.setOnClickListener(storyActionListener); binding.mention.setOnClickListener(storyActionListener); binding.quiz.setOnClickListener(storyActionListener); + binding.slider.setOnClickListener(storyActionListener); } private void resetView() { @@ -588,6 +727,10 @@ public class StoryViewerFragment extends Fragment { binding.quiz.setVisibility(quiz != null ? View.VISIBLE : View.GONE); binding.quiz.setTag(quiz); + slider = currentStory.getSlider(); + binding.slider.setVisibility(slider != null ? View.VISIBLE : View.GONE); + binding.slider.setTag(slider); + releasePlayer(); if (isHashtag || isLoc) { final ActionBar actionBar = fragmentActivity.getSupportActionBar(); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index afc14848..91fbb6f8 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -47,6 +47,7 @@ import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.viewmodels.FeedStoriesViewModel; @@ -55,6 +56,7 @@ import awais.instagrabber.webservices.StoriesService; import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; +import static awais.instagrabber.utils.Utils.settingsHelper; public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "FeedFragment"; @@ -367,9 +369,10 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre } private void fetchStories() { + final String cookie = settingsHelper.getString(Constants.COOKIE); storiesFetching = true; updateSwipeRefreshState(); - storiesService.getFeedStories(new ServiceCallback>() { + storiesService.getFeedStories(CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback>() { @Override public void onSuccess(final List result) { feedStoriesViewModel.getList().postValue(result); diff --git a/app/src/main/java/awais/instagrabber/models/StoryModel.java b/app/src/main/java/awais/instagrabber/models/StoryModel.java index 9d3959c8..c9615c8b 100755 --- a/app/src/main/java/awais/instagrabber/models/StoryModel.java +++ b/app/src/main/java/awais/instagrabber/models/StoryModel.java @@ -6,6 +6,7 @@ import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.stickers.PollModel; import awais.instagrabber.models.stickers.QuestionModel; import awais.instagrabber.models.stickers.QuizModel; +import awais.instagrabber.models.stickers.SliderModel; import awais.instagrabber.models.stickers.SwipeUpModel; public final class StoryModel implements Serializable { @@ -21,6 +22,7 @@ public final class StoryModel implements Serializable { private String spotify; private PollModel poll; private QuestionModel question; + private SliderModel slider; private QuizModel quiz; private SwipeUpModel swipeUp; private String[] mentions; @@ -71,6 +73,10 @@ public final class StoryModel implements Serializable { return question; } + public SliderModel getSlider() { + return slider; + } + public QuizModel getQuiz() { return quiz; } @@ -109,6 +115,10 @@ public final class StoryModel implements Serializable { this.question = question; } + public void setSlider(final SliderModel slider) { + this.slider = slider; + } + public void setQuiz(final QuizModel quiz) { this.quiz = quiz; } diff --git a/app/src/main/java/awais/instagrabber/models/stickers/SliderModel.java b/app/src/main/java/awais/instagrabber/models/stickers/SliderModel.java new file mode 100755 index 00000000..ff5c0f20 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/models/stickers/SliderModel.java @@ -0,0 +1,53 @@ +package awais.instagrabber.models.stickers; + +import java.io.Serializable; + +public final class SliderModel implements Serializable { + private final int voteCount; + private final Double average; + private Double myChoice; + private final boolean canVote; + private final String id, question, emoji; + + public SliderModel(final String id, final String question, final String emoji, final boolean canVote, + final Double average, final int voteCount, final Double myChoice) { + this.id = id; + this.question = question; + this.emoji = emoji; + this.canVote = canVote; + this.average = average; + this.voteCount = voteCount; + this.myChoice = myChoice; + } + + public String getId() { + return id; + } + + public String getQuestion() { + return question; + } + + public String getEmoji() { + return emoji; + } + + public boolean canVote() { + return canVote; + } + + public int getVoteCount() { + return voteCount; + } + + public Double getAverage() { + return average; + } + + public Double getMyChoice() { return myChoice; } + + public Double setMyChoice(final Double choice) { + this.myChoice = choice; + return choice; + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java index 42f262d6..8ed0da74 100644 --- a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java @@ -2,17 +2,33 @@ package awais.instagrabber.repositories; import java.util.Map; +import awais.instagrabber.repositories.responses.StoryStickerResponse; import retrofit2.Call; +import retrofit2.http.FieldMap; +import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.Header; +import retrofit2.http.Path; +import retrofit2.http.POST; import retrofit2.http.QueryMap; import retrofit2.http.Url; public interface StoriesRepository { - @GET("graphql/query/") - Call getStories(@QueryMap(encoded = true) Map variables); + @FormUrlEncoded + @POST("/api/v1/feed/reels_tray/") + Call getStories(@Header("User-Agent") String userAgent, + @FieldMap Map form); @GET Call getUserStory(@Header("User-Agent") String userAgent, @Url String url); + + @FormUrlEncoded + @POST("/api/v1/media/{storyId}/{stickerId}/{action}/") + Call respondToSticker(@Header("User-Agent") String userAgent, + @Path("storyId") String storyId, + @Path("stickerId") String stickerId, + @Path("action") String action, + // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer + @FieldMap Map form); } diff --git a/app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java b/app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java new file mode 100644 index 00000000..8ac2f4a9 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/responses/StoryStickerResponse.java @@ -0,0 +1,20 @@ +package awais.instagrabber.repositories.responses; + +public class StoryStickerResponse { + private final String status; + + public StoryStickerResponse(final String status) { + this.status = status; + } + + public String getStatus() { + return status; + } + + @Override + public String toString() { + return "StoryStickerResponse{" + + "status='" + status + '\'' + + '}'; + } +} diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index ecc657d1..c895a3fa 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.ProfileModel; @@ -26,9 +27,13 @@ import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.stickers.PollModel; import awais.instagrabber.models.stickers.QuestionModel; import awais.instagrabber.models.stickers.QuizModel; +import awais.instagrabber.models.stickers.SliderModel; +import awais.instagrabber.models.stickers.SwipeUpModel; import awais.instagrabber.repositories.StoriesRepository; +import awais.instagrabber.repositories.responses.StoryStickerResponse; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.ResponseBodyUtils; +import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -44,7 +49,7 @@ public class StoriesService extends BaseService { private StoriesService() { final Retrofit retrofit = getRetrofitBuilder() - .baseUrl("https://www.instagram.com") + .baseUrl("https://i.instagram.com") .build(); repository = retrofit.create(StoriesRepository.class); } @@ -56,7 +61,7 @@ public class StoriesService extends BaseService { return instance; } - public void getFeedStories(final ServiceCallback> callback) { + public void getFeedStories(final String csrfToken, final ServiceCallback> callback) { if (loadFromMock) { final Handler handler = new Handler(); handler.postDelayed(() -> { @@ -81,10 +86,13 @@ public class StoriesService extends BaseService { }, 1000); return; } - final Map queryMap = new HashMap<>(); - queryMap.put("query_hash", "b7b84d884400bc5aa7cfe12ae843a091"); - queryMap.put("variables", "{\"only_stories\":true,\"stories_prefetch\":false,\"stories_video_dash_manifest\":false}"); - final Call response = repository.getStories(queryMap); + final Map form = new HashMap<>(4); + form.put("reason", "cold_start"); + form.put("_csrftoken", csrfToken); + form.put("_uuid", UUID.randomUUID().toString()); + form.put("supported_capabilities_new", Constants.SUPPORTED_CAPABILITIES); + final Map signedForm = Utils.sign(form); + final Call response = repository.getStories(Constants.I_USER_AGENT, signedForm); response.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -106,17 +114,12 @@ public class StoriesService extends BaseService { private void parseStoriesBody(final String body, final ServiceCallback> callback) { try { final List feedStoryModels = new ArrayList<>(); - final JSONArray feedStoriesReel = new JSONObject(body) - .getJSONObject("data") - .getJSONObject(Constants.EXTRAS_USER) - .getJSONObject("feed_reels_tray") - .getJSONObject("edge_reels_tray_to_reel") - .getJSONArray("edges"); + final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray"); for (int i = 0; i < feedStoriesReel.length(); ++i) { - final JSONObject node = feedStoriesReel.getJSONObject(i).getJSONObject("node"); + final JSONObject node = feedStoriesReel.getJSONObject(i); final JSONObject user = node.getJSONObject(node.has("user") ? "user" : "owner"); final ProfileModel profileModel = new ProfileModel(false, false, false, - user.getString("id"), + user.getString("pk"), user.getString("username"), null, null, null, user.getString("profile_pic_url"), @@ -240,6 +243,27 @@ public class StoriesService extends BaseService { )); } } + if (data.has("story_cta") && data.has("link_text")) { + JSONObject tappableObject = data.getJSONArray("story_cta").getJSONObject(0).getJSONArray("links").getJSONObject(0); + String swipeUpUrl = tappableObject.getString("webUri"); + if (swipeUpUrl.startsWith("http")) { + model.setSwipeUp(new SwipeUpModel(swipeUpUrl, data.getString("link_text"))); + } + } + if (data.has("story_sliders")) { + final JSONObject tappableObject = data.getJSONArray("story_sliders").getJSONObject(0) + .optJSONObject("slider_sticker"); + if (tappableObject != null) + model.setSlider(new SliderModel( + String.valueOf(tappableObject.getLong("slider_id")), + tappableObject.getString("question"), + tappableObject.getString("emoji"), + tappableObject.getBoolean("viewer_can_vote"), + tappableObject.getDouble("slider_vote_average"), + tappableObject.getInt("slider_vote_count"), + tappableObject.optDouble("viewer_vote") + )); + } JSONArray hashtags = data.optJSONArray("story_hashtags"); JSONArray locations = data.optJSONArray("story_locations"); JSONArray atmarks = data.optJSONArray("reel_mentions"); @@ -283,6 +307,83 @@ public class StoriesService extends BaseService { }); } + private void respondToSticker(final String storyId, + final String stickerId, + final String action, + final String arg1, + final String arg2, + final String userId, + final String csrfToken, + final ServiceCallback callback) { + final Map form = new HashMap<>(); + form.put("_csrftoken", csrfToken); + form.put("_uid", userId); + form.put("_uuid", UUID.randomUUID().toString()); + form.put("mutation_token", UUID.randomUUID().toString()); + form.put("client_context", UUID.randomUUID().toString()); + form.put("radio_type", "wifi-none"); + form.put(arg1, arg2); + final Map signedForm = Utils.sign(form); + final Call request = + repository.respondToSticker(Constants.I_USER_AGENT, storyId, stickerId, action, signedForm); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, + @NonNull final Response response) { + if (callback != null) { + callback.onSuccess(response.body()); + } + } + + @Override + public void onFailure(@NonNull final Call call, + @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); + } + + // RespondAction.java + public void respondToQuestion(final String storyId, + final String stickerId, + final String answer, + final String userId, + final String csrfToken, + final ServiceCallback callback) { + respondToSticker(storyId, stickerId, "story_question_response", "response", answer, userId, csrfToken, callback); + } + + // QuizAction.java + public void respondToQuiz(final String storyId, + final String stickerId, + final int answer, + final String userId, + final String csrfToken, + final ServiceCallback callback) { + respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), userId, csrfToken, callback); + } + + // VoteAction.java + public void respondToPoll(final String storyId, + final String stickerId, + final int answer, + final String userId, + final String csrfToken, + final ServiceCallback callback) { + respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); + } + + public void respondToSlider(final String storyId, + final String stickerId, + final double answer, + final String userId, + final String csrfToken, + final ServiceCallback callback) { + respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); + } + private String buildUrl(final String id, final boolean isLoc, final boolean isHashtag, final boolean highlight) { final String userId = id.replace(":", "%3A"); final StringBuilder builder = new StringBuilder(); diff --git a/app/src/main/res/layout/fragment_story_viewer.xml b/app/src/main/res/layout/fragment_story_viewer.xml index fb16343a..d9893f08 100644 --- a/app/src/main/res/layout/fragment_story_viewer.xml +++ b/app/src/main/res/layout/fragment_story_viewer.xml @@ -85,6 +85,16 @@ android:visibility="gone" app:backgroundTint="@color/btn_blue_background" /> + + Respond Answer… Answer successful! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s Reply to story Reply… Quiz + Slider You have already answered! Mentions This Account is Private From 4157c113f8d5b27c369bc1c771d2147de03d33b9 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 17 Dec 2020 15:24:46 -0500 Subject: [PATCH 005/101] fix #317 --- .../notification_viewer_nav_graph.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/res/navigation/notification_viewer_nav_graph.xml b/app/src/main/res/navigation/notification_viewer_nav_graph.xml index 9a7f586f..162ab949 100644 --- a/app/src/main/res/navigation/notification_viewer_nav_graph.xml +++ b/app/src/main/res/navigation/notification_viewer_nav_graph.xml @@ -14,4 +14,23 @@ + + + + + + + + \ No newline at end of file From 3899b9adfad97823d99efcfd7b4a02dfb23fa372 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Fri, 18 Dec 2020 15:45:17 -0500 Subject: [PATCH 006/101] comments viewer improvement 1. Viewing parent comments is now paginated, no more long waits 2. Liking a comment will no longer refresh the entire comment list 3. The pink tint on liked comments from v18 is restored also removed FeedStoriesFetcher which was deprecated by c24fd01 --- .../adapters/CommentsAdapter.java | 16 +++- .../comments/ChildCommentViewHolder.java | 3 +- .../comments/ParentCommentViewHolder.java | 3 +- .../instagrabber/asyncs/CommentsFetcher.java | 52 +++++------ .../asyncs/FeedStoriesFetcher.java | 93 ------------------- .../fragments/CommentsViewerFragment.java | 70 +++++++++++--- .../instagrabber/models/CommentModel.java | 10 +- app/src/main/res/values/color.xml | 1 + 8 files changed, 106 insertions(+), 142 deletions(-) delete mode 100755 app/src/main/java/awais/instagrabber/asyncs/FeedStoriesFetcher.java diff --git a/app/src/main/java/awais/instagrabber/adapters/CommentsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/CommentsAdapter.java index e0ccb44e..d88e5f34 100755 --- a/app/src/main/java/awais/instagrabber/adapters/CommentsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/CommentsAdapter.java @@ -83,8 +83,8 @@ public final class CommentsAdapter extends ListAdapter> { private static final String TAG = "CommentsFetcher"; - private final String shortCode; + private final String shortCode, endCursor; private final FetchListener> fetchListener; - public CommentsFetcher(final String shortCode, final FetchListener> fetchListener) { + public CommentsFetcher(final String shortCode, final String endCursor, final FetchListener> fetchListener) { this.shortCode = shortCode; + this.endCursor = endCursor; this.fetchListener = fetchListener; } @@ -48,15 +49,17 @@ public final class CommentsFetcher extends AsyncTask commentModels = getParentComments(); - for (final CommentModel commentModel : commentModels) { - final List childCommentModels = commentModel.getChildCommentModels(); - if (childCommentModels != null) { - final int childCommentsLen = childCommentModels.size(); - final CommentModel lastChild = childCommentModels.get(childCommentsLen - 1); - if (lastChild != null && lastChild.hasNextPage() && !TextUtils.isEmpty(lastChild.getEndCursor())) { - final List remoteChildComments = getChildComments(commentModel.getId()); - commentModel.setChildCommentModels(remoteChildComments); - lastChild.setPageCursor(false, null); + if (commentModels != null) { + for (final CommentModel commentModel : commentModels) { + final List childCommentModels = commentModel.getChildCommentModels(); + if (childCommentModels != null) { + final int childCommentsLen = childCommentModels.size(); + final CommentModel lastChild = childCommentModels.get(childCommentsLen - 1); + if (lastChild != null && lastChild.hasNextPage() && !TextUtils.isEmpty(lastChild.getEndCursor())) { + final List remoteChildComments = getChildComments(commentModel.getId()); + commentModel.setChildCommentModels(remoteChildComments); + lastChild.setPageCursor(false, null); + } } } } @@ -76,11 +79,10 @@ public final class CommentsFetcher extends AsyncTask getChildComments(final String commentId) { final List commentModels = new ArrayList<>(); - String endCursor = ""; - while (endCursor != null) { + String childEndCursor = ""; + while (childEndCursor != null) { final String url = "https://www.instagram.com/graphql/query/?query_hash=51fdd02b67508306ad4484ff574a0b62&variables=" + - "{\"comment_id\":\"" + commentId + "\",\"first\":50,\"after\":\"" + endCursor + "\"}"; - + "{\"comment_id\":\"" + commentId + "\",\"first\":50,\"after\":\"" + childEndCursor + "\"}"; try { final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); conn.setUseCaches(false); @@ -93,8 +95,8 @@ public final class CommentsFetcher extends AsyncTask getParentComments() { final List commentModels = new ArrayList<>(); - String endCursor = ""; - while (endCursor != null) { final String url = "https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables=" + - "{\"shortcode\":\"" + shortCode + "\",\"first\":50,\"after\":\"" + endCursor + "\"}"; - - try { + "{\"shortcode\":\"" + shortCode + "\",\"first\":50,\"after\":\"" + endCursor.replace("\"", "\\\"") + "\"}"; + try { final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); conn.setUseCaches(false); conn.connect(); - if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) break; + if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) return null; else { final JSONObject parentComments = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data") .getJSONObject("shortcode_media") @@ -170,8 +169,7 @@ public final class CommentsFetcher extends AsyncTask("commentModelsList.size", commentModels.size())); if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - break; + return null; } - } return commentModels; } } diff --git a/app/src/main/java/awais/instagrabber/asyncs/FeedStoriesFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/FeedStoriesFetcher.java deleted file mode 100755 index c975dc5d..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/FeedStoriesFetcher.java +++ /dev/null @@ -1,93 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.net.HttpURLConnection; -import java.net.URL; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.models.FeedStoryModel; -import awais.instagrabber.models.ProfileModel; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.NetworkUtils; -import awaisomereport.LogCollector.LogFile; - -import static awais.instagrabber.utils.Utils.logCollector; - -public final class FeedStoriesFetcher extends AsyncTask { - private final FetchListener fetchListener; - - public FeedStoriesFetcher(final FetchListener fetchListener) { - this.fetchListener = fetchListener; - } - - @Override - protected FeedStoryModel[] doInBackground(final Void... voids) { - FeedStoryModel[] result = null; - String url = "https://www.instagram.com/graphql/query/?query_hash=b7b84d884400bc5aa7cfe12ae843a091&variables=" + - "{\"only_stories\":true,\"stories_prefetch\":false,\"stories_video_dash_manifest\":false}"; - - try { - HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); - conn.setInstanceFollowRedirects(false); - conn.setUseCaches(false); - conn.connect(); - - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - final JSONArray feedStoriesReel = new JSONObject(NetworkUtils.readFromConnection(conn)) - .getJSONObject("data") - .getJSONObject(Constants.EXTRAS_USER) - .getJSONObject("feed_reels_tray") - .getJSONObject("edge_reels_tray_to_reel") - .getJSONArray("edges"); - - conn.disconnect(); - - final int storiesLen = feedStoriesReel.length(); - final FeedStoryModel[] feedStoryModels = new FeedStoryModel[storiesLen]; - final String[] feedStoryIDs = new String[storiesLen]; - - for (int i = 0; i < storiesLen; ++i) { - final JSONObject node = feedStoriesReel.getJSONObject(i).getJSONObject("node"); - - final JSONObject user = node.getJSONObject(node.has("user") ? "user" : "owner"); - final ProfileModel profileModel = new ProfileModel(false, false, false, - user.getString("id"), - user.getString("username"), - null, null, null, - user.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); - - final String id = node.getString("id"); - final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == node.getLong("latest_reel_media"); - feedStoryIDs[i] = id; - feedStoryModels[i] = new FeedStoryModel(id, profileModel, fullyRead); - } - result = feedStoryModels; - } - - conn.disconnect(); - } catch (final Exception e) { - if (logCollector != null) - logCollector.appendException(e, LogFile.ASYNC_FEED_STORY_FETCHER, "doInBackground"); - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - } - - return result; - } - - @Override - protected void onPreExecute() { - if (fetchListener != null) fetchListener.doBefore(); - } - - @Override - protected void onPostExecute(final FeedStoryModel[] result) { - if (fetchListener != null) fetchListener.onResult(result); - } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java index c716c989..f39b2ea1 100644 --- a/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java @@ -32,11 +32,18 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.adapters.CommentsAdapter; import awais.instagrabber.asyncs.CommentsFetcher; +import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.FragmentCommentsBinding; import awais.instagrabber.dialogs.ProfilePicDialogFragment; +import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.CommentModel; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.utils.Constants; @@ -56,8 +63,9 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl private CommentsAdapter commentsAdapter; private FragmentCommentsBinding binding; - private String shortCode; - private String userId; + private LinearLayoutManager layoutManager; + private RecyclerLazyLoader lazyLoader; + private String shortCode, userId, endCursor = null; private Resources resources; private InputMethodManager imm; private AppCompatActivity fragmentActivity; @@ -65,8 +73,30 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl private boolean shouldRefresh = true; private MediaService mediaService; private String postId; + private AsyncTask> currentlyRunning; private CommentsViewModel commentsViewModel; + private final FetchListener> fetchListener = new FetchListener>() { + @Override + public void doBefore() { + binding.swipeRefreshLayout.setRefreshing(true); + } + + @Override + public void onResult(final List commentModels) { + endCursor = commentModels.get(0).getEndCursor(); + if (commentModels != null && commentModels.size() > 0) { + List list = commentsViewModel.getList().getValue(); + list = list != null ? new LinkedList<>(list) : new LinkedList<>(); + // final int oldSize = list != null ? list.size() : 0; + list.addAll(commentModels); + commentsViewModel.getList().postValue(list); + } + binding.swipeRefreshLayout.setRefreshing(false); + stopCurrentExecutor(); + } + }; + private final CommentsAdapter.CommentCallback commentCallback = new CommentsAdapter.CommentCallback() { @Override public void onClick(final CommentModel comment) { @@ -181,11 +211,11 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl @Override public void onRefresh() { - binding.swipeRefreshLayout.setRefreshing(true); - new CommentsFetcher(shortCode, commentModels -> { - commentsViewModel.getList().postValue(commentModels); - binding.swipeRefreshLayout.setRefreshing(false); - }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + endCursor = null; + lazyLoader.resetState(); + commentsViewModel.getList().postValue(Collections.emptyList()); + stopCurrentExecutor(); + currentlyRunning = new CommentsFetcher(shortCode, "", fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } private void init() { @@ -198,7 +228,8 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl binding.swipeRefreshLayout.setOnRefreshListener(this); binding.swipeRefreshLayout.setRefreshing(true); commentsViewModel = new ViewModelProvider(this).get(CommentsViewModel.class); - binding.rvComments.setLayoutManager(new LinearLayoutManager(getContext())); + layoutManager = new LinearLayoutManager(getContext()); + binding.rvComments.setLayoutManager(layoutManager); commentsAdapter = new CommentsAdapter(commentCallback); binding.rvComments.setAdapter(commentsAdapter); commentsViewModel.getList().observe(getViewLifecycleOwner(), commentsAdapter::submitList); @@ -226,6 +257,13 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl }); binding.commentField.setEndIconOnClickListener(newCommentListener); } + lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { + if (!TextUtils.isEmpty(endCursor)) + currentlyRunning = new CommentsFetcher(shortCode, endCursor, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + endCursor = null; + }); + binding.rvComments.addOnScrollListener(lazyLoader); + stopCurrentExecutor(); onRefresh(); } @@ -301,8 +339,6 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl Utils.copyText(context, "@" + profileModel.getUsername() + ": " + commentModel.getText()); break; case 3: // reply to comment - // final View focus = binding.rvComments.findViewWithTag(commentModel); - // focus.setBackgroundColor(0x80888888); commentsAdapter.setSelected(commentModel); String mention = "@" + profileModel.getUsername() + " "; binding.commentText.setText(mention); @@ -326,7 +362,7 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); return; } - onRefresh(); + commentsAdapter.setLiked(commentModel, true); } @Override @@ -344,7 +380,7 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); return; } - onRefresh(); + commentsAdapter.setLiked(commentModel, false); } @Override @@ -389,4 +425,14 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl final NavDirections action = CommentsViewerFragmentDirections.actionGlobalProfileFragment(username); NavHostFragment.findNavController(this).navigate(action); } + + private void stopCurrentExecutor() { + if (currentlyRunning != null) { + try { + currentlyRunning.cancel(true); + } catch (final Exception e) { + if (BuildConfig.DEBUG) Log.e(TAG, "", e); + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/models/CommentModel.java b/app/src/main/java/awais/instagrabber/models/CommentModel.java index 9ce02bb0..c66f6916 100755 --- a/app/src/main/java/awais/instagrabber/models/CommentModel.java +++ b/app/src/main/java/awais/instagrabber/models/CommentModel.java @@ -11,11 +11,10 @@ public class CommentModel { private final ProfileModel profileModel; private final String id; private final String text; - private final long likes; + private long likes; private final long timestamp; private List childCommentModels; - private final boolean liked; - private boolean hasNextPage; + private boolean liked, hasNextPage; private String endCursor; public CommentModel(final String id, @@ -53,6 +52,11 @@ public class CommentModel { return liked; } + public void setLiked(boolean liked) { + this.likes = liked ? likes + 1 : likes - 1; + this.liked = liked; + } + public ProfileModel getProfileModel() { return profileModel; } diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml index c59baf9a..b46d1762 100755 --- a/app/src/main/res/values/color.xml +++ b/app/src/main/res/values/color.xml @@ -31,6 +31,7 @@ #efefef #888888 + #40FF69B4 #FFFFFF #80FFFFFF From 8240829fa81586c0064b7d9368ccae0e920cba47 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 19 Dec 2020 16:59:09 -0500 Subject: [PATCH 007/101] fix #385, fix #417, fix #429, cleanup, prep for splash --- .../viewholder/PostViewerViewHolder.java | 240 ------------------ .../fragments/PostViewV2Fragment.java | 1 + .../fragments/StoryViewerFragment.java | 8 +- .../fragments/main/FeedFragment.java | 7 +- app/src/main/res/drawable/launch.xml | 5 + app/src/main/res/drawable/launch_dark.xml | 5 + app/src/main/res/values-night/styles.xml | 5 + app/src/main/res/values/color.xml | 5 - app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 8 + 10 files changed, 37 insertions(+), 248 deletions(-) delete mode 100644 app/src/main/java/awais/instagrabber/adapters/viewholder/PostViewerViewHolder.java create mode 100644 app/src/main/res/drawable/launch.xml create mode 100644 app/src/main/res/drawable/launch_dark.xml diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/PostViewerViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/PostViewerViewHolder.java deleted file mode 100644 index dcb2f9fc..00000000 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/PostViewerViewHolder.java +++ /dev/null @@ -1,240 +0,0 @@ -// package awais.instagrabber.adapters.viewholder; -// -// import android.content.res.ColorStateList; -// import android.content.res.Resources; -// import android.util.Log; -// import android.view.View; -// import android.widget.TextView; -// -// import androidx.annotation.NonNull; -// import androidx.core.content.ContextCompat; -// import androidx.core.view.ViewCompat; -// import androidx.recyclerview.widget.RecyclerView; -// import androidx.viewpager2.widget.ViewPager2; -// -// import com.google.android.exoplayer2.Player; -// import com.google.android.exoplayer2.SimpleExoPlayer; -// import com.google.android.exoplayer2.ui.PlayerView; -// -// import java.util.ArrayList; -// import java.util.List; -// -// import awais.instagrabber.R; -// import awais.instagrabber.adapters.PostViewAdapter.OnPostCaptionLongClickListener; -// import awais.instagrabber.adapters.PostViewAdapter.OnPostViewChildViewClickListener; -// import awais.instagrabber.adapters.PostViewerChildAdapter; -// import awais.instagrabber.databinding.ItemFullPostViewBinding; -// import awais.instagrabber.interfaces.MentionClickListener; -// import awais.instagrabber.models.PostChild; -// import awais.instagrabber.models.ProfileModel; -// import awais.instagrabber.models.ViewerPostModel; -// import awais.instagrabber.models.ViewerPostModelWrapper; -// import awais.instagrabber.models.enums.MediaItemType; -// import awais.instagrabber.utils.TextUtils; -// import awais.instagrabber.utils.Utils; -// -// public class PostViewerViewHolder extends RecyclerView.ViewHolder { -// private static final String TAG = "PostViewerViewHolder"; -// -// private final ItemFullPostViewBinding binding; -// private int currentChildPosition; -// -// public PostViewerViewHolder(@NonNull final ItemFullPostViewBinding binding) { -// super(binding.getRoot()); -// this.binding = binding; -// binding.topPanel.viewStoryPost.setVisibility(View.GONE); -// } -// -// public void bind(final ViewerPostModelWrapper wrapper, -// final int position, -// final OnPostViewChildViewClickListener clickListener, -// final OnPostCaptionLongClickListener longClickListener, -// final MentionClickListener mentionClickListener) { -// if (wrapper == null) return; -// final List items = wrapper.getViewerPostModels(); -// if (items == null || items.size() == 0) return; -// if (items.get(0) == null) return; -// final PostViewerChildAdapter adapter = new PostViewerChildAdapter(); -// binding.mediaViewPager.setAdapter(adapter); -// final PostChild firstPost = items.get(0); -// setPostInfo(firstPost, mentionClickListener); -// setMediaItems(items, adapter); -// setupListeners(wrapper, -// position, -// clickListener, -// longClickListener, -// mentionClickListener, -// firstPost.getLocation()); -// } -// -// private void setPostInfo(final PostChild firstPost, -// final MentionClickListener mentionClickListener) { -// final ProfileModel profileModel = firstPost.getProfileModel(); -// if (profileModel == null) return; -// binding.topPanel.title.setText(profileModel.getUsername()); -// final String locationName = firstPost.getLocationName(); -// if (!TextUtils.isEmpty(locationName)) { -// binding.topPanel.location.setVisibility(View.VISIBLE); -// binding.topPanel.location.setText(locationName); -// } else binding.topPanel.location.setVisibility(View.GONE); -// binding.topPanel.ivProfilePic.setImageURI(profileModel.getSdProfilePic()); -// binding.bottomPanel.commentsCount.setText(String.valueOf(firstPost.getCommentsCount())); -// final CharSequence postCaption = firstPost.getPostCaption(); -// if (TextUtils.hasMentions(postCaption)) { -// binding.bottomPanel.viewerCaption.setMentionClickListener(mentionClickListener); -// binding.bottomPanel.viewerCaption -// .setText(TextUtils.getMentionText(postCaption), TextView.BufferType.SPANNABLE); -// } else { -// binding.bottomPanel.viewerCaption.setMentionClickListener(null); -// binding.bottomPanel.viewerCaption.setText(postCaption); -// } -// binding.bottomPanel.tvPostDate.setText(firstPost.getPostDate()); -// setupLikes(firstPost); -// setupSave(firstPost); -// } -// -// private void setupLikes(final ViewerPostModel firstPost) { -// final boolean liked = firstPost.getLike(); -// final long likeCount = firstPost.getLikes(); -// final Resources resources = itemView.getContext().getResources(); -// if (liked) { -// final String unlikeString = resources.getString(R.string.unlike, String.valueOf(likeCount)); -// binding.btnLike.setText(unlikeString); -// ViewCompat.setBackgroundTintList(binding.btnLike, -// ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_pink_background))); -// } else { -// final String likeString = resources.getString(R.string.like, String.valueOf(likeCount)); -// binding.btnLike.setText(likeString); -// ViewCompat.setBackgroundTintList(binding.btnLike, -// ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_lightpink_background))); -// } -// } -// -// private void setupSave(final ViewerPostModel firstPost) { -// final boolean saved = firstPost.isSaved(); -// if (saved) { -// binding.btnBookmark.setText(R.string.unbookmark); -// ViewCompat.setBackgroundTintList(binding.btnBookmark, -// ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_orange_background))); -// } else { -// binding.btnBookmark.setText(R.string.bookmark); -// ViewCompat.setBackgroundTintList( -// binding.btnBookmark, -// ColorStateList.valueOf(ContextCompat.getColor(itemView.getContext(), R.color.btn_lightorange_background))); -// } -// } -// -// private void setupListeners(final ViewerPostModelWrapper wrapper, -// final int position, -// final OnPostViewChildViewClickListener clickListener, -// final OnPostCaptionLongClickListener longClickListener, -// final MentionClickListener mentionClickListener, -// final String location) { -// final View.OnClickListener onClickListener = v -> clickListener -// .onClick(v, wrapper, position, currentChildPosition); -// binding.bottomPanel.btnComments.setOnClickListener(onClickListener); -// binding.topPanel.title.setOnClickListener(onClickListener); -// binding.topPanel.ivProfilePic.setOnClickListener(onClickListener); -// binding.bottomPanel.btnDownload.setOnClickListener(onClickListener); -// binding.bottomPanel.viewerCaption.setOnClickListener(onClickListener); -// binding.btnLike.setOnClickListener(onClickListener); -// binding.btnBookmark.setOnClickListener(onClickListener); -// binding.bottomPanel.viewerCaption.setOnLongClickListener(v -> { -// longClickListener.onLongClick(binding.bottomPanel.viewerCaption.getText().toString()); -// return true; -// }); -// if (!TextUtils.isEmpty(location)) { -// binding.topPanel.location.setOnClickListener(v -> mentionClickListener -// .onClick(binding.topPanel.location, location, false, true)); -// } -// } -// -// private void setMediaItems(final List items, -// final PostViewerChildAdapter adapter) { -// final List filteredList = new ArrayList<>(); -// for (final ViewerPostModel model : items) { -// final MediaItemType itemType = model.getItemType(); -// if (itemType == MediaItemType.MEDIA_TYPE_VIDEO || itemType == MediaItemType.MEDIA_TYPE_IMAGE) { -// filteredList.add(model); -// } -// } -// binding.mediaCounter.setVisibility(filteredList.size() > 1 ? View.VISIBLE : View.GONE); -// final String counter = "1/" + filteredList.size(); -// binding.mediaCounter.setText(counter); -// adapter.submitList(filteredList); -// binding.mediaViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { -// @Override -// public void onPageSelected(final int position) { -// if (filteredList.size() <= 0 || position >= filteredList.size()) return; -// currentChildPosition = position; -// final String counter = (position + 1) + "/" + filteredList.size(); -// binding.mediaCounter.setText(counter); -// final ViewerPostModel viewerPostModel = filteredList.get(position); -// if (viewerPostModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) { -// setVideoDetails(viewerPostModel); -// setVolumeListener(position); -// return; -// } -// setImageDetails(); -// } -// }); -// } -// -// private void setVolumeListener(final int position) { -// binding.bottomPanel.btnMute.setOnClickListener(v -> { -// try { -// final RecyclerView.ViewHolder viewHolder = ((RecyclerView) binding.mediaViewPager -// .getChildAt(0)).findViewHolderForAdapterPosition(position); -// if (viewHolder != null) { -// final View itemView = viewHolder.itemView; -// if (itemView instanceof PlayerView) { -// final SimpleExoPlayer player = (SimpleExoPlayer) ((PlayerView) itemView) -// .getPlayer(); -// if (player == null) return; -// final float vol = player.getVolume() == 0f ? 1f : 0f; -// player.setVolume(vol); -// binding.bottomPanel.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 -// : R.drawable.ic_volume_off_24); -// Utils.sessionVolumeFull = vol == 1f; -// } -// } -// } catch (Exception e) { -// Log.e(TAG, "Error", e); -// } -// }); -// } -// -// private void setImageDetails() { -// binding.bottomPanel.btnMute.setVisibility(View.GONE); -// binding.bottomPanel.videoViewsContainer.setVisibility(View.GONE); -// } -// -// private void setVideoDetails(final ViewerPostModel viewerPostModel) { -// binding.bottomPanel.btnMute.setVisibility(View.VISIBLE); -// final long videoViews = viewerPostModel.getVideoViews(); -// if (videoViews < 0) { -// binding.bottomPanel.videoViewsContainer.setVisibility(View.GONE); -// return; -// } -// binding.bottomPanel.tvVideoViews.setText(String.valueOf(videoViews)); -// binding.bottomPanel.videoViewsContainer.setVisibility(View.VISIBLE); -// } -// -// public void stopPlayingVideo() { -// try { -// final RecyclerView.ViewHolder viewHolder = ((RecyclerView) binding.mediaViewPager -// .getChildAt(0)).findViewHolderForAdapterPosition(currentChildPosition); -// if (viewHolder != null) { -// final View itemView = viewHolder.itemView; -// if (itemView instanceof PlayerView) { -// final Player player = ((PlayerView) itemView).getPlayer(); -// if (player != null) { -// player.setPlayWhenReady(false); -// } -// } -// } -// } catch (Exception e) { -// Log.e(TAG, "Error", e); -// } -// } -// } diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 4b77b6e3..ad1fd41d 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -306,6 +306,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { @Override public void onDestroyView() { super.onDestroyView(); + if (feedModel == null) return; switch (feedModel.getItemType()) { case MEDIA_TYPE_VIDEO: if (videoPlayerViewHelper != null) { diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index 1a90128c..6c1fd576 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -612,6 +612,7 @@ public class StoryViewerFragment extends Fragment { } private void resetView() { + final Context context = getContext(); slidePos = 0; lastSlidePos = 0; if (menuDownload != null) menuDownload.setVisible(false); @@ -623,7 +624,10 @@ public class StoryViewerFragment extends Fragment { if (isHighlight) { final HighlightsViewModel highlightsViewModel = (HighlightsViewModel) viewModel; final List models = highlightsViewModel.getList().getValue(); - if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size()) return; + if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size()) { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + return; + } final HighlightModel model = models.get(currentFeedStoryIndex); currentStoryMediaId = model.getId(); currentStoryUsername = model.getTitle(); @@ -683,7 +687,7 @@ public class StoryViewerFragment extends Fragment { private void refreshStory() { if (binding.storiesList.getVisibility() == View.VISIBLE) { final List storyModels = storiesViewModel.getList().getValue(); - if (storyModels != null) { + if (storyModels != null && storyModels.size() > 0) { StoryModel item = storyModels.get(lastSlidePos); if (item != null) { item.setCurrentSlide(false); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index 91fbb6f8..f562770a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -12,6 +12,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedDispatcher; @@ -311,9 +312,13 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre @Override public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - final boolean granted = grantResults[0] == PackageManager.PERMISSION_GRANTED; + final boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; final Context context = getContext(); if (context == null) return; + if (!granted) { + Toast.makeText(context, R.string.download_permission, Toast.LENGTH_SHORT).show(); + return; + } if (requestCode == STORAGE_PERM_REQUEST_CODE && granted) { if (downloadFeedModel == null) return; DownloadUtils.showDownloadDialog(context, downloadFeedModel, downloadChildPosition); diff --git a/app/src/main/res/drawable/launch.xml b/app/src/main/res/drawable/launch.xml new file mode 100644 index 00000000..c34eafaa --- /dev/null +++ b/app/src/main/res/drawable/launch.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/launch_dark.xml b/app/src/main/res/drawable/launch_dark.xml new file mode 100644 index 00000000..d436940f --- /dev/null +++ b/app/src/main/res/drawable/launch_dark.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml index e5fbb438..aa7d71de 100755 --- a/app/src/main/res/values-night/styles.xml +++ b/app/src/main/res/values-night/styles.xml @@ -1,5 +1,10 @@ + + --> + + --> From 4d6ac5d2939b1f88f71d3c762507c3d9d71a43ff Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sat, 19 Dec 2020 21:38:21 -0500 Subject: [PATCH 008/101] profile viewer improvement 1. restore tagged posts access for anons 2. chip-ify profile viewer, bring it to consistency with tag/loc viewers 3. add a following/er status chip 4. pluralize "post(s)" and "follower(s)" 5. correct favourited string --- .../instagrabber/asyncs/CommentsFetcher.java | 3 + .../instagrabber/asyncs/PostFetcher.java | 1 + .../instagrabber/asyncs/ProfileFetcher.java | 1 + .../asyncs/SavedPostFetchService.java | 2 +- .../fragments/HashTagFragment.java | 4 +- .../fragments/LocationFragment.java | 5 +- .../fragments/main/ProfileFragment.java | 200 ++++++++++-------- .../instagrabber/models/HashtagModel.java | 2 +- .../instagrabber/models/LocationModel.java | 2 +- .../instagrabber/models/ProfileModel.java | 31 +-- .../repositories/ProfileRepository.java | 3 - .../instagrabber/utils/ResponseBodyUtils.java | 10 +- .../webservices/DiscoverService.java | 1 + .../webservices/ProfileService.java | 181 +++++----------- .../webservices/StoriesService.java | 2 +- .../res/layout/layout_profile_details.xml | 132 +++++++----- app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 16 +- 18 files changed, 301 insertions(+), 296 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java index 77ab5371..4876e3e3 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/CommentsFetcher.java @@ -122,6 +122,7 @@ public final class CommentsFetcher extends AsyncTask { owner.optInt("edge_followed_by"), -1, owner.optBoolean("followed_by_viewer"), + false, owner.optBoolean("restricted_by_viewer"), owner.optBoolean("blocked_by_viewer"), owner.optBoolean("requested_by_viewer") diff --git a/app/src/main/java/awais/instagrabber/asyncs/ProfileFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/ProfileFetcher.java index e2e4fe2c..7e78b0b2 100755 --- a/app/src/main/java/awais/instagrabber/asyncs/ProfileFetcher.java +++ b/app/src/main/java/awais/instagrabber/asyncs/ProfileFetcher.java @@ -72,6 +72,7 @@ public final class ProfileFetcher extends AsyncTask { user.getJSONObject("edge_followed_by").getLong("count"), user.getJSONObject("edge_follow").getLong("count"), user.optBoolean("followed_by_viewer"), + user.optBoolean("follows_viewer"), user.optBoolean("restricted_by_viewer"), user.optBoolean("blocked_by_viewer"), user.optBoolean("requested_by_viewer")); diff --git a/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java index 36c668d1..fcae9b65 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java @@ -50,7 +50,7 @@ public class SavedPostFetchService implements PostFetcher.PostFetchService { profileService.fetchLiked(nextMaxId, callback); break; case TAGGED: - profileService.fetchTagged(profileId, nextMaxId, callback); + profileService.fetchTagged(profileId, 30, nextMaxId, callback); break; case SAVED: default: diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 26733e12..c89f7970 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -513,7 +513,9 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe })); hashtagDetailsBinding.mainHashtagImage.setImageURI(hashtagModel.getSdProfilePic()); final String postCount = String.valueOf(hashtagModel.getPostCount()); - final SpannableStringBuilder span = new SpannableStringBuilder(getString(R.string.main_posts_count_inline, postCount)); + final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, + hashtagModel.getPostCount() > 2000000000L ? 2000000000 : hashtagModel.getPostCount().intValue(), + postCount)); span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); hashtagDetailsBinding.mainTagPostCount.setText(span); diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index acccc0b9..d857c083 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -400,8 +400,9 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR // binding.swipeRefreshLayout.setRefreshing(true); locationDetailsBinding.mainLocationImage.setImageURI(locationModel.getSdProfilePic()); final String postCount = String.valueOf(locationModel.getPostCount()); - final SpannableStringBuilder span = new SpannableStringBuilder(getString(R.string.main_posts_count_inline, - postCount)); + final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, + locationModel.getPostCount() > 2000000000L ? 2000000000 : locationModel.getPostCount().intValue(), + postCount)); span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); locationDetailsBinding.mainLocPostCount.setText(span); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 4c12b4e3..180f6e25 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -370,10 +370,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } if (item.getItemId() == R.id.restrict) { if (!isLoggedIn) return false; - final String action = profileModel.getRestricted() ? "Unrestrict" : "Restrict"; + final String action = profileModel.isRestricted() ? "Unrestrict" : "Restrict"; friendshipService.toggleRestrict( profileModel.getId(), - !profileModel.getRestricted(), + !profileModel.isRestricted(), CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback() { @Override @@ -392,7 +392,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe if (item.getItemId() == R.id.block) { final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); if (!isLoggedIn) return false; - if (profileModel.getBlocked()) { + if (profileModel.isBlocked()) { friendshipService.unblock( userIdFromCookie, profileModel.getId(), @@ -571,44 +571,85 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe fetchStoryAndHighlights(profileId); } setupButtons(profileId, myId); - if (!profileId.equals(myId)) { - profileDetailsBinding.favCb.setVisibility(View.VISIBLE); - favoriteRepository.getFavorite(username.substring(1), FavoriteType.USER, new RepositoryCallback() { - @Override - public void onSuccess(final Favorite result) { - profileDetailsBinding.favCb.setChecked(true); - profileDetailsBinding.favCb.setButtonDrawable(R.drawable.ic_star_check_24); - } + profileDetailsBinding.favChip.setVisibility(View.VISIBLE); + final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); + favoriteRepository.getFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback() { + @Override + public void onSuccess(final Favorite result) { + profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); + profileDetailsBinding.favChip.setText(R.string.added_to_favs); + } - @Override - public void onDataNotAvailable() { - profileDetailsBinding.favCb.setChecked(false); - profileDetailsBinding.favCb.setButtonDrawable(R.drawable.ic_outline_star_plus_24); - } - }); - } else { - profileDetailsBinding.favCb.setVisibility(View.GONE); - } + @Override + public void onDataNotAvailable() { + profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_outline_star_plus_24); + profileDetailsBinding.favChip.setText(R.string.add_to_favorites); + } + }); + profileDetailsBinding.favChip.setOnClickListener( + v -> favoriteRepository.getFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback() { + @Override + public void onSuccess(final Favorite result) { + favoriteRepository.deleteFavorite(profileModel.getUsername(), FavoriteType.USER, new RepositoryCallback() { + @Override + public void onSuccess(final Void result) { + profileDetailsBinding.favChip.setText(R.string.add_to_favorites); + profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_outline_star_plus_24); + showSnackbar(getString(R.string.removed_from_favs)); + } + + @Override + public void onDataNotAvailable() {} + }); + } + + @Override + public void onDataNotAvailable() { + final String finalUsername = username.startsWith("@") ? username.substring(1) : username; + favoriteRepository.insertOrUpdateFavorite(new Favorite( + -1, + finalUsername, + FavoriteType.USER, + profileModel.getName(), + profileModel.getSdProfilePic(), + new Date() + ), new RepositoryCallback() { + @Override + public void onSuccess(final Void result) { + profileDetailsBinding.favChip.setText(R.string.added_to_favs); + profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); + showSnackbar(getString(R.string.added_to_favs)); + } + + @Override + public void onDataNotAvailable() {} + }); + } + })); profileDetailsBinding.mainProfileImage.setImageURI(profileModel.getHdProfilePic()); - final long followersCount = profileModel.getFollowersCount(); - final long followingCount = profileModel.getFollowingCount(); + final Long followersCount = profileModel.getFollowersCount(); + final Long followingCount = profileModel.getFollowingCount(); final String postCount = String.valueOf(profileModel.getPostCount()); - SpannableStringBuilder span = new SpannableStringBuilder(getString(R.string.main_posts_count, - postCount)); + SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline, + profileModel.getPostCount() > 2000000000L ? 2000000000 : profileModel.getPostCount().intValue(), + postCount)); span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0); span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0); profileDetailsBinding.mainPostCount.setText(span); + profileDetailsBinding.mainPostCount.setVisibility(View.VISIBLE); final String followersCountStr = String.valueOf(followersCount); final int followersCountStrLen = followersCountStr.length(); - span = new SpannableStringBuilder(getString(R.string.main_posts_followers, - followersCountStr)); + span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_followers, + followersCount > 2000000000L ? 2000000000 : followersCount.intValue(), + followersCountStr)); span.setSpan(new RelativeSizeSpan(1.2f), 0, followersCountStrLen, 0); span.setSpan(new StyleSpan(Typeface.BOLD), 0, followersCountStrLen, 0); profileDetailsBinding.mainFollowers.setText(span); + profileDetailsBinding.mainFollowers.setVisibility(View.VISIBLE); final String followingCountStr = String.valueOf(followingCount); final int followingCountStrLen = followingCountStr.length(); @@ -617,6 +658,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe span.setSpan(new RelativeSizeSpan(1.2f), 0, followingCountStrLen, 0); span.setSpan(new StyleSpan(Typeface.BOLD), 0, followingCountStrLen, 0); profileDetailsBinding.mainFollowing.setText(span); + profileDetailsBinding.mainFollowing.setVisibility(View.VISIBLE); profileDetailsBinding.mainFullName.setText(TextUtils.isEmpty(profileModel.getName()) ? profileModel.getUsername() : profileModel.getName()); @@ -701,10 +743,25 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileDetailsBinding.btnLiked.setVisibility(View.GONE); profileDetailsBinding.btnDM.setVisibility(View.VISIBLE); // maybe there is a judgment mechanism? profileDetailsBinding.btnFollow.setVisibility(View.VISIBLE); - if (profileModel.getFollowing()) { + if (profileModel.isFollowing() || profileModel.isFollower()) { + profileDetailsBinding.mainStatus.setVisibility(View.VISIBLE); + if (!profileModel.isFollowing()) { + profileDetailsBinding.mainStatus.setChipBackgroundColor(getResources().getColorStateList(R.color.blue_800)); + profileDetailsBinding.mainStatus.setText(R.string.status_follower); + } + else if (!profileModel.isFollower()) { + profileDetailsBinding.mainStatus.setChipBackgroundColor(getResources().getColorStateList(R.color.deep_orange_800)); + profileDetailsBinding.mainStatus.setText(R.string.status_following); + } + else { + profileDetailsBinding.mainStatus.setChipBackgroundColor(getResources().getColorStateList(R.color.green_800)); + profileDetailsBinding.mainStatus.setText(R.string.status_mutual); + } + } + if (profileModel.isFollowing()) { profileDetailsBinding.btnFollow.setText(R.string.unfollow); profileDetailsBinding.btnFollow.setIconResource(R.drawable.ic_outline_person_add_disabled_24); - } else if (profileModel.getRequested()) { + } else if (profileModel.isRequested()) { profileDetailsBinding.btnFollow.setText(R.string.cancel); profileDetailsBinding.btnFollow.setIconResource(R.drawable.ic_outline_person_add_disabled_24); } else { @@ -713,7 +770,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } if (restrictMenuItem != null) { restrictMenuItem.setVisible(true); - if (profileModel.getRestricted()) { + if (profileModel.isRestricted()) { restrictMenuItem.setTitle(R.string.unrestrict); } else { restrictMenuItem.setTitle(R.string.restrict); @@ -722,7 +779,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileDetailsBinding.btnTagged.setVisibility(profileModel.isReallyPrivate() ? View.GONE : View.VISIBLE); if (blockMenuItem != null) { blockMenuItem.setVisible(true); - if (profileModel.getBlocked()) { + if (profileModel.isBlocked()) { blockMenuItem.setTitle(R.string.unblock); } else { blockMenuItem.setTitle(R.string.block); @@ -732,7 +789,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } if (!profileModel.isReallyPrivate() && restrictMenuItem != null) { restrictMenuItem.setVisible(true); - if (profileModel.getRestricted()) { + if (profileModel.isRestricted()) { restrictMenuItem.setTitle(R.string.unrestrict); } else { restrictMenuItem.setTitle(R.string.restrict); @@ -771,9 +828,34 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } private void setupCommonListeners() { + final Context context = getContext(); final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); profileDetailsBinding.btnFollow.setOnClickListener(v -> { - if (profileModel.getFollowing() || profileModel.getRequested()) { + if (profileModel.isFollowing() && profileModel.isPrivate()) { + new AlertDialog.Builder(context) + .setTitle(R.string.priv_acc) + .setMessage(R.string.priv_acc_confirm) + .setPositiveButton(R.string.confirm, (d, w) -> + friendshipService.unfollow( + userIdFromCookie, + profileModel.getId(), + CookieUtils.getCsrfTokenFromCookie(cookie), + new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoChangeRootResponse result) { + // Log.d(TAG, "Unfollow success: " + result); + onRefresh(); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error unfollowing", t); + } + })) + .setNegativeButton(R.string.cancel, null) + .show(); + } + else if (profileModel.isFollowing() || profileModel.isRequested()) { friendshipService.unfollow( userIdFromCookie, profileModel.getId(), @@ -860,66 +942,12 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } showProfilePicDialog(); }; - final Context context = getContext(); if (context == null) return; new AlertDialog.Builder(context) .setItems(options, profileDialogListener) .setNegativeButton(R.string.cancel, null) .show(); }); - profileDetailsBinding.favCb.setOnCheckedChangeListener((buttonView, isChecked) -> { - // do not do anything if state matches the db, as listener is set before profile details are set - final Context context = getContext(); - if (context == null) return; - final String finalUsername = username.startsWith("@") ? username.substring(1) : username; - favoriteRepository.getFavorite(finalUsername, FavoriteType.USER, new RepositoryCallback() { - @Override - public void onSuccess(final Favorite result) { - if (isChecked) return; // already a fav - buttonView.setVisibility(View.GONE); - profileDetailsBinding.favProgress.setVisibility(View.VISIBLE); - favoriteRepository.deleteFavorite(finalUsername, FavoriteType.USER, new RepositoryCallback() { - @Override - public void onSuccess(final Void result) { - profileDetailsBinding.favCb.setButtonDrawable(R.drawable.ic_outline_star_plus_24); - profileDetailsBinding.favProgress.setVisibility(View.GONE); - profileDetailsBinding.favCb.setVisibility(View.VISIBLE); - showSnackbar(getString(R.string.removed_from_favs)); - } - - @Override - public void onDataNotAvailable() {} - }); - } - - @Override - public void onDataNotAvailable() { - if (!isChecked) return; // not in fav already - buttonView.setVisibility(View.GONE); - profileDetailsBinding.favProgress.setVisibility(View.VISIBLE); - final Favorite model = new Favorite( - -1, - finalUsername, - FavoriteType.USER, - profileModel.getName(), - profileModel.getSdProfilePic(), - new Date() - ); - favoriteRepository.insertOrUpdateFavorite(model, new RepositoryCallback() { - @Override - public void onSuccess(final Void result) { - profileDetailsBinding.favCb.setButtonDrawable(R.drawable.ic_star_check_24); - profileDetailsBinding.favProgress.setVisibility(View.GONE); - profileDetailsBinding.favCb.setVisibility(View.VISIBLE); - showSnackbar(getString(R.string.added_to_favs)); - } - - @Override - public void onDataNotAvailable() {} - }); - } - }); - }); } private void showSnackbar(final String message) { diff --git a/app/src/main/java/awais/instagrabber/models/HashtagModel.java b/app/src/main/java/awais/instagrabber/models/HashtagModel.java index fbcac9db..58ff7932 100755 --- a/app/src/main/java/awais/instagrabber/models/HashtagModel.java +++ b/app/src/main/java/awais/instagrabber/models/HashtagModel.java @@ -29,7 +29,7 @@ public final class HashtagModel implements Serializable { return sdProfilePic; } - public long getPostCount() { return postCount; } + public Long getPostCount() { return postCount; } public boolean getFollowing() { return following; } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/models/LocationModel.java b/app/src/main/java/awais/instagrabber/models/LocationModel.java index fedaa773..b237d4e4 100755 --- a/app/src/main/java/awais/instagrabber/models/LocationModel.java +++ b/app/src/main/java/awais/instagrabber/models/LocationModel.java @@ -59,5 +59,5 @@ public final class LocationModel implements Serializable { return sdProfilePic; } - public long getPostCount() { return postCount; } + public Long getPostCount() { return postCount; } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/models/ProfileModel.java b/app/src/main/java/awais/instagrabber/models/ProfileModel.java index e6367ef6..ffed64f7 100755 --- a/app/src/main/java/awais/instagrabber/models/ProfileModel.java +++ b/app/src/main/java/awais/instagrabber/models/ProfileModel.java @@ -3,15 +3,15 @@ package awais.instagrabber.models; import java.io.Serializable; public final class ProfileModel implements Serializable { - private final boolean isPrivate, reallyPrivate, isVerified, following, restricted, blocked, requested; + private final boolean isPrivate, reallyPrivate, isVerified, following, follower, restricted, blocked, requested; private final long postCount, followersCount, followingCount; private final String id, username, name, biography, url, sdProfilePic, hdProfilePic; public ProfileModel(final boolean isPrivate, final boolean reallyPrivate, final boolean isVerified, final String id, final String username, final String name, final String biography, final String url, final String sdProfilePic, final String hdProfilePic, final long postCount, - final long followersCount, final long followingCount, final boolean following, final boolean restricted, - final boolean blocked, final boolean requested) { + final long followersCount, final long followingCount, final boolean following, final boolean follower, + final boolean restricted, final boolean blocked, final boolean requested) { this.isPrivate = isPrivate; this.reallyPrivate = reallyPrivate; this.isVerified = isVerified; @@ -26,21 +26,22 @@ public final class ProfileModel implements Serializable { this.followersCount = followersCount; this.followingCount = followingCount; this.following = following; + this.follower = follower; this.restricted = restricted; this.blocked = blocked; this.requested = requested; } public static ProfileModel getDefaultProfileModel() { - return new ProfileModel(false, false, false, null, null, null, null, null, null, null, 0, 0, 0, false, false, false, false); + return new ProfileModel(false, false, false, null, null, null, null, null, null, null, 0, 0, 0, false, false, false, false, false); } public static ProfileModel getDefaultProfileModel(final String userId) { - return new ProfileModel(false, false, false, userId, null, null, null, null, null, null, 0, 0, 0, false, false, false, false); + return new ProfileModel(false, false, false, userId, null, null, null, null, null, null, 0, 0, 0, false, false, false, false, false); } public static ProfileModel getDefaultProfileModel(final String userId, final String username) { - return new ProfileModel(false, false, false, userId, username, null, null, null, null, null, 0, 0, 0, false, false, false, false); + return new ProfileModel(false, false, false, userId, username, null, null, null, null, null, 0, 0, 0, false, false, false, false, false); } public boolean isPrivate() { @@ -83,31 +84,35 @@ public final class ProfileModel implements Serializable { return hdProfilePic; } - public long getPostCount() { + public Long getPostCount() { return postCount; } - public long getFollowersCount() { + public Long getFollowersCount() { return followersCount; } - public long getFollowingCount() { + public Long getFollowingCount() { return followingCount; } - public boolean getFollowing() { + public boolean isFollowing() { return following; } - public boolean getRestricted() { + public boolean isFollower() { + return follower; + } + + public boolean isRestricted() { return restricted; } - public boolean getBlocked() { + public boolean isBlocked() { return blocked; } - public boolean getRequested() { + public boolean isRequested() { return requested; } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java b/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java index 8643b682..ec6a0d6e 100644 --- a/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java @@ -20,7 +20,4 @@ public interface ProfileRepository { @GET("/api/v1/feed/liked/") Call fetchLiked(@QueryMap Map queryParams); - - @GET("/api/v1/usertags/{profileId}/feed/") - Call fetchTagged(@Path("profileId") final String profileId, @QueryMap Map queryParams); } diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index e0f028ce..c9029a00 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -203,7 +203,7 @@ public final class ResponseBodyUtils { userObj.getString("full_name"), null, null, userObj.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + null, 0, 0, 0, false, false, false, false, false); } final MediaItemType mediaType = getMediaItemType(mediaObj.optInt("media_type", -1)); @@ -291,7 +291,7 @@ public final class ResponseBodyUtils { userObject.getString("full_name"), null, null, userObject.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + null, 0, 0, 0, false, false, false, false, false); } final ProfileModel[] leftuserModels = new ProfileModel[leftusersLen]; @@ -305,7 +305,7 @@ public final class ResponseBodyUtils { userObject.getString("full_name"), null, null, userObject.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + null, 0, 0, 0, false, false, false, false, false); } final Long[] adminIDs = new Long[adminsLen]; @@ -470,7 +470,7 @@ public final class ResponseBodyUtils { profile.getString("full_name"), null, null, profile.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + null, 0, 0, 0, false, false, false, false, false); } break; @@ -622,6 +622,7 @@ public final class ResponseBodyUtils { 0, 0, following, + false, restricted, false, requested); @@ -705,6 +706,7 @@ public final class ResponseBodyUtils { false, false, false, + false, false); } JSONObject tempJsonObject = feedItem.optJSONObject("edge_media_preview_comment"); diff --git a/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java b/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java index 1f542694..84d7f305 100644 --- a/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java +++ b/app/src/main/java/awais/instagrabber/webservices/DiscoverService.java @@ -165,6 +165,7 @@ public class DiscoverService extends BaseService { false, false, false, + false, false); } final String resourceUrl = ResponseBodyUtils.getHighQualityImage(coverMediaJson); diff --git a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java index 47766743..9ba5a620 100644 --- a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java +++ b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java @@ -89,7 +89,6 @@ public class ProfileService extends BaseService { }); } - public void fetchPosts(final ProfileModel profileModel, final int postsPerPage, final String cursor, @@ -156,135 +155,18 @@ public class ProfileService extends BaseService { } final JSONArray edges = mediaPosts.getJSONArray("edges"); for (int i = 0; i < edges.length(); ++i) { - final JSONObject mediaNode = edges.getJSONObject(i).getJSONObject("node"); - final String mediaType = mediaNode.optString("__typename"); - if (mediaType.isEmpty() || "GraphSuggestedUserFeedUnit".equals(mediaType)) + final JSONObject itemJson = edges.optJSONObject(i); + if (itemJson == null) { continue; - final boolean isVideo = mediaNode.getBoolean("is_video"); - final long videoViews = mediaNode.optLong("video_view_count", 0); - - final String displayUrl = mediaNode.optString("display_url"); - if (TextUtils.isEmpty(displayUrl)) continue; - final String resourceUrl; - - if (isVideo) { - resourceUrl = mediaNode.getString("video_url"); - } else { - resourceUrl = mediaNode.has("display_resources") ? ResponseBodyUtils.getHighQualityImage(mediaNode) : displayUrl; } - JSONObject tempJsonObject = mediaNode.optJSONObject("edge_media_to_comment"); - final long commentsCount = tempJsonObject != null ? tempJsonObject.optLong("count") : 0; - tempJsonObject = mediaNode.optJSONObject("edge_media_preview_like"); - final long likesCount = tempJsonObject != null ? tempJsonObject.optLong("count") : 0; - tempJsonObject = mediaNode.optJSONObject("edge_media_to_caption"); - final JSONArray captions = tempJsonObject != null ? tempJsonObject.getJSONArray("edges") : null; - String captionText = null; - if (captions != null && captions.length() > 0) { - if ((tempJsonObject = captions.optJSONObject(0)) != null && - (tempJsonObject = tempJsonObject.optJSONObject("node")) != null) { - captionText = tempJsonObject.getString("text"); - } + final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson); + if (feedModel != null) { + feedModels.add(feedModel); } - final JSONObject location = mediaNode.optJSONObject("location"); - // Log.d(TAG, "location: " + (location == null ? null : location.toString())); - String locationId = null; - String locationName = null; - if (location != null) { - locationName = location.optString("name"); - if (location.has("id")) { - locationId = location.getString("id"); - } else if (location.has("pk")) { - locationId = location.getString("pk"); - } - // Log.d(TAG, "locationId: " + locationId); - } - int height = 0; - int width = 0; - final JSONObject dimensions = mediaNode.optJSONObject("dimensions"); - if (dimensions != null) { - height = dimensions.optInt("height"); - width = dimensions.optInt("width"); - } - String thumbnailUrl = null; - try { - thumbnailUrl = mediaNode.getJSONArray("display_resources") - .getJSONObject(0) - .getString("src"); - } catch (JSONException ignored) {} - final FeedModel.Builder builder = new FeedModel.Builder() - .setProfileModel(profileModel) - .setItemType(isVideo ? MediaItemType.MEDIA_TYPE_VIDEO - : MediaItemType.MEDIA_TYPE_IMAGE) - .setViewCount(videoViews) - .setPostId(mediaNode.getString(Constants.EXTRAS_ID)) - .setDisplayUrl(resourceUrl) - .setThumbnailUrl(thumbnailUrl != null ? thumbnailUrl : displayUrl) - .setShortCode(mediaNode.getString(Constants.EXTRAS_SHORTCODE)) - .setPostCaption(captionText) - .setCommentsCount(commentsCount) - .setTimestamp(mediaNode.optLong("taken_at_timestamp", -1)) - .setLiked(mediaNode.getBoolean("viewer_has_liked")) - .setBookmarked(mediaNode.getBoolean("viewer_has_saved")) - .setLikesCount(likesCount) - .setLocationName(locationName) - .setLocationId(locationId) - .setImageHeight(height) - .setImageWidth(width); - final boolean isSlider = "GraphSidecar".equals(mediaType) && mediaNode.has("edge_sidecar_to_children"); - if (isSlider) { - builder.setItemType(MediaItemType.MEDIA_TYPE_SLIDER); - final JSONObject sidecar = mediaNode.optJSONObject("edge_sidecar_to_children"); - if (sidecar != null) { - final JSONArray children = sidecar.optJSONArray("edges"); - if (children != null) { - final List sliderItems = getSliderItems(children); - builder.setSliderItems(sliderItems); - } - } - } - final FeedModel feedModel = builder.build(); - feedModels.add(feedModel); } return new PostsFetchResponse(feedModels, hasNextPage, endCursor); } - @NonNull - private List getSliderItems(final JSONArray children) throws JSONException { - final List sliderItems = new ArrayList<>(); - for (int j = 0; j < children.length(); ++j) { - final JSONObject childNode = children.optJSONObject(j).getJSONObject("node"); - final boolean isChildVideo = childNode.optBoolean("is_video"); - int height = 0; - int width = 0; - final JSONObject dimensions = childNode.optJSONObject("dimensions"); - if (dimensions != null) { - height = dimensions.optInt("height"); - width = dimensions.optInt("width"); - } - String thumbnailUrl = null; - try { - thumbnailUrl = childNode.getJSONArray("display_resources") - .getJSONObject(0) - .getString("src"); - } catch (JSONException ignored) {} - final PostChild sliderItem = new PostChild.Builder() - .setItemType(isChildVideo ? MediaItemType.MEDIA_TYPE_VIDEO - : MediaItemType.MEDIA_TYPE_IMAGE) - .setPostId(childNode.getString(Constants.EXTRAS_ID)) - .setDisplayUrl(isChildVideo ? childNode.getString("video_url") - : childNode.getString("display_url")) - .setThumbnailUrl(thumbnailUrl != null ? thumbnailUrl - : childNode.getString("display_url")) - .setVideoViews(childNode.optLong("video_view_count", 0)) - .setHeight(height) - .setWidth(width) - .build(); - // Log.d(TAG, "getSliderItems: sliderItem: " + sliderItem); - sliderItems.add(sliderItem); - } - return sliderItems; - } - public void fetchSaved(final String maxId, final ServiceCallback callback) { final ImmutableMap.Builder builder = ImmutableMap.builder(); @@ -358,13 +240,17 @@ public class ProfileService extends BaseService { } public void fetchTagged(final String profileId, - final String maxId, + final int postsPerPage, + final String cursor, final ServiceCallback callback) { - final ImmutableMap.Builder builder = ImmutableMap.builder(); - if (!TextUtils.isEmpty(maxId)) { - builder.put("max_id", maxId); - } - final Call request = repository.fetchTagged(profileId, builder.build()); + final Map queryMap = new HashMap<>(); + queryMap.put("query_hash", "31fe64d9463cbbe58319dced405c6206"); + queryMap.put("variables", "{" + + "\"id\":\"" + profileId + "\"," + + "\"first\":" + postsPerPage + "," + + "\"after\":\"" + (cursor == null ? "" : cursor) + "\"" + + "}"); + final Call request = wwwRepository.fetch(queryMap); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -377,7 +263,7 @@ public class ProfileService extends BaseService { callback.onSuccess(null); return; } - final SavedPostsFetchResponse savedPostsFetchResponse = parseSavedPostsResponse(body, false); + final SavedPostsFetchResponse savedPostsFetchResponse = parseTaggedPostsResponse(body); callback.onSuccess(savedPostsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); @@ -411,6 +297,41 @@ public class ProfileService extends BaseService { ); } + @NonNull + private SavedPostsFetchResponse parseTaggedPostsResponse(@NonNull final String body) + throws JSONException { + final List feedModels = new ArrayList<>(); + final JSONObject timelineFeed = new JSONObject(body) + .getJSONObject("data") + .getJSONObject(Constants.EXTRAS_USER) + .getJSONObject("edge_user_to_photos_of_you"); + final String endCursor; + final boolean hasNextPage; + + final JSONObject pageInfo = timelineFeed.getJSONObject("page_info"); + if (pageInfo.has("has_next_page")) { + hasNextPage = pageInfo.getBoolean("has_next_page"); + endCursor = hasNextPage ? pageInfo.getString("end_cursor") : null; + } else { + hasNextPage = false; + endCursor = null; + } + + final JSONArray feedItems = timelineFeed.getJSONArray("edges"); + + for (int i = 0; i < feedItems.length(); ++i) { + final JSONObject itemJson = feedItems.optJSONObject(i); + if (itemJson == null) { + continue; + } + final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson); + if (feedModel != null) { + feedModels.add(feedModel); + } + } + return new SavedPostsFetchResponse(hasNextPage, endCursor, timelineFeed.getInt("count"), "ok", feedModels); + } + private List parseItems(final JSONArray items, final boolean isInMedia) throws JSONException { if (items == null) { return Collections.emptyList(); diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index c895a3fa..d5a0c723 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -123,7 +123,7 @@ public class StoriesService extends BaseService { user.getString("username"), null, null, null, user.getString("profile_pic_url"), - null, 0, 0, 0, false, false, false, false); + null, 0, 0, 0, false, false, false, false, false); final String id = node.getString("id"); final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == node.getLong("latest_reel_media"); feedStoryModels.add(new FeedStoryModel(id, profileModel, fullyRead)); diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index 41abd3b3..eb14c1f9 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -18,45 +18,96 @@ app:layout_constraintEnd_toStartOf="@id/mainPostCount" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="@id/fav_chip" tools:background="@mipmap/ic_launcher" /> - + app:layout_constraintTop_toTopOf="@id/mainProfileImage" + tools:text="35 Posts" /> - + app:layout_constraintTop_toTopOf="@id/mainPostCount" + tools:text="omg what do u expect" /> - + + + app:layout_constraintTop_toBottomOf="@id/mainPostCount" + app:rippleColor="@color/grey_400" + tools:text="10 Following" /> + + + + @@ -151,29 +202,12 @@ app:iconGravity="top" app:iconTint="@color/deep_purple_200" app:layout_constraintBottom_toTopOf="@id/highlights_barrier" - app:layout_constraintEnd_toStartOf="@id/btnTagged" + app:layout_constraintEnd_toStartOf="@id/btnSaved" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/mainUrl" app:rippleColor="@color/purple_200" tools:visibility="visible" /> - - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index ab79c8d3..3545af5f 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -4,6 +4,7 @@ @dimen/profile_picture_size 90dp + 40dp 40dp 24dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cf373b48..b82e1caf 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -45,10 +45,15 @@ Use Instadp for high definition profile pictures Import/Export Language - %s\nPosts - %s Posts - %s\nFollowers - %s\nFollowing + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Autoplay videos Always mute videos Select what to download @@ -107,6 +112,9 @@ Unblock Restrict Unrestrict + Following each other + Followed by you + Following you Map Export Import From 49f41f46548b75766e166698f4c829b98d29ac0c Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sun, 20 Dec 2020 13:35:16 -0500 Subject: [PATCH 009/101] api refactor --- .../asyncs/FeedPostFetchService.java | 8 +- .../asyncs/HashtagPostFetchService.java | 19 +- .../asyncs/HighlightsFetcher.java | 73 ----- .../asyncs/LocationPostFetchService.java | 19 +- .../asyncs/ProfilePostFetchService.java | 27 +- .../asyncs/SavedPostFetchService.java | 24 +- .../fragments/SavedViewerFragment.java | 12 +- .../fragments/main/ProfileFragment.java | 33 ++- ...Repository.java => GraphQLRepository.java} | 2 +- .../repositories/LocationRepository.java | 3 - .../repositories/ProfileRepository.java | 9 +- .../repositories/StoriesRepository.java | 7 +- .../repositories/TagsRepository.java | 3 - .../{FeedService.java => GraphQLService.java} | 158 ++++++---- .../webservices/LocationService.java | 191 +------------ .../webservices/ProfileService.java | 270 ++++-------------- .../webservices/StoriesService.java | 50 +++- .../instagrabber/webservices/TagsService.java | 187 +----------- 18 files changed, 320 insertions(+), 775 deletions(-) delete mode 100755 app/src/main/java/awais/instagrabber/asyncs/HighlightsFetcher.java rename app/src/main/java/awais/instagrabber/repositories/{FeedRepository.java => GraphQLRepository.java} (87%) rename app/src/main/java/awais/instagrabber/webservices/{FeedService.java => GraphQLService.java} (55%) diff --git a/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java index d2bba0ce..a3792921 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java @@ -6,22 +6,22 @@ import awais.instagrabber.customviews.helpers.PostFetcher; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; import awais.instagrabber.repositories.responses.PostsFetchResponse; -import awais.instagrabber.webservices.FeedService; +import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.ServiceCallback; public class FeedPostFetchService implements PostFetcher.PostFetchService { private static final String TAG = "FeedPostFetchService"; - private final FeedService feedService; + private final GraphQLService graphQLService; private String nextCursor; private boolean hasNextPage; public FeedPostFetchService() { - feedService = FeedService.getInstance(); + graphQLService = GraphQLService.getInstance(); } @Override public void fetch(final FetchListener> fetchListener) { - feedService.fetch(25, nextCursor, new ServiceCallback() { + graphQLService.fetchFeed(25, nextCursor, new ServiceCallback() { @Override public void onSuccess(final PostsFetchResponse result) { if (result == null) return; diff --git a/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java index 4c12f16e..55f1bc40 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/HashtagPostFetchService.java @@ -6,12 +6,14 @@ import awais.instagrabber.customviews.helpers.PostFetcher; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.HashtagModel; +import awais.instagrabber.repositories.responses.PostsFetchResponse; +import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.TagsService; -import awais.instagrabber.webservices.TagsService.TagPostsFetchResponse; public class HashtagPostFetchService implements PostFetcher.PostFetchService { private final TagsService tagsService; + private final GraphQLService graphQLService; private final HashtagModel hashtagModel; private String nextMaxId; private boolean moreAvailable; @@ -20,19 +22,20 @@ public class HashtagPostFetchService implements PostFetcher.PostFetchService { public HashtagPostFetchService(final HashtagModel hashtagModel, final boolean isLoggedIn) { this.hashtagModel = hashtagModel; this.isLoggedIn = isLoggedIn; - tagsService = TagsService.getInstance(); + tagsService = isLoggedIn ? TagsService.getInstance() : null; + graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); } @Override public void fetch(final FetchListener> fetchListener) { - final ServiceCallback cb = new ServiceCallback() { + final ServiceCallback cb = new ServiceCallback() { @Override - public void onSuccess(final TagPostsFetchResponse result) { + public void onSuccess(final PostsFetchResponse result) { if (result == null) return; - nextMaxId = result.getNextMaxId(); - moreAvailable = result.isMoreAvailable(); + nextMaxId = result.getNextCursor(); + moreAvailable = result.hasNextPage(); if (fetchListener != null) { - fetchListener.onResult(result.getItems()); + fetchListener.onResult(result.getFeedModels()); } } @@ -45,7 +48,7 @@ public class HashtagPostFetchService implements PostFetcher.PostFetchService { } }; if (isLoggedIn) tagsService.fetchPosts(hashtagModel.getName().toLowerCase(), nextMaxId, cb); - else tagsService.fetchGraphQLPosts(hashtagModel.getName().toLowerCase(), nextMaxId, cb); + else graphQLService.fetchHashtagPosts(hashtagModel.getName().toLowerCase(), nextMaxId, cb); } @Override diff --git a/app/src/main/java/awais/instagrabber/asyncs/HighlightsFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/HighlightsFetcher.java deleted file mode 100755 index acb7b7c1..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/HighlightsFetcher.java +++ /dev/null @@ -1,73 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import awais.instagrabber.BuildConfig; -import awais.instagrabber.interfaces.FetchListener; -import awais.instagrabber.models.HighlightModel; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.NetworkUtils; - -public final class HighlightsFetcher extends AsyncTask> { - private final String id; - private final FetchListener> fetchListener; - - public HighlightsFetcher(final String id, final FetchListener> fetchListener) { - this.id = id; - this.fetchListener = fetchListener; - } - - @Override - protected List doInBackground(final Void... voids) { - List result = null; - String url = "https://i.instagram.com/api/v1/highlights/" + id + "/highlights_tray/"; - - try { - HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); - conn.setInstanceFollowRedirects(false); - conn.setUseCaches(false); - conn.setRequestProperty("User-Agent", Constants.I_USER_AGENT); - conn.connect(); - - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - final JSONArray highlightsReel = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONArray("tray"); - - final int length = highlightsReel.length(); - final List highlightModels = new ArrayList<>(); - // final String[] highlightIds = new String[length]; - for (int i = 0; i < length; ++i) { - final JSONObject highlightNode = highlightsReel.getJSONObject(i); - highlightModels.add(new HighlightModel( - highlightNode.getString("title"), - highlightNode.getString(Constants.EXTRAS_ID), - highlightNode.getJSONObject("cover_media") - .getJSONObject("cropped_image_version") - .getString("url") - )); - } - conn.disconnect(); - result = highlightModels; - } - - conn.disconnect(); - } catch (Exception e) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - } - - return result; - } - - @Override - protected void onPostExecute(final List result) { - if (fetchListener != null) fetchListener.onResult(result); - } -} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java index 2b504c50..7c7a12ce 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/LocationPostFetchService.java @@ -6,12 +6,14 @@ import awais.instagrabber.customviews.helpers.PostFetcher; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.LocationModel; +import awais.instagrabber.repositories.responses.PostsFetchResponse; +import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.LocationService; -import awais.instagrabber.webservices.LocationService.LocationPostsFetchResponse; import awais.instagrabber.webservices.ServiceCallback; public class LocationPostFetchService implements PostFetcher.PostFetchService { private final LocationService locationService; + private final GraphQLService graphQLService; private final LocationModel locationModel; private String nextMaxId; private boolean moreAvailable; @@ -20,19 +22,20 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService { public LocationPostFetchService(final LocationModel locationModel, final boolean isLoggedIn) { this.locationModel = locationModel; this.isLoggedIn = isLoggedIn; - locationService = LocationService.getInstance(); + locationService = isLoggedIn ? LocationService.getInstance() : null; + graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); } @Override public void fetch(final FetchListener> fetchListener) { - final ServiceCallback cb = new ServiceCallback() { + final ServiceCallback cb = new ServiceCallback() { @Override - public void onSuccess(final LocationPostsFetchResponse result) { + public void onSuccess(final PostsFetchResponse result) { if (result == null) return; - nextMaxId = result.getNextMaxId(); - moreAvailable = result.isMoreAvailable(); + nextMaxId = result.getNextCursor(); + moreAvailable = result.hasNextPage(); if (fetchListener != null) { - fetchListener.onResult(result.getItems()); + fetchListener.onResult(result.getFeedModels()); } } @@ -45,7 +48,7 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService { } }; if (isLoggedIn) locationService.fetchPosts(locationModel.getId(), nextMaxId, cb); - else locationService.fetchGraphQLPosts(locationModel.getId(), nextMaxId, cb); + else graphQLService.fetchLocationPosts(locationModel.getId(), nextMaxId, cb); } @Override diff --git a/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java index 3617cbd2..649d28d8 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/ProfilePostFetchService.java @@ -7,29 +7,34 @@ import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.repositories.responses.PostsFetchResponse; +import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.ProfileService; import awais.instagrabber.webservices.ServiceCallback; public class ProfilePostFetchService implements PostFetcher.PostFetchService { private static final String TAG = "ProfilePostFetchService"; private final ProfileService profileService; + private final GraphQLService graphQLService; private final ProfileModel profileModel; - private String nextCursor; - private boolean hasNextPage; + private final boolean isLoggedIn; + private String nextMaxId; + private boolean moreAvailable; - public ProfilePostFetchService(final ProfileModel profileModel) { + public ProfilePostFetchService(final ProfileModel profileModel, final boolean isLoggedIn) { this.profileModel = profileModel; - profileService = ProfileService.getInstance(); + this.isLoggedIn = isLoggedIn; + graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); + profileService = isLoggedIn ? ProfileService.getInstance() : null; } @Override public void fetch(final FetchListener> fetchListener) { - profileService.fetchPosts(profileModel, 30, nextCursor, new ServiceCallback() { + final ServiceCallback cb = new ServiceCallback() { @Override public void onSuccess(final PostsFetchResponse result) { if (result == null) return; - nextCursor = result.getNextCursor(); - hasNextPage = result.hasNextPage(); + nextMaxId = result.getNextCursor(); + moreAvailable = result.hasNextPage(); if (fetchListener != null) { fetchListener.onResult(result.getFeedModels()); } @@ -42,16 +47,18 @@ public class ProfilePostFetchService implements PostFetcher.PostFetchService { fetchListener.onFailure(t); } } - }); + }; + if (isLoggedIn) profileService.fetchPosts(profileModel.getId(), nextMaxId, cb); + else graphQLService.fetchProfilePosts(profileModel.getId(), 30, nextMaxId, cb); } @Override public void reset() { - nextCursor = null; + nextMaxId = null; } @Override public boolean hasNextPage() { - return hasNextPage; + return moreAvailable; } } diff --git a/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java index fcae9b65..b13d842d 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/SavedPostFetchService.java @@ -6,34 +6,39 @@ import awais.instagrabber.customviews.helpers.PostFetcher; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.enums.PostItemType; +import awais.instagrabber.repositories.responses.PostsFetchResponse; +import awais.instagrabber.webservices.GraphQLService; import awais.instagrabber.webservices.ProfileService; -import awais.instagrabber.webservices.ProfileService.SavedPostsFetchResponse; import awais.instagrabber.webservices.ServiceCallback; public class SavedPostFetchService implements PostFetcher.PostFetchService { private final ProfileService profileService; + private final GraphQLService graphQLService; private final String profileId; private final PostItemType type; + private final boolean isLoggedIn; private String nextMaxId; private boolean moreAvailable; - public SavedPostFetchService(final String profileId, final PostItemType type) { + public SavedPostFetchService(final String profileId, final PostItemType type, final boolean isLoggedIn) { this.profileId = profileId; this.type = type; - profileService = ProfileService.getInstance(); + this.isLoggedIn = isLoggedIn; + graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); + profileService = isLoggedIn ? ProfileService.getInstance() : null; } @Override public void fetch(final FetchListener> fetchListener) { - final ServiceCallback callback = new ServiceCallback() { + final ServiceCallback callback = new ServiceCallback() { @Override - public void onSuccess(final SavedPostsFetchResponse result) { + public void onSuccess(final PostsFetchResponse result) { if (result == null) return; - nextMaxId = result.getNextMaxId(); - moreAvailable = result.isMoreAvailable(); + nextMaxId = result.getNextCursor(); + moreAvailable = result.hasNextPage(); if (fetchListener != null) { - fetchListener.onResult(result.getItems()); + fetchListener.onResult(result.getFeedModels()); } } @@ -50,7 +55,8 @@ public class SavedPostFetchService implements PostFetcher.PostFetchService { profileService.fetchLiked(nextMaxId, callback); break; case TAGGED: - profileService.fetchTagged(profileId, 30, nextMaxId, callback); + if (isLoggedIn) profileService.fetchTagged(profileId, nextMaxId, callback); + else graphQLService.fetchTaggedPosts(profileId, 30, nextMaxId, callback); break; case SAVED: default: diff --git a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java index fbb9f8f7..ed16f43c 100644 --- a/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/SavedViewerFragment.java @@ -40,24 +40,26 @@ import awais.instagrabber.models.FeedModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; +import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import static androidx.core.content.PermissionChecker.checkSelfPermission; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; +import static awais.instagrabber.utils.Utils.settingsHelper; public final class SavedViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final int STORAGE_PERM_REQUEST_CODE = 8020; private static final int STORAGE_PERM_REQUEST_CODE_FOR_SELECTION = 8030; private FragmentSavedBinding binding; - private String username; + private String username, cookie, profileId; private ActionMode actionMode; private SwipeRefreshLayout root; private AppCompatActivity fragmentActivity; - private boolean shouldRefresh = true; + private boolean isLoggedIn, shouldRefresh = true; private PostItemType type; - private String profileId; private Set selectedFeedModels; private FeedModel downloadFeedModel; private int downloadChildPosition = -1; @@ -225,6 +227,8 @@ public final class SavedViewerFragment extends Fragment implements SwipeRefreshL @Override public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { + cookie = settingsHelper.getString(Constants.COOKIE); + isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != null; if (root != null) { shouldRefresh = false; return root; @@ -281,7 +285,7 @@ public final class SavedViewerFragment extends Fragment implements SwipeRefreshL private void setupPosts() { binding.posts.setViewModelStoreOwner(this) .setLifeCycleOwner(this) - .setPostFetchService(new SavedPostFetchService(profileId, type)) + .setPostFetchService(new SavedPostFetchService(profileId, type, isLoggedIn)) .setLayoutPreferences(layoutPreferences) .addFetchStatusChangeListener(fetching -> updateSwipeRefreshState()) .setFeedItemCallback(feedItemCallback) diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 180f6e25..f9e85d3e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -54,7 +54,6 @@ import awais.instagrabber.R; import awais.instagrabber.activities.MainActivity; import awais.instagrabber.adapters.FeedAdapterV2; import awais.instagrabber.adapters.HighlightsAdapter; -import awais.instagrabber.asyncs.HighlightsFetcher; import awais.instagrabber.asyncs.ProfileFetcher; import awais.instagrabber.asyncs.ProfilePostFetchService; import awais.instagrabber.asyncs.UsernameFetcher; @@ -75,6 +74,7 @@ import awais.instagrabber.dialogs.ProfilePicDialogFragment; import awais.instagrabber.fragments.PostViewV2Fragment; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; +import awais.instagrabber.models.HighlightModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.models.StoryModel; @@ -729,6 +729,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe } private void setupButtons(final String profileId, final String myId) { + profileDetailsBinding.btnTagged.setVisibility(profileModel.isReallyPrivate() ? View.GONE : View.VISIBLE); if (isLoggedIn) { if (profileId.equals(myId)) { profileDetailsBinding.btnTagged.setVisibility(View.VISIBLE); @@ -738,7 +739,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileDetailsBinding.btnSaved.setText(R.string.saved); return; } - profileDetailsBinding.btnTagged.setVisibility(View.GONE); profileDetailsBinding.btnSaved.setVisibility(View.GONE); profileDetailsBinding.btnLiked.setVisibility(View.GONE); profileDetailsBinding.btnDM.setVisibility(View.VISIBLE); // maybe there is a judgment mechanism? @@ -776,7 +776,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe restrictMenuItem.setTitle(R.string.restrict); } } - profileDetailsBinding.btnTagged.setVisibility(profileModel.isReallyPrivate() ? View.GONE : View.VISIBLE); if (blockMenuItem != null) { blockMenuItem.setVisible(true); if (profileModel.isBlocked()) { @@ -817,14 +816,24 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe Log.e(TAG, "Error", t); } }); - new HighlightsFetcher(profileId, - result -> { - highlightsFetching = false; - if (result != null) { - profileDetailsBinding.highlightsList.setVisibility(View.VISIBLE); - highlightsViewModel.getList().postValue(result); - } else profileDetailsBinding.highlightsList.setVisibility(View.GONE); - }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + storiesService.fetchHighlights(profileId, + new ServiceCallback>() { + @Override + public void onSuccess(final List result) { + highlightsFetching = false; + if (result != null) { + profileDetailsBinding.highlightsList.setVisibility(View.VISIBLE); + highlightsViewModel.getList().postValue(result); + } + else profileDetailsBinding.highlightsList.setVisibility(View.GONE); + } + + @Override + public void onFailure(final Throwable t) { + profileDetailsBinding.highlightsList.setVisibility(View.GONE); + Log.e(TAG, "Error", t); + } + }); } private void setupCommonListeners() { @@ -979,7 +988,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private void setupPosts() { binding.postsRecyclerView.setViewModelStoreOwner(this) .setLifeCycleOwner(this) - .setPostFetchService(new ProfilePostFetchService(profileModel)) + .setPostFetchService(new ProfilePostFetchService(profileModel, isLoggedIn)) .setLayoutPreferences(layoutPreferences) .addFetchStatusChangeListener(fetching -> updateSwipeRefreshState()) .setFeedItemCallback(feedItemCallback) diff --git a/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java b/app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java similarity index 87% rename from app/src/main/java/awais/instagrabber/repositories/FeedRepository.java rename to app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java index 3672fb90..23020035 100644 --- a/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/GraphQLRepository.java @@ -6,7 +6,7 @@ import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.QueryMap; -public interface FeedRepository { +public interface GraphQLRepository { @GET("/graphql/query/") Call fetch(@QueryMap(encoded = true) Map queryParams); } diff --git a/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java b/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java index 2237254d..7cb5ca41 100644 --- a/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/LocationRepository.java @@ -12,7 +12,4 @@ public interface LocationRepository { @GET("/api/v1/feed/location/{location}/") Call fetchPosts(@Path("location") final String locationId, @QueryMap Map queryParams); - - @GET("/graphql/query/") - Call fetchGraphQLPosts(@QueryMap(encoded = true) Map queryParams); } diff --git a/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java b/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java index ec6a0d6e..916dd094 100644 --- a/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java @@ -9,15 +9,18 @@ import retrofit2.http.QueryMap; public interface ProfileRepository { - @GET("api/v1/users/{uid}/info/") + @GET("/api/v1/users/{uid}/info/") Call getUserInfo(@Path("uid") final String uid); - @GET("/graphql/query/") - Call fetch(@QueryMap Map queryMap); + @GET("/api/v1/feed/user/{uid}/") + Call fetch(@Path("uid") final String uid, @QueryMap Map queryParams); @GET("/api/v1/feed/saved/") Call fetchSaved(@QueryMap Map queryParams); @GET("/api/v1/feed/liked/") Call fetchLiked(@QueryMap Map queryParams); + + @GET("/api/v1/usertags/{profileId}/feed/") + Call fetchTagged(@Path("profileId") final String profileId, @QueryMap Map queryParams); } diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java index 8ed0da74..c66368de 100644 --- a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java @@ -17,8 +17,11 @@ public interface StoriesRepository { @FormUrlEncoded @POST("/api/v1/feed/reels_tray/") - Call getStories(@Header("User-Agent") String userAgent, - @FieldMap Map form); + Call getFeedStories(@Header("User-Agent") String userAgent, + @FieldMap Map form); + + @GET("/api/v1/highlights/{uid}/highlights_tray/") + Call fetchHighlights(@Path("uid") final String uid); @GET Call getUserStory(@Header("User-Agent") String userAgent, @Url String url); diff --git a/app/src/main/java/awais/instagrabber/repositories/TagsRepository.java b/app/src/main/java/awais/instagrabber/repositories/TagsRepository.java index b646a8a3..4db3efbd 100644 --- a/app/src/main/java/awais/instagrabber/repositories/TagsRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/TagsRepository.java @@ -24,7 +24,4 @@ public interface TagsRepository { @GET("/api/v1/feed/tag/{tag}/") Call fetchPosts(@Path("tag") final String tag, @QueryMap Map queryParams); - - @GET("/graphql/query/") - Call fetchGraphQLPosts(@QueryMap(encoded = true) Map queryParams); } diff --git a/app/src/main/java/awais/instagrabber/webservices/FeedService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java similarity index 55% rename from app/src/main/java/awais/instagrabber/webservices/FeedService.java rename to app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index d4e84e35..94d9f38f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FeedService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -21,10 +21,7 @@ import java.util.List; import java.util.Map; import awais.instagrabber.models.FeedModel; -import awais.instagrabber.models.PostChild; -import awais.instagrabber.models.ProfileModel; -import awais.instagrabber.models.enums.MediaItemType; -import awais.instagrabber.repositories.FeedRepository; +import awais.instagrabber.repositories.GraphQLRepository; import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.ResponseBodyUtils; @@ -34,69 +31,43 @@ import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; -public class FeedService extends BaseService { - private static final String TAG = "FeedService"; +public class GraphQLService extends BaseService { + private static final String TAG = "GraphQLService"; private static final boolean loadFromMock = false; - private final FeedRepository repository; + private final GraphQLRepository repository; - private static FeedService instance; + private static GraphQLService instance; - private FeedService() { + private GraphQLService() { final Retrofit retrofit = getRetrofitBuilder() .baseUrl("https://www.instagram.com") .build(); - repository = retrofit.create(FeedRepository.class); + repository = retrofit.create(GraphQLRepository.class); } - public static FeedService getInstance() { + public static GraphQLService getInstance() { if (instance == null) { - instance = new FeedService(); + instance = new GraphQLService(); } return instance; } - public void fetch(final int maxItemsToLoad, - final String cursor, - final ServiceCallback callback) { - if (loadFromMock) { - final Handler handler = new Handler(); - handler.postDelayed(() -> { - final ClassLoader classLoader = getClass().getClassLoader(); - if (classLoader == null) { - Log.e(TAG, "fetch: classLoader is null!"); - return; - } - try (InputStream resourceAsStream = classLoader.getResourceAsStream("feed_response.json"); - Reader in = new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8)) { - final int bufferSize = 1024; - final char[] buffer = new char[bufferSize]; - final StringBuilder out = new StringBuilder(); - int charsRead; - while ((charsRead = in.read(buffer, 0, buffer.length)) > 0) { - out.append(buffer, 0, charsRead); - } - callback.onSuccess(parseResponseBody(out.toString())); - } catch (IOException | JSONException e) { - Log.e(TAG, "fetch: ", e); - } - }, 1000); - return; - } + private void fetch(final String queryHash, + final String variables, + final String arg1, + final String arg2, + final ServiceCallback callback) { final Map queryMap = new HashMap<>(); - queryMap.put("query_hash", "c699b185975935ae2a457f24075de8c7"); - queryMap.put("variables", "{" + - "\"fetch_media_item_count\":" + maxItemsToLoad + "," + - "\"fetch_like\":3,\"has_stories\":false,\"has_stories\":false,\"has_threaded_comments\":true," + - "\"fetch_media_item_cursor\":\"" + (cursor == null ? "" : cursor) + "\"" + - "}"); + queryMap.put("query_hash", queryHash); + queryMap.put("variables", variables); final Call request = repository.fetch(queryMap); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { try { // Log.d(TAG, "onResponse: body: " + response.body()); - final PostsFetchResponse postsFetchResponse = parseResponse(response); + final PostsFetchResponse postsFetchResponse = parsePostResponse(response, arg1, arg2); if (callback != null) { callback.onSuccess(postsFetchResponse); } @@ -115,26 +86,111 @@ public class FeedService extends BaseService { } } }); + } + public void fetchFeed(final int maxItemsToLoad, + final String cursor, + final ServiceCallback callback) { + if (loadFromMock) { + final Handler handler = new Handler(); + handler.postDelayed(() -> { + final ClassLoader classLoader = getClass().getClassLoader(); + if (classLoader == null) { + Log.e(TAG, "fetch: classLoader is null!"); + return; + } + try (InputStream resourceAsStream = classLoader.getResourceAsStream("feed_response.json"); + Reader in = new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8)) { + final int bufferSize = 1024; + final char[] buffer = new char[bufferSize]; + final StringBuilder out = new StringBuilder(); + int charsRead; + while ((charsRead = in.read(buffer, 0, buffer.length)) > 0) { + out.append(buffer, 0, charsRead); + } + callback.onSuccess(parseResponseBody(out.toString(), Constants.EXTRAS_USER, "edge_web_feed_timeline")); + } catch (IOException | JSONException e) { + Log.e(TAG, "fetch: ", e); + } + }, 1000); + return; + } + fetch("c699b185975935ae2a457f24075de8c7", + "{\"fetch_media_item_count\":" + maxItemsToLoad + "," + + "\"fetch_like\":3,\"has_stories\":false,\"has_stories\":false,\"has_threaded_comments\":true," + + "\"fetch_media_item_cursor\":\"" + (cursor == null ? "" : cursor) + "\"}", + Constants.EXTRAS_USER, + "edge_web_feed_timeline", + callback); + } + + public void fetchLocationPosts(@NonNull final String locationId, + final String maxId, + final ServiceCallback callback) { + fetch("36bd0f2bf5911908de389b8ceaa3be6d", + "{\"id\":\"" + locationId + "\"," + + "\"first\":25," + + "\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", + Constants.EXTRAS_LOCATION, + "edge_location_to_media", + callback); + } + + public void fetchHashtagPosts(@NonNull final String tag, + final String maxId, + final ServiceCallback callback) { + fetch("9b498c08113f1e09617a1703c22b2f32", + "{\"tag_name\":\"" + tag + "\"," + + "\"first\":25," + + "\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", + Constants.EXTRAS_HASHTAG, + "edge_hashtag_to_media", + callback); + } + + public void fetchProfilePosts(@NonNull final String profileId, + final int postsPerPage, + final String maxId, + final ServiceCallback callback) { + fetch("18a7b935ab438c4514b1f742d8fa07a7", + "{\"id\":\"" + profileId + "\"," + + "\"first\":" + postsPerPage + "," + + "\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", + Constants.EXTRAS_USER, + "edge_owner_to_timeline_media", + callback); + } + + public void fetchTaggedPosts(@NonNull final String profileId, + final int postsPerPage, + final String maxId, + final ServiceCallback callback) { + fetch("31fe64d9463cbbe58319dced405c6206", + "{\"id\":\"" + profileId + "\"," + + "\"first\":" + postsPerPage + "," + + "\"after\":\"" + (maxId == null ? "" : maxId) + "\"}", + Constants.EXTRAS_USER, + "edge_user_to_photos_of_you", + callback); } @NonNull - private PostsFetchResponse parseResponse(@NonNull final Response response) throws JSONException { + private PostsFetchResponse parsePostResponse(@NonNull final Response response, @NonNull final String arg1, @NonNull final String arg2) throws JSONException { if (TextUtils.isEmpty(response.body())) { Log.e(TAG, "parseResponse: feed response body is empty with status code: " + response.code()); return new PostsFetchResponse(Collections.emptyList(), false, null); } - return parseResponseBody(response.body()); + return parseResponseBody(response.body(), arg1, arg2); } @NonNull - private PostsFetchResponse parseResponseBody(@NonNull final String body) + private PostsFetchResponse parseResponseBody(@NonNull final String body, @NonNull final String arg1, @NonNull final String arg2) throws JSONException { final List feedModels = new ArrayList<>(); final JSONObject timelineFeed = new JSONObject(body) .getJSONObject("data") - .getJSONObject(Constants.EXTRAS_USER) - .getJSONObject("edge_web_feed_timeline"); + .getJSONObject(arg1) + .getJSONObject(arg2); final String endCursor; final boolean hasNextPage; diff --git a/app/src/main/java/awais/instagrabber/webservices/LocationService.java b/app/src/main/java/awais/instagrabber/webservices/LocationService.java index 241453be..d0bbe7c2 100644 --- a/app/src/main/java/awais/instagrabber/webservices/LocationService.java +++ b/app/src/main/java/awais/instagrabber/webservices/LocationService.java @@ -19,6 +19,7 @@ import java.util.Objects; import awais.instagrabber.models.FeedModel; import awais.instagrabber.repositories.LocationRepository; +import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.TextUtils; import retrofit2.Call; @@ -29,7 +30,7 @@ import retrofit2.Retrofit; public class LocationService extends BaseService { private static final String TAG = "LocationService"; - private final LocationRepository repository, webRepository; + private final LocationRepository repository; private static LocationService instance; @@ -38,10 +39,6 @@ public class LocationService extends BaseService { .baseUrl("https://i.instagram.com") .build(); repository = retrofit.create(LocationRepository.class); - final Retrofit webRetrofit = getRetrofitBuilder() - .baseUrl("https://www.instagram.com") - .build(); - webRepository = webRetrofit.create(LocationRepository.class); } public static LocationService getInstance() { @@ -53,7 +50,7 @@ public class LocationService extends BaseService { public void fetchPosts(@NonNull final String locationId, final String maxId, - final ServiceCallback callback) { + final ServiceCallback callback) { final ImmutableMap.Builder builder = ImmutableMap.builder(); if (!TextUtils.isEmpty(maxId)) { builder.put("max_id", maxId); @@ -71,7 +68,7 @@ public class LocationService extends BaseService { callback.onSuccess(null); return; } - final LocationPostsFetchResponse tagPostsFetchResponse = parseResponse(body); + final PostsFetchResponse tagPostsFetchResponse = parseResponse(body); callback.onSuccess(tagPostsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); @@ -88,7 +85,7 @@ public class LocationService extends BaseService { }); } - private LocationPostsFetchResponse parseResponse(@NonNull final String body) throws JSONException { + private PostsFetchResponse parseResponse(@NonNull final String body) throws JSONException { final JSONObject root = new JSONObject(body); final boolean moreAvailable = root.optBoolean("more_available"); final String nextMaxId = root.optString("next_max_id"); @@ -96,12 +93,10 @@ public class LocationService extends BaseService { final String status = root.optString("status"); final JSONArray itemsJson = root.optJSONArray("items"); final List items = parseItems(itemsJson); - return new LocationPostsFetchResponse( + return new PostsFetchResponse( + items, moreAvailable, - nextMaxId, - numResults, - status, - items + nextMaxId ); } @@ -122,174 +117,4 @@ public class LocationService extends BaseService { } return feedModels; } - - public void fetchGraphQLPosts(@NonNull final String locationId, - final String maxId, - final ServiceCallback callback) { - final Map queryMap = new HashMap<>(); - queryMap.put("query_hash", "36bd0f2bf5911908de389b8ceaa3be6d"); - queryMap.put("variables", "{" + - "\"id\":\"" + locationId + "\"," + - "\"first\":25," + - "\"after\":\"" + (maxId == null ? "" : maxId) + "\"" + - "}"); - final Call request = webRepository.fetchGraphQLPosts(queryMap); - request.enqueue(new Callback() { - @Override - public void onResponse(@NonNull final Call call, @NonNull final Response response) { - try { - if (callback == null) { - return; - } - final String body = response.body(); - if (TextUtils.isEmpty(body)) { - callback.onSuccess(null); - return; - } - final LocationPostsFetchResponse tagPostsFetchResponse = parseGraphQLResponse(body); - callback.onSuccess(tagPostsFetchResponse); - } catch (JSONException e) { - Log.e(TAG, "onResponse", e); - callback.onFailure(e); - } - } - - @Override - public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { - if (callback != null) { - callback.onFailure(t); - } - } - }); - } - - private LocationPostsFetchResponse parseGraphQLResponse(@NonNull final String body) throws JSONException { - final JSONObject rootroot = new JSONObject(body); - final JSONObject root = rootroot.getJSONObject("data").getJSONObject("location").getJSONObject("edge_location_to_media"); - final boolean moreAvailable = root.getJSONObject("page_info").optBoolean("has_next_page"); - final String nextMaxId = root.getJSONObject("page_info").optString("end_cursor"); - final int numResults = root.optInt("count"); - final String status = rootroot.optString("status"); - final JSONArray itemsJson = root.optJSONArray("edges"); - final List items = parseGraphQLItems(itemsJson); - return new LocationPostsFetchResponse( - moreAvailable, - nextMaxId, - numResults, - status, - items - ); - } - - private List parseGraphQLItems(final JSONArray items) throws JSONException { - if (items == null) { - return Collections.emptyList(); - } - final List feedModels = new ArrayList<>(); - for (int i = 0; i < items.length(); i++) { - final JSONObject itemJson = items.optJSONObject(i); - if (itemJson == null) { - continue; - } - final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson); - if (feedModel != null) { - feedModels.add(feedModel); - } - } - return feedModels; - } - - public static class LocationPostsFetchResponse { - private boolean moreAvailable; - private String nextMaxId; - private int numResults; - private String status; - private List items; - - public LocationPostsFetchResponse(final boolean moreAvailable, - final String nextMaxId, - final int numResults, - final String status, - final List items) { - this.moreAvailable = moreAvailable; - this.nextMaxId = nextMaxId; - this.numResults = numResults; - this.status = status; - this.items = items; - } - - public boolean isMoreAvailable() { - return moreAvailable; - } - - public LocationPostsFetchResponse setMoreAvailable(final boolean moreAvailable) { - this.moreAvailable = moreAvailable; - return this; - } - - public String getNextMaxId() { - return nextMaxId; - } - - public LocationPostsFetchResponse setNextMaxId(final String nextMaxId) { - this.nextMaxId = nextMaxId; - return this; - } - - public int getNumResults() { - return numResults; - } - - public LocationPostsFetchResponse setNumResults(final int numResults) { - this.numResults = numResults; - return this; - } - - public String getStatus() { - return status; - } - - public LocationPostsFetchResponse setStatus(final String status) { - this.status = status; - return this; - } - - public List getItems() { - return items; - } - - public LocationPostsFetchResponse setItems(final List items) { - this.items = items; - return this; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final LocationPostsFetchResponse that = (LocationPostsFetchResponse) o; - return moreAvailable == that.moreAvailable && - numResults == that.numResults && - Objects.equals(nextMaxId, that.nextMaxId) && - Objects.equals(status, that.status) && - Objects.equals(items, that.items); - } - - @Override - public int hashCode() { - return Objects.hash(moreAvailable, nextMaxId, numResults, status, items); - } - - @NonNull - @Override - public String toString() { - return "LocationPostsFetchResponse{" + - "moreAvailable=" + moreAvailable + - ", nextMaxId='" + nextMaxId + '\'' + - ", numResults=" + numResults + - ", status='" + status + '\'' + - ", items=" + items + - '}'; - } - } } diff --git a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java index 9ba5a620..8e3c4c6a 100644 --- a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java +++ b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java @@ -12,15 +12,9 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; import awais.instagrabber.models.FeedModel; -import awais.instagrabber.models.PostChild; -import awais.instagrabber.models.ProfileModel; -import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.repositories.ProfileRepository; import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.UserInfo; @@ -36,7 +30,6 @@ public class ProfileService extends BaseService { private static final String TAG = "ProfileService"; private final ProfileRepository repository; - private final ProfileRepository wwwRepository; private static ProfileService instance; @@ -44,11 +37,7 @@ public class ProfileService extends BaseService { final Retrofit retrofit = getRetrofitBuilder() .baseUrl("https://i.instagram.com") .build(); - final Retrofit wwwRetrofit = getRetrofitBuilder() - .baseUrl("https://www.instagram.com") - .build(); repository = retrofit.create(ProfileRepository.class); - wwwRepository = wwwRetrofit.create(ProfileRepository.class); } public static ProfileService getInstance() { @@ -89,32 +78,31 @@ public class ProfileService extends BaseService { }); } - public void fetchPosts(final ProfileModel profileModel, - final int postsPerPage, - final String cursor, + public void fetchPosts(final String userId, + final String maxId, final ServiceCallback callback) { - final Map queryMap = new HashMap<>(); - queryMap.put("query_hash", "18a7b935ab438c4514b1f742d8fa07a7"); - queryMap.put("variables", "{" + - "\"id\":\"" + profileModel.getId() + "\"," + - "\"first\":" + postsPerPage + "," + - "\"after\":\"" + (cursor == null ? "" : cursor) + "\"" + - "}"); - final Call request = wwwRepository.fetch(queryMap); + final ImmutableMap.Builder builder = ImmutableMap.builder(); + if (!TextUtils.isEmpty(maxId)) { + builder.put("max_id", maxId); + } + final Call request = repository.fetch(userId, builder.build()); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { try { - // Log.d(TAG, "onResponse: body: " + response.body()); - final PostsFetchResponse postsFetchResponse = parseResponse(profileModel, response); - if (callback != null) { - callback.onSuccess(postsFetchResponse); + if (callback == null) { + return; } + final String body = response.body(); + if (TextUtils.isEmpty(body)) { + callback.onSuccess(null); + return; + } + final PostsFetchResponse postsFetchResponse = parseProfilePostsResponse(body, false); + callback.onSuccess(postsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); - if (callback != null) { - callback.onFailure(e); - } + callback.onFailure(e); } } @@ -127,48 +115,8 @@ public class ProfileService extends BaseService { }); } - private PostsFetchResponse parseResponse(final ProfileModel profileModel, final Response response) throws JSONException { - if (TextUtils.isEmpty(response.body())) { - Log.e(TAG, "parseResponse: feed response body is empty with status code: " + response.code()); - return new PostsFetchResponse(Collections.emptyList(), false, null); - } - return parseResponseBody(profileModel, response.body()); - } - - private PostsFetchResponse parseResponseBody(final ProfileModel profileModel, final String body) throws JSONException { - // Log.d(TAG, "parseResponseBody: body: " + body); - final List feedModels = new ArrayList<>(); - // return new FeedFetchResponse(feedModels, false, null); - final JSONObject mediaPosts = new JSONObject(body) - .getJSONObject("data") - .getJSONObject(Constants.EXTRAS_USER) - .getJSONObject("edge_owner_to_timeline_media"); - final String endCursor; - final boolean hasNextPage; - final JSONObject pageInfo = mediaPosts.getJSONObject("page_info"); - if (pageInfo.has("has_next_page")) { - hasNextPage = pageInfo.getBoolean("has_next_page"); - endCursor = hasNextPage ? pageInfo.getString("end_cursor") : null; - } else { - hasNextPage = false; - endCursor = null; - } - final JSONArray edges = mediaPosts.getJSONArray("edges"); - for (int i = 0; i < edges.length(); ++i) { - final JSONObject itemJson = edges.optJSONObject(i); - if (itemJson == null) { - continue; - } - final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson); - if (feedModel != null) { - feedModels.add(feedModel); - } - } - return new PostsFetchResponse(feedModels, hasNextPage, endCursor); - } - public void fetchSaved(final String maxId, - final ServiceCallback callback) { + final ServiceCallback callback) { final ImmutableMap.Builder builder = ImmutableMap.builder(); if (!TextUtils.isEmpty(maxId)) { builder.put("max_id", maxId); @@ -186,8 +134,8 @@ public class ProfileService extends BaseService { callback.onSuccess(null); return; } - final SavedPostsFetchResponse savedPostsFetchResponse = parseSavedPostsResponse(body, true); - callback.onSuccess(savedPostsFetchResponse); + final PostsFetchResponse PostsFetchResponse = parseSavedPostsResponse(body, true); + callback.onSuccess(PostsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); callback.onFailure(e); @@ -204,7 +152,7 @@ public class ProfileService extends BaseService { } public void fetchLiked(final String maxId, - final ServiceCallback callback) { + final ServiceCallback callback) { final ImmutableMap.Builder builder = ImmutableMap.builder(); if (!TextUtils.isEmpty(maxId)) { builder.put("max_id", maxId); @@ -222,8 +170,8 @@ public class ProfileService extends BaseService { callback.onSuccess(null); return; } - final SavedPostsFetchResponse savedPostsFetchResponse = parseSavedPostsResponse(body, false); - callback.onSuccess(savedPostsFetchResponse); + final PostsFetchResponse PostsFetchResponse = parseSavedPostsResponse(body, false); + callback.onSuccess(PostsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); callback.onFailure(e); @@ -240,17 +188,13 @@ public class ProfileService extends BaseService { } public void fetchTagged(final String profileId, - final int postsPerPage, - final String cursor, - final ServiceCallback callback) { - final Map queryMap = new HashMap<>(); - queryMap.put("query_hash", "31fe64d9463cbbe58319dced405c6206"); - queryMap.put("variables", "{" + - "\"id\":\"" + profileId + "\"," + - "\"first\":" + postsPerPage + "," + - "\"after\":\"" + (cursor == null ? "" : cursor) + "\"" + - "}"); - final Call request = wwwRepository.fetch(queryMap); + final String maxId, + final ServiceCallback callback) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + if (!TextUtils.isEmpty(maxId)) { + builder.put("max_id", maxId); + } + final Call request = repository.fetchTagged(profileId, builder.build()); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -263,8 +207,8 @@ public class ProfileService extends BaseService { callback.onSuccess(null); return; } - final SavedPostsFetchResponse savedPostsFetchResponse = parseTaggedPostsResponse(body); - callback.onSuccess(savedPostsFetchResponse); + final PostsFetchResponse PostsFetchResponse = parseSavedPostsResponse(body, false); + callback.onSuccess(PostsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); callback.onFailure(e); @@ -280,7 +224,7 @@ public class ProfileService extends BaseService { }); } - private SavedPostsFetchResponse parseSavedPostsResponse(final String body, final boolean isInMedia) throws JSONException { + private PostsFetchResponse parseProfilePostsResponse(final String body, final boolean isInMedia) throws JSONException { final JSONObject root = new JSONObject(body); final boolean moreAvailable = root.optBoolean("more_available"); final String nextMaxId = root.optString("next_max_id"); @@ -288,48 +232,26 @@ public class ProfileService extends BaseService { final String status = root.optString("status"); final JSONArray itemsJson = root.optJSONArray("items"); final List items = parseItems(itemsJson, isInMedia); - return new SavedPostsFetchResponse( + return new PostsFetchResponse( + items, moreAvailable, - nextMaxId, - numResults, - status, - items + nextMaxId ); } - @NonNull - private SavedPostsFetchResponse parseTaggedPostsResponse(@NonNull final String body) - throws JSONException { - final List feedModels = new ArrayList<>(); - final JSONObject timelineFeed = new JSONObject(body) - .getJSONObject("data") - .getJSONObject(Constants.EXTRAS_USER) - .getJSONObject("edge_user_to_photos_of_you"); - final String endCursor; - final boolean hasNextPage; - - final JSONObject pageInfo = timelineFeed.getJSONObject("page_info"); - if (pageInfo.has("has_next_page")) { - hasNextPage = pageInfo.getBoolean("has_next_page"); - endCursor = hasNextPage ? pageInfo.getString("end_cursor") : null; - } else { - hasNextPage = false; - endCursor = null; - } - - final JSONArray feedItems = timelineFeed.getJSONArray("edges"); - - for (int i = 0; i < feedItems.length(); ++i) { - final JSONObject itemJson = feedItems.optJSONObject(i); - if (itemJson == null) { - continue; - } - final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson); - if (feedModel != null) { - feedModels.add(feedModel); - } - } - return new SavedPostsFetchResponse(hasNextPage, endCursor, timelineFeed.getInt("count"), "ok", feedModels); + private PostsFetchResponse parseSavedPostsResponse(final String body, final boolean isInMedia) throws JSONException { + final JSONObject root = new JSONObject(body); + final boolean moreAvailable = root.optBoolean("more_available"); + final String nextMaxId = root.optString("next_max_id"); + final int numResults = root.optInt("num_results"); + final String status = root.optString("status"); + final JSONArray itemsJson = root.optJSONArray("items"); + final List items = parseItems(itemsJson, isInMedia); + return new PostsFetchResponse( + items, + moreAvailable, + nextMaxId + ); } private List parseItems(final JSONArray items, final boolean isInMedia) throws JSONException { @@ -349,98 +271,4 @@ public class ProfileService extends BaseService { } return feedModels; } - - public static class SavedPostsFetchResponse { - private boolean moreAvailable; - private String nextMaxId; - private int numResults; - private String status; - private List items; - - public SavedPostsFetchResponse(final boolean moreAvailable, - final String nextMaxId, - final int numResults, - final String status, - final List items) { - this.moreAvailable = moreAvailable; - this.nextMaxId = nextMaxId; - this.numResults = numResults; - this.status = status; - this.items = items; - } - - public boolean isMoreAvailable() { - return moreAvailable; - } - - public SavedPostsFetchResponse setMoreAvailable(final boolean moreAvailable) { - this.moreAvailable = moreAvailable; - return this; - } - - public String getNextMaxId() { - return nextMaxId; - } - - public SavedPostsFetchResponse setNextMaxId(final String nextMaxId) { - this.nextMaxId = nextMaxId; - return this; - } - - public int getNumResults() { - return numResults; - } - - public SavedPostsFetchResponse setNumResults(final int numResults) { - this.numResults = numResults; - return this; - } - - public String getStatus() { - return status; - } - - public SavedPostsFetchResponse setStatus(final String status) { - this.status = status; - return this; - } - - public List getItems() { - return items; - } - - public SavedPostsFetchResponse setItems(final List items) { - this.items = items; - return this; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final SavedPostsFetchResponse that = (SavedPostsFetchResponse) o; - return moreAvailable == that.moreAvailable && - numResults == that.numResults && - Objects.equals(nextMaxId, that.nextMaxId) && - Objects.equals(status, that.status) && - Objects.equals(items, that.items); - } - - @Override - public int hashCode() { - return Objects.hash(moreAvailable, nextMaxId, numResults, status, items); - } - - @NonNull - @Override - public String toString() { - return "SavedPostsFetchResponse{" + - "moreAvailable=" + moreAvailable + - ", nextMaxId='" + nextMaxId + '\'' + - ", numResults=" + numResults + - ", status='" + status + '\'' + - ", items=" + items + - '}'; - } - } } diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index d5a0c723..a0d93d3c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.UUID; import awais.instagrabber.models.FeedStoryModel; +import awais.instagrabber.models.HighlightModel; import awais.instagrabber.models.ProfileModel; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.MediaItemType; @@ -33,6 +34,7 @@ import awais.instagrabber.repositories.StoriesRepository; import awais.instagrabber.repositories.responses.StoryStickerResponse; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.ResponseBodyUtils; +import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import retrofit2.Call; import retrofit2.Callback; @@ -92,7 +94,7 @@ public class StoriesService extends BaseService { form.put("_uuid", UUID.randomUUID().toString()); form.put("supported_capabilities_new", Constants.SUPPORTED_CAPABILITIES); final Map signedForm = Utils.sign(form); - final Call response = repository.getStories(Constants.I_USER_AGENT, signedForm); + final Call response = repository.getFeedStories(Constants.I_USER_AGENT, signedForm); response.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -134,6 +136,52 @@ public class StoriesService extends BaseService { } } + public void fetchHighlights(final String profileId, + final ServiceCallback> callback) { + final Call request = repository.fetchHighlights(profileId); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + try { + if (callback == null) { + return; + } + final String body = response.body(); + if (TextUtils.isEmpty(body)) { + callback.onSuccess(null); + return; + } + final JSONArray highlightsReel = new JSONObject(body).getJSONArray("tray"); + + final int length = highlightsReel.length(); + final List highlightModels = new ArrayList<>(); + // final String[] highlightIds = new String[length]; + for (int i = 0; i < length; ++i) { + final JSONObject highlightNode = highlightsReel.getJSONObject(i); + highlightModels.add(new HighlightModel( + highlightNode.getString("title"), + highlightNode.getString(Constants.EXTRAS_ID), + highlightNode.getJSONObject("cover_media") + .getJSONObject("cropped_image_version") + .getString("url") + )); + } + callback.onSuccess(highlightModels); + } catch (JSONException e) { + Log.e(TAG, "onResponse", e); + callback.onFailure(e); + } + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); + } + public void getUserStory(final String id, final String username, final boolean isLoc, diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java index 5aabaee1..5786e82f 100644 --- a/app/src/main/java/awais/instagrabber/webservices/TagsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java @@ -19,6 +19,7 @@ import java.util.Objects; import awais.instagrabber.models.FeedModel; import awais.instagrabber.repositories.TagsRepository; +import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.ResponseBodyUtils; import awais.instagrabber.utils.TextUtils; @@ -118,8 +119,8 @@ public class TagsService extends BaseService { public void fetchPosts(@NonNull final String tag, final String maxId, - final ServiceCallback callback) { - final ImmutableMap.Builder builder = ImmutableMap.builder(); + final ServiceCallback callback) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); if (!TextUtils.isEmpty(maxId)) { builder.put("max_id", maxId); } @@ -136,7 +137,7 @@ public class TagsService extends BaseService { callback.onSuccess(null); return; } - final TagPostsFetchResponse tagPostsFetchResponse = parseResponse(body); + final PostsFetchResponse tagPostsFetchResponse = parseResponse(body); callback.onSuccess(tagPostsFetchResponse); } catch (JSONException e) { Log.e(TAG, "onResponse", e); @@ -153,7 +154,7 @@ public class TagsService extends BaseService { }); } - private TagPostsFetchResponse parseResponse(@NonNull final String body) throws JSONException { + private PostsFetchResponse parseResponse(@NonNull final String body) throws JSONException { final JSONObject root = new JSONObject(body); final boolean moreAvailable = root.optBoolean("more_available"); final String nextMaxId = root.optString("next_max_id"); @@ -161,12 +162,10 @@ public class TagsService extends BaseService { final String status = root.optString("status"); final JSONArray itemsJson = root.optJSONArray("items"); final List items = parseItems(itemsJson); - return new TagPostsFetchResponse( + return new PostsFetchResponse( + items, moreAvailable, - nextMaxId, - numResults, - status, - items + nextMaxId ); } @@ -187,174 +186,4 @@ public class TagsService extends BaseService { } return feedModels; } - - public void fetchGraphQLPosts(@NonNull final String tag, - final String maxId, - final ServiceCallback callback) { - final Map queryMap = new HashMap<>(); - queryMap.put("query_hash", "9b498c08113f1e09617a1703c22b2f32"); - queryMap.put("variables", "{" + - "\"tag_name\":\"" + tag + "\"," + - "\"first\":25," + - "\"after\":\"" + (maxId == null ? "" : maxId) + "\"" + - "}"); - final Call request = webRepository.fetchGraphQLPosts(queryMap); - request.enqueue(new Callback() { - @Override - public void onResponse(@NonNull final Call call, @NonNull final Response response) { - try { - if (callback == null) { - return; - } - final String body = response.body(); - if (TextUtils.isEmpty(body)) { - callback.onSuccess(null); - return; - } - final TagPostsFetchResponse tagPostsFetchResponse = parseGraphQLResponse(body); - callback.onSuccess(tagPostsFetchResponse); - } catch (JSONException e) { - Log.e(TAG, "onResponse", e); - callback.onFailure(e); - } - } - - @Override - public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { - if (callback != null) { - callback.onFailure(t); - } - } - }); - } - - private TagPostsFetchResponse parseGraphQLResponse(@NonNull final String body) throws JSONException { - final JSONObject rootroot = new JSONObject(body); - final JSONObject root = rootroot.getJSONObject("data").getJSONObject("hashtag").getJSONObject("edge_hashtag_to_media"); - final boolean moreAvailable = root.getJSONObject("page_info").optBoolean("has_next_page"); - final String nextMaxId = root.getJSONObject("page_info").optString("end_cursor"); - final int numResults = root.optInt("count"); - final String status = rootroot.optString("status"); - final JSONArray itemsJson = root.optJSONArray("edges"); - final List items = parseGraphQLItems(itemsJson); - return new TagPostsFetchResponse( - moreAvailable, - nextMaxId, - numResults, - status, - items - ); - } - - private List parseGraphQLItems(final JSONArray items) throws JSONException { - if (items == null) { - return Collections.emptyList(); - } - final List feedModels = new ArrayList<>(); - for (int i = 0; i < items.length(); i++) { - final JSONObject itemJson = items.optJSONObject(i); - if (itemJson == null) { - continue; - } - final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson); - if (feedModel != null) { - feedModels.add(feedModel); - } - } - return feedModels; - } - - public static class TagPostsFetchResponse { - private boolean moreAvailable; - private String nextMaxId; - private int numResults; - private String status; - private List items; - - public TagPostsFetchResponse(final boolean moreAvailable, - final String nextMaxId, - final int numResults, - final String status, - final List items) { - this.moreAvailable = moreAvailable; - this.nextMaxId = nextMaxId; - this.numResults = numResults; - this.status = status; - this.items = items; - } - - public boolean isMoreAvailable() { - return moreAvailable; - } - - public TagPostsFetchResponse setMoreAvailable(final boolean moreAvailable) { - this.moreAvailable = moreAvailable; - return this; - } - - public String getNextMaxId() { - return nextMaxId; - } - - public TagPostsFetchResponse setNextMaxId(final String nextMaxId) { - this.nextMaxId = nextMaxId; - return this; - } - - public int getNumResults() { - return numResults; - } - - public TagPostsFetchResponse setNumResults(final int numResults) { - this.numResults = numResults; - return this; - } - - public String getStatus() { - return status; - } - - public TagPostsFetchResponse setStatus(final String status) { - this.status = status; - return this; - } - - public List getItems() { - return items; - } - - public TagPostsFetchResponse setItems(final List items) { - this.items = items; - return this; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final TagPostsFetchResponse that = (TagPostsFetchResponse) o; - return moreAvailable == that.moreAvailable && - numResults == that.numResults && - Objects.equals(nextMaxId, that.nextMaxId) && - Objects.equals(status, that.status) && - Objects.equals(items, that.items); - } - - @Override - public int hashCode() { - return Objects.hash(moreAvailable, nextMaxId, numResults, status, items); - } - - @NonNull - @Override - public String toString() { - return "TagPostsFetchResponse{" + - "moreAvailable=" + moreAvailable + - ", nextMaxId='" + nextMaxId + '\'' + - ", numResults=" + numResults + - ", status='" + status + '\'' + - ", items=" + items + - '}'; - } - } } From ae27d5d57a8cbf7a3c959bb9331ff706fd2572a7 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sun, 20 Dec 2020 15:52:09 -0500 Subject: [PATCH 010/101] post likes viewer --- .../instagrabber/adapters/LikesAdapter.java | 45 +++++++ .../viewholder/FollowsViewHolder.java | 2 + .../fragments/LikesViewerFragment.java | 118 ++++++++++++++++++ .../fragments/PostViewV2Fragment.java | 7 +- .../repositories/MediaRepository.java | 4 + .../webservices/MediaService.java | 47 +++++++ app/src/main/res/layout/fragment_likes.xml | 21 ++++ .../navigation/direct_messages_nav_graph.xml | 11 ++ .../res/navigation/discover_nav_graph.xml | 11 ++ .../main/res/navigation/feed_nav_graph.xml | 11 ++ .../main/res/navigation/hashtag_nav_graph.xml | 11 ++ .../main/res/navigation/likes_nav_graph.xml | 40 ++++++ .../res/navigation/location_nav_graph.xml | 11 ++ .../main/res/navigation/more_nav_graph.xml | 1 + .../notification_viewer_nav_graph.xml | 1 + .../main/res/navigation/profile_nav_graph.xml | 12 ++ 16 files changed, 352 insertions(+), 1 deletion(-) create mode 100755 app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java create mode 100644 app/src/main/java/awais/instagrabber/fragments/LikesViewerFragment.java create mode 100644 app/src/main/res/layout/fragment_likes.xml create mode 100644 app/src/main/res/navigation/likes_nav_graph.xml diff --git a/app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java b/app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java new file mode 100755 index 00000000..5592ee6d --- /dev/null +++ b/app/src/main/java/awais/instagrabber/adapters/LikesAdapter.java @@ -0,0 +1,45 @@ +package awais.instagrabber.adapters; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import awais.instagrabber.adapters.viewholder.FollowsViewHolder; +import awais.instagrabber.databinding.ItemFollowBinding; +import awais.instagrabber.models.ProfileModel; + +public final class LikesAdapter extends RecyclerView.Adapter { + private final List profileModels; + private final View.OnClickListener onClickListener; + + public LikesAdapter(final List profileModels, + final View.OnClickListener onClickListener) { + this.profileModels = profileModels; + this.onClickListener = onClickListener; + } + + @NonNull + @Override + public FollowsViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { + final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + final ItemFollowBinding binding = ItemFollowBinding.inflate(layoutInflater, parent, false); + return new FollowsViewHolder(binding); + } + + @Override + public void onBindViewHolder(@NonNull final FollowsViewHolder holder, final int position) { + final ProfileModel model = profileModels.get(position); + holder.bind(model, null, onClickListener); + } + + @Override + public int getItemCount() { + return profileModels.size(); + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java index a9b09de0..6396d4b2 100755 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java @@ -1,5 +1,6 @@ package awais.instagrabber.adapters.viewholder; +import android.util.Log; import android.view.View; import androidx.recyclerview.widget.RecyclerView; @@ -22,6 +23,7 @@ public final class FollowsViewHolder extends RecyclerView.ViewHolder { public void bind(final ProfileModel model, final List admins, final View.OnClickListener onClickListener) { + Log.d("austin_debug", "bind "+model); if (model == null) return; itemView.setTag(model); itemView.setOnClickListener(onClickListener); diff --git a/app/src/main/java/awais/instagrabber/fragments/LikesViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/LikesViewerFragment.java new file mode 100644 index 00000000..40174383 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/fragments/LikesViewerFragment.java @@ -0,0 +1,118 @@ +package awais.instagrabber.fragments; + +import android.content.Context; +import android.content.res.Resources; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.LinearLayoutCompat; +import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavDirections; +import androidx.navigation.fragment.NavHostFragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + +import java.util.Collections; +import java.util.List; + +import awais.instagrabber.BuildConfig; +import awais.instagrabber.R; +import awais.instagrabber.adapters.LikesAdapter; +import awais.instagrabber.databinding.FragmentLikesBinding; +import awais.instagrabber.models.ProfileModel; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.TextUtils; +import awais.instagrabber.utils.Utils; +import awais.instagrabber.webservices.MediaService; +import awais.instagrabber.webservices.ServiceCallback; + +public final class LikesViewerFragment extends BottomSheetDialogFragment implements SwipeRefreshLayout.OnRefreshListener { + private static final String TAG = "LikesViewerFragment"; + + private final String cookie = Utils.settingsHelper.getString(Constants.COOKIE); + + private LikesAdapter likesAdapter; + private FragmentLikesBinding binding; + private LinearLayoutManager layoutManager; + private Resources resources; + private AppCompatActivity fragmentActivity; + private LinearLayoutCompat root; + private MediaService mediaService; + private String postId; + + private final ServiceCallback> cb = new ServiceCallback>() { + @Override + public void onSuccess(final List result) { + final LikesAdapter likesAdapter = new LikesAdapter(result, v -> { + final Object tag = v.getTag(); + if (tag instanceof ProfileModel) { + ProfileModel model = (ProfileModel) tag; + final Bundle bundle = new Bundle(); + bundle.putString("username", "@" + model.getUsername()); + NavHostFragment.findNavController(LikesViewerFragment.this).navigate(R.id.action_global_profileFragment, bundle); + } + }); + binding.rvLikes.setAdapter(likesAdapter); + binding.rvLikes.setLayoutManager(new LinearLayoutManager(getContext())); + binding.swipeRefreshLayout.setRefreshing(false); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error", t); + try { + final Context context = getContext(); + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } + catch (Exception e) {} + } + }; + + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fragmentActivity = (AppCompatActivity) getActivity(); + mediaService = MediaService.getInstance(); + // setHasOptionsMenu(true); + } + + @NonNull + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { + binding = FragmentLikesBinding.inflate(getLayoutInflater()); + binding.swipeRefreshLayout.setEnabled(false); + binding.swipeRefreshLayout.setNestedScrollingEnabled(false); + root = binding.getRoot(); + return root; + } + + @Override + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { + init(); + } + + @Override + public void onRefresh() { + mediaService.fetchLikes(postId, cb); + } + + private void init() { + if (getArguments() == null) return; + final LikesViewerFragmentArgs fragmentArgs = LikesViewerFragmentArgs.fromBundle(getArguments()); + postId = fragmentArgs.getPostId(); + binding.swipeRefreshLayout.setOnRefreshListener(this); + binding.swipeRefreshLayout.setRefreshing(true); + resources = getResources(); + onRefresh(); + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index ad1fd41d..84fea98e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -535,7 +535,12 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { } }); binding.like.setOnLongClickListener(v -> { - Utils.displayToastAboveView(context, v, getString(R.string.like_without_count)); + final NavController navController = getNavController(); + if (navController != null) { + final Bundle bundle = new Bundle(); + bundle.putString("postId", feedModel.getPostId()); + navController.navigate(R.id.action_global_likesViewerFragment, bundle); + } return true; }); } diff --git a/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java b/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java index 048df6ca..f8e42a21 100644 --- a/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java @@ -5,11 +5,15 @@ import java.util.Map; import retrofit2.Call; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; import retrofit2.http.Header; import retrofit2.http.POST; import retrofit2.http.Path; public interface MediaRepository { + @GET("/api/v1/media/{mediaId}/likers/") + Call fetchLikes(@Header("User-Agent") final String userAgent, + @Path("mediaId") final String mediaId); @FormUrlEncoded @POST("/api/v1/media/{mediaId}/{action}/") diff --git a/app/src/main/java/awais/instagrabber/webservices/MediaService.java b/app/src/main/java/awais/instagrabber/webservices/MediaService.java index decbc85f..f41c14cd 100644 --- a/app/src/main/java/awais/instagrabber/webservices/MediaService.java +++ b/app/src/main/java/awais/instagrabber/webservices/MediaService.java @@ -5,15 +5,18 @@ import android.util.Log; import androidx.annotation.NonNull; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import awais.instagrabber.models.ProfileModel; import awais.instagrabber.repositories.MediaRepository; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Utils; @@ -277,4 +280,48 @@ public class MediaService extends BaseService { } }); } + + public void fetchLikes(final String mediaId, + @NonNull final ServiceCallback> callback) { + final Call likesRequest = repository.fetchLikes(Constants.I_USER_AGENT, mediaId); + likesRequest.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final String body = response.body(); + if (body == null) { + Log.e(TAG, "Error occurred while fetching likes of "+mediaId); + callback.onSuccess(null); + return; + } + try { + final JSONObject data = new JSONObject(body); + final JSONArray users = data.getJSONArray("users"); + final int usersLen = users.length(); + final List userModels = new ArrayList<>(); + for (int j = 0; j < usersLen; ++j) { + final JSONObject userObject = users.getJSONObject(j); + userModels.add(new ProfileModel(userObject.optBoolean("is_private"), + false, + userObject.optBoolean("is_verified"), + String.valueOf(userObject.get("pk")), + userObject.getString("username"), + userObject.optString("full_name"), + null, null, + userObject.getString("profile_pic_url"), + null, 0, 0, 0, false, false, false, false, false)); + } + callback.onSuccess(userModels); + } catch (JSONException e) { + // Log.e(TAG, "Error parsing body", e); + callback.onFailure(e); + } + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + Log.e(TAG, "Error getting likes", t); + callback.onFailure(t); + } + }); + } } diff --git a/app/src/main/res/layout/fragment_likes.xml b/app/src/main/res/layout/fragment_likes.xml new file mode 100644 index 00000000..15d2763d --- /dev/null +++ b/app/src/main/res/layout/fragment_likes.xml @@ -0,0 +1,21 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/direct_messages_nav_graph.xml b/app/src/main/res/navigation/direct_messages_nav_graph.xml index 5ce1b064..87686c3d 100644 --- a/app/src/main/res/navigation/direct_messages_nav_graph.xml +++ b/app/src/main/res/navigation/direct_messages_nav_graph.xml @@ -63,6 +63,17 @@ app:nullable="false" /> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/navigation/likes_nav_graph.xml b/app/src/main/res/navigation/likes_nav_graph.xml new file mode 100644 index 00000000..bd5a2de5 --- /dev/null +++ b/app/src/main/res/navigation/likes_nav_graph.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/location_nav_graph.xml b/app/src/main/res/navigation/location_nav_graph.xml index b787f9eb..100760b3 100644 --- a/app/src/main/res/navigation/location_nav_graph.xml +++ b/app/src/main/res/navigation/location_nav_graph.xml @@ -24,6 +24,17 @@ app:nullable="false" /> + + + + + + diff --git a/app/src/main/res/navigation/more_nav_graph.xml b/app/src/main/res/navigation/more_nav_graph.xml index 50d9cf54..1df73665 100644 --- a/app/src/main/res/navigation/more_nav_graph.xml +++ b/app/src/main/res/navigation/more_nav_graph.xml @@ -8,6 +8,7 @@ + + + + + + + + + Date: Sun, 20 Dec 2020 15:54:47 -0500 Subject: [PATCH 011/101] New Crowdin updates (#425) * New translations arrays.xml (Odia) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Indonesian) * New translations arrays.xml (Persian) * New translations strings.xml (Persian) * New translations arrays.xml (Hindi) * New translations strings.xml (Hindi) * New translations strings.xml (Odia) * New translations strings.xml (Vietnamese) * New translations arrays.xml (Catalan) * New translations strings.xml (Catalan) * New translations arrays.xml (Russian) * New translations strings.xml (Russian) * New translations arrays.xml (Dutch) * New translations strings.xml (Dutch) * New translations arrays.xml (Vietnamese) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Spanish) * New translations strings.xml (Czech) * New translations arrays.xml (German) * New translations strings.xml (German) * New translations arrays.xml (Macedonian) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Macedonian) * New translations arrays.xml (Polish) * New translations strings.xml (Polish) * New translations arrays.xml (Turkish) * New translations strings.xml (Turkish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Kannada) * Update source file strings.xml * New translations strings.xml (French) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Catalan) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Vietnamese) * New translations strings.xml (Vietnamese) * New translations strings.xml (Odia) * New translations strings.xml (Italian) * New translations strings.xml (Vietnamese) * New translations strings.xml (Spanish) * New translations strings.xml (French) * New translations strings.xml (Odia) * New translations strings.xml (Odia) * New translations strings.xml (Odia) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Indonesian) * New translations strings.xml (Persian) * New translations strings.xml (Hindi) * New translations strings.xml (Odia) * New translations strings.xml (Vietnamese) * New translations strings.xml (Catalan) * New translations strings.xml (Russian) * New translations strings.xml (Dutch) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Spanish) * New translations strings.xml (Czech) * New translations strings.xml (German) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Macedonian) * New translations strings.xml (Polish) * New translations strings.xml (Turkish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Kannada) * Update source file strings.xml * New translations strings.xml (Spanish) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Indonesian) * New translations strings.xml (Persian) * New translations strings.xml (Hindi) * New translations strings.xml (Odia) * New translations strings.xml (Vietnamese) * New translations strings.xml (Catalan) * New translations strings.xml (Russian) * New translations strings.xml (Dutch) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Spanish) * New translations strings.xml (Czech) * New translations strings.xml (German) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Macedonian) * New translations strings.xml (Polish) * New translations strings.xml (Turkish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Kannada) * Update source file strings.xml * New translations strings.xml (Spanish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Spanish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Turkish) * New translations strings.xml (Italian) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Portuguese, Brazilian) --- app/src/main/res/values-ca/arrays.xml | 2 +- app/src/main/res/values-ca/strings.xml | 23 ++++- app/src/main/res/values-cs/strings.xml | 29 +++++- app/src/main/res/values-de/arrays.xml | 2 +- app/src/main/res/values-de/strings.xml | 23 ++++- app/src/main/res/values-es/strings.xml | 23 ++++- app/src/main/res/values-fa/arrays.xml | 2 +- app/src/main/res/values-fa/strings.xml | 23 ++++- app/src/main/res/values-fr/strings.xml | 23 ++++- app/src/main/res/values-hi/arrays.xml | 2 +- app/src/main/res/values-hi/strings.xml | 23 ++++- app/src/main/res/values-in/strings.xml | 20 +++- app/src/main/res/values-it/strings.xml | 23 ++++- app/src/main/res/values-kn/strings.xml | 23 ++++- app/src/main/res/values-mk/arrays.xml | 2 +- app/src/main/res/values-mk/strings.xml | 23 ++++- app/src/main/res/values-nl/arrays.xml | 2 +- app/src/main/res/values-nl/strings.xml | 23 ++++- app/src/main/res/values-or/arrays.xml | 2 +- app/src/main/res/values-or/strings.xml | 65 ++++++++----- app/src/main/res/values-pl/arrays.xml | 2 +- app/src/main/res/values-pl/strings.xml | 29 +++++- app/src/main/res/values-pt/strings.xml | 35 +++++-- app/src/main/res/values-ru/arrays.xml | 2 +- app/src/main/res/values-ru/strings.xml | 29 +++++- app/src/main/res/values-tr/arrays.xml | 2 +- app/src/main/res/values-tr/strings.xml | 25 ++++- app/src/main/res/values-vi/arrays.xml | 2 +- app/src/main/res/values-vi/strings.xml | 106 ++++++++++++--------- app/src/main/res/values-zh-rCN/strings.xml | 20 +++- app/src/main/res/values-zh-rTW/strings.xml | 22 ++++- 31 files changed, 469 insertions(+), 163 deletions(-) diff --git a/app/src/main/res/values-ca/arrays.xml b/app/src/main/res/values-ca/arrays.xml index 39224cd2..3c898f93 100644 --- a/app/src/main/res/values-ca/arrays.xml +++ b/app/src/main/res/values-ca/arrays.xml @@ -2,7 +2,7 @@ Predeterminat del sistema - Anglès + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 525ecc2e..c14d0abc 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -42,10 +42,15 @@ Utilitza Instadp per a les imatges del perfil d\'alta definició Importar/Exportar Llengua - %s\nPublicacions - %s Publicacions - %s\n Seguidors - %s\n Seguint + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Reproduir vídeos automàticament Silenciar sempre els vídeos Seleccionar el que s\'ha de descarregar @@ -63,9 +68,15 @@ Contestar Resposta… Has contestat amb èxit! + + %d response averaging %s + %d mitjana de respostes %s + + La teva resposta: %s Respon a la història Resposta… Qüestionari + Desplaçador Ja has contestat! Mencions Aquest compte és privat @@ -98,6 +109,9 @@ Desbloquejar Restringir Deixar de restringir + Following each other + Followed by you + Following you Mapa Exportar Importar @@ -305,4 +319,5 @@ %d comentari %d comentaris + Storage permission not granted! diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index bb0a00a0..7cb1d43c 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -42,10 +42,19 @@ Use Instadp for high definition profile pictures Import/Export Language - %s\nPosts - %s Posts - %s\nFollowers - %s\nFollowing + + %s Post + %s Posts + %s Posts + %s Posts + + + %s Follower + %s Followers + %s Followers + %s Followers + + %s Following Autoplay videos Always mute videos Select what to download @@ -63,9 +72,17 @@ Respond Answer… Answer successful! + + %d response averaging %s + %d responses averaging %s + %d responses averaging %s + %d responses averaging %s + + Your answer: %s Reply to story Reply… Quiz + Slider You have already answered! Mentions This Account is Private @@ -98,6 +115,9 @@ Unblock Restrict Unrestrict + Following each other + Followed by you + Following you Map Export Import @@ -309,4 +329,5 @@ %d comments %d comments + Storage permission not granted! diff --git a/app/src/main/res/values-de/arrays.xml b/app/src/main/res/values-de/arrays.xml index 845a4b87..5a8c3811 100644 --- a/app/src/main/res/values-de/arrays.xml +++ b/app/src/main/res/values-de/arrays.xml @@ -2,7 +2,7 @@ Systemstandard - Englisch + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index e2905481..a852568c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -42,10 +42,15 @@ Instadp für hochauflösende Profilbilder verwenden Importieren/Exportieren Sprache - %s\nBeiträge - %s Beiträge - %s\nAbonnenten - %s\nAbonniert + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Videos automatisch abspielen Videos immer stummschalten Datei zum Download auswählen @@ -63,9 +68,15 @@ Antworten Antworten… Antwort erfolgreich! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s Auf Story antworten Antworten… Quiz + Slider Du hast bereits geantwortet! Erwähnungen Dieser Account ist privat @@ -98,6 +109,9 @@ Nicht mehr blockieren Einschränken Nicht mehr einschränken + Following each other + Followed by you + Following you Karte Exportieren Importieren @@ -305,4 +319,5 @@ %d Kommentar %d Kommentare + Storage permission not granted! diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f998d155..e398ae01 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -42,10 +42,15 @@ Usar Instadp para imágenes de perfil de alta definición Importar/Exportar Idioma - %s\nPublicaciones - %s Publicaciones - %s\nSeguidores - %s\nSiguiendo + + %s Post + %s publicaciones + + + %s Follower + %s seguidores + + %s seguidos Autorreproducir vídeos Siempre silenciar vídeos Seleccionar qué descargar @@ -63,9 +68,15 @@ Comentar Responder… ¡Has respondido con éxito! + + %d respuesta promediando un %s + %d respuestas promediando un %s + + Tu respuesta: %s Responder a la historia Responder… Cuestionario + Deslizador ¡Ya has respondido! Menciones Esta cuenta es privada @@ -98,6 +109,9 @@ Desbloquear Restringir Desrestringir + Siguiéndose mutuamente + Seguido por ti + Siguiéndote Mapa Exportar Importar @@ -305,4 +319,5 @@ %d comentario %d comentarios + ¡Permiso de almacenamiento no concecido! diff --git a/app/src/main/res/values-fa/arrays.xml b/app/src/main/res/values-fa/arrays.xml index 8cc33d59..9d97c4c9 100644 --- a/app/src/main/res/values-fa/arrays.xml +++ b/app/src/main/res/values-fa/arrays.xml @@ -2,7 +2,7 @@ پیشگزیده سامانه - انگلیسی + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 7f9aefc4..38e0948f 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -42,10 +42,15 @@ استفاده از Instadp برای بالا بردن وضوح عکس‌های نمایه وارد کردن/خروجی گرفتن زبان - %s\n پست‌ها - %s پست ها - %s\nدنبال کننده ها - %s\nدنبال کننده ها + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following پخش خودکار فیلم ها همیشه فیلم هارو بی صدا کن انتخاب کن چی دانلود کنی @@ -63,9 +68,15 @@ پاسخ پاسخ… جواب درست است! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s پاسخ به استوری پاسخ… نظرسنجی + Slider در حال حاظر شما رای داده اید! یادآوری ها این اکانت شخصی است @@ -99,6 +110,9 @@ رفع مسدودیت محدود کردن حذف محدودیت + Following each other + Followed by you + Following you نقشه صادر کردن وارد کردن @@ -306,4 +320,5 @@ %d دیدگاه %d دیدگاه + Storage permission not granted! diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 3a22c8b4..87879cf3 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -42,10 +42,15 @@ Utiliser Instadp pour les photos de profil haute définition Importer/Exporter Langues - %s\nPosts - %s Publications - %s\nAbonnés - %s\nAbonnements + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Lecture automatique des vidéos Toujours couper le son des vidéos Sélectionnez ce que vous souhaitez télécharger @@ -63,9 +68,15 @@ Répondre Réponse… Réponse envoyée ! + + %d réponse en moyenne %s + %d réponses en moyenne %s + + Votre réponse : %s Répondre à la story Réponse… Quiz + Curseur Vous avez déjà répondu ! Mentions Compte privé @@ -98,6 +109,9 @@ Débloquer Restreindre Retirer des restrictions + Following each other + Followed by you + Following you Carte Exporter Importer @@ -305,4 +319,5 @@ %d commentaire %d commentaires + Storage permission not granted! diff --git a/app/src/main/res/values-hi/arrays.xml b/app/src/main/res/values-hi/arrays.xml index 8534c2cc..d13eb531 100644 --- a/app/src/main/res/values-hi/arrays.xml +++ b/app/src/main/res/values-hi/arrays.xml @@ -2,7 +2,7 @@ सिस्टम निर्धारित - अंग्रेजी + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 0fed4a76..c7fc7be2 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -42,10 +42,15 @@ अधिक स्पष्ट रूपरेखा के लिये instadp कि ब्यबहार करें। आयात/निर्यात भाषा - %s\n पोस्टस - %s पोस्टस - %s\n अनुगामीयाॅ - %s\n फलो कर रहें है + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following वीडियो ऑटोप्ले करें सर्बदा वीडियो को शब्दहिन रखें डाउनलोड करने के लिए चयन करें @@ -63,9 +68,15 @@ जवाब उत्तर… सही उत्तर + + %d response averaging %s + %d responses averaging %s + + Your answer: %s स्टोरि पे प्रतिक्रिया करें जवाब… प्रश्नोत्तरी + Slider आप पहले से ही उत्तर दिये हो! उल्लेख यह एकाउॅट निजी है @@ -99,6 +110,9 @@ अनब्ल़ॉक करें प्रतिबंध लगाए प्रतिबंध न लगाए + Following each other + Followed by you + Following you नक्शा निर्यात करें आयात करें @@ -306,4 +320,5 @@ %d comment %d comments + Storage permission not granted! diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index db18f42e..71868b83 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -42,10 +42,13 @@ Gunakan Instadp untuk foto profil kualitas tinggi Ekspor/impor Pengaturan Bahasa - %s\nkiriman - %s Kiriman - %s\npengikut - %s\ndiikuti + + %s Posts + + + %s Followers + + %s Following Otomatis putar video Selalu bisukan video Pilih apa yang akan diunduh @@ -63,9 +66,14 @@ Tanggapi Balasan… Berhasil menjawab! + + %d responses averaging %s + + Your answer: %s Balas cerita Balas… Kuis + Slider Anda sudah menjawab! Sebutan Akun Ini Bersifat Pribadi @@ -98,6 +106,9 @@ Batalkan Blokir Batasi Hilangkan Batasan + Following each other + Followed by you + Following you Peta Ekspor Impor @@ -303,4 +314,5 @@ %d komentar + Storage permission not granted! diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5f22338a..045b4898 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -42,10 +42,15 @@ Usa Instadp per immagini del profilo ad alta definizione Importa/Esporta Lingua - %s\nPost - %s Post - %s\nSeguaci - %s\nSeguiti + + %s Post + %s Post + + + %s Seguace + %s Seguaci + + %s Seguiti Riproduzione automatica video Silenzia sempre i video Seleziona cosa scaricare @@ -63,9 +68,15 @@ Rispondi Rispondi… Risposta corretta! + + %d risposta media %s + %d risposte medie %s + + La tua risposta: %s Rispondi alla storia Rispondi… Quiz + Scorrimento Hai già risposto! Menzioni Questo Profilo è Privato @@ -98,6 +109,9 @@ Sblocca Limita Rimuovi limitazione + Si seguono a vicenda + Seguito da te + Ti segue Mappa Esporta Importa @@ -305,4 +319,5 @@ %d commento %d commenti + Permesso di archiviazione non garantito! diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index 17b0f4ee..c68149fb 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -42,10 +42,15 @@ Use Instadp for high definition profile pictures Import/Export Language - %s\nPosts - %s Posts - %s\nFollowers - %s\nFollowing + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Autoplay videos Always mute videos Select what to download @@ -63,9 +68,15 @@ Respond Answer… Answer successful! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s Reply to story Reply… Quiz + Slider You have already answered! Mentions This Account is Private @@ -98,6 +109,9 @@ Unblock Restrict Unrestrict + Following each other + Followed by you + Following you Map Export Import @@ -305,4 +319,5 @@ %d comment %d comments + Storage permission not granted! diff --git a/app/src/main/res/values-mk/arrays.xml b/app/src/main/res/values-mk/arrays.xml index 19203a1a..afdc1067 100644 --- a/app/src/main/res/values-mk/arrays.xml +++ b/app/src/main/res/values-mk/arrays.xml @@ -2,7 +2,7 @@ Системски одбрано - Англиски + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 14995f48..e38c3345 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -42,10 +42,15 @@ Користи Instadp за профили со висока резолуција Увоз/Извоз Јазик - %s\nПостови - %s Постови - %s\nСледбеници - %s\nСледбеници + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Autoplay на видеа Секогаш гледај видеа без звук Селектирај што сакаш да превземеш @@ -63,9 +68,15 @@ Одговори Answer… Одговарњето беше успешно! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s Одговори на приказната Reply… Квиз + Slider Вие веќе гласавте/одговоривте! Спомнувања Овoј корисник има приватен профил @@ -98,6 +109,9 @@ Одблокни Ограничи Одограничи + Following each other + Followed by you + Following you Мапа Експорт Импорт @@ -305,4 +319,5 @@ %d comment %d comments + Storage permission not granted! diff --git a/app/src/main/res/values-nl/arrays.xml b/app/src/main/res/values-nl/arrays.xml index 54fe7725..a7306264 100644 --- a/app/src/main/res/values-nl/arrays.xml +++ b/app/src/main/res/values-nl/arrays.xml @@ -2,7 +2,7 @@ Systeemstandaard - Engels + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index de20b842..37f18a9f 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -42,10 +42,15 @@ Instadp gebruiken voor hoge definitie profielfoto\'s Importeren/Exporteren Taal - %s\nBerichten - %s Berichten - %s\nVolgers - %s\nVolgend + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following Video\'s automatisch afspelen Video\'s altijd dempen Selecteer wat je wil downloaden @@ -63,9 +68,15 @@ Reageer Antwoord… Antwoord gelukt! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s Reageer op het verhaal Reageer… Quiz + Slider Je hebt al geantwoord! Vermeldingen Dit Account is Privé @@ -98,6 +109,9 @@ Deblokkeer Beperk De-restrict + Following each other + Followed by you + Following you Kaart Exporteer Importeer @@ -305,4 +319,5 @@ %d opmerking %d opmerkingen + Storage permission not granted! diff --git a/app/src/main/res/values-or/arrays.xml b/app/src/main/res/values-or/arrays.xml index 8a3b45aa..30249275 100644 --- a/app/src/main/res/values-or/arrays.xml +++ b/app/src/main/res/values-or/arrays.xml @@ -2,7 +2,7 @@ ସିଷ୍ଟମ ନିର୍ଧାରିତ - ଇଂରାଜୀ + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index 7e36b6d6..1bce7999 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -32,40 +32,51 @@ ବାର୍ତା ଦେଖିବା ପରେ \'ଦେଖାଗଲା\' ଚିହ୍ନିତ କରନ୍ତୁ | ଅନ୍ୟ ସଦସ୍ୟମାନେ ଜାଣିବେ ତୁମେ ଏହାକୁ ଦେଖିଛ। କାର୍ଯ୍ୟକଳାପ ସୂଚନା ଦେଖାନ୍ତୁ - Error loading profile!\nTry logging in and search again. - Error creating Download folder(s). - Save to custom folder - Select folder - Theme - Only affects logged-in users: - Only affects anonymous users: - Use Instadp for high definition profile pictures - Import/Export - Language - %s\nPosts - %s Posts - %s\nFollowers - %s\nFollowing - Autoplay videos - Always mute videos - Select what to download - Current - Whole Album - Show stories - No more stories! - Be patient! - View Post - View Post + ପ୍ରୋଫାଇଲ୍ ଲୋଡ୍ କରିବାରେ ତ୍ରୁଟି!\nପୁନର୍ବାର ଲଗ୍ ଇନ୍ କରି ଚେଷ୍ଟା କରନ୍ତୁ | + ଡ଼ାଉନଲୋଡ଼ ଫୋଲଡ଼ର ସୃଷ୍ଟି କରିବାରେ ତ୍ରୁଟି ପରିଲକ୍ଷିତ ହେଉଛି। + ନିଜେ ସ୍ଥିର କରିଥିବା ଫୋଲଡର ରେ ରଖ। + ଫୋଲ୍‌ଡର୍‌ ଚୟନ କରନ୍ତୁ + ଥିମ + କେବଳ ଲଗ ଇନ ହୋଇଥିବା ବ୍ୟବହାରକାରୀଙ୍କ ପାଇଁ: + କେବଳ ଲଗ ଇନ ହୋଇନଥିବା ବ୍ୟବହାରକାରୀଙ୍କ ପାଇଁ: + ଅଧିକ ସ୍ପଷ୍ଟ ପ୍ରୋଫାଇଲ ଚିତ୍ର ପାଇଁ instadp ର ବ୍ୟବହାର କରନ୍ତୁ। + ଇମ୍ପୋର୍ଟ/ଏକ୍ସପୋର୍ଟ + ଭାଷା + + %s Post + %s Posts + + + %s Follower + %s Followers + + %s Following + ଭିଡ଼ିଓ ସ୍ୱତଃ ଚାଲୁ କର + ସର୍ବଦା ଭିଡ଼ିଓକୁ ଶବ୍ଦହୀନ ରଖ + ଡାଉନଲୋଡ଼ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ + ସମ୍ପ୍ରତି + ସମସ୍ତ ଆଲବମ + କାହାଣୀଗୁଡିକ ଦେଖାନ୍ତୁ + ଆଉ କାହାଣୀ ନାହିଁ! + ଧୈର୍ଯ୍ୟ ରଖନ୍ତୁ! + ପୋଷ୍ଟ ଦେଖନ୍ତୁ + ପୋଷ୍ଟ ଦେଖନ୍ତୁ Spotify - Vote + ମତଦାନ କରନ୍ତୁ | Vote successful! You have already voted! Respond Answer… Answer successful! + + %d response averaging %s + %d responses averaging %s + + Your answer: %s Reply to story Reply… Quiz + Slider You have already answered! Mentions This Account is Private @@ -98,6 +109,9 @@ Unblock Restrict Unrestrict + Following each other + Followed by you + Following you Map Export Import @@ -305,4 +319,5 @@ %d comment %d comments + Storage permission not granted! diff --git a/app/src/main/res/values-pl/arrays.xml b/app/src/main/res/values-pl/arrays.xml index a66e5a7f..cff0513f 100644 --- a/app/src/main/res/values-pl/arrays.xml +++ b/app/src/main/res/values-pl/arrays.xml @@ -2,7 +2,7 @@ Język urządzenia - Angielski + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 17f87e4c..d89333ab 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -42,10 +42,19 @@ Użyj Instadp dla zdjęć profilowych o wysokiej rozdzielczości Importuj/Eksportuj Język - %s\nPosty - %s postów - %s\nObserwujący - %s\nObserwuje + + %s Post + %s Posts + %s Posts + %s Posts + + + %s Follower + %s Followers + %s Followers + %s Followers + + %s Following Automatyczne odtwarzanie filmów Zawsze wyciszaj filmy Wybierz, co chcesz pobrać @@ -63,9 +72,17 @@ Odpowiedz Odpowiedz… Odpowiedziano pomyślnie! + + %d response averaging %s + %d responses averaging %s + %d responses averaging %s + %d responses averaging %s + + Your answer: %s Odpowiedz na relację Odpowiedź… Quiz + Slider Już odpowiedziałeś! Wzmianki To konto jest prywatne @@ -98,6 +115,9 @@ Odblokuj Ogranicz Nieograniczone + Following each other + Followed by you + Following you Mapa Eksportuj Importuj @@ -309,4 +329,5 @@ %d komentarzy %d komentarzy + Storage permission not granted! diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 5c9c07b5..fb874ff2 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -42,10 +42,15 @@ Usar Instadp para fotos de perfil de alta definição Importar/Exportar Idioma - %s\nPublicações - %s Publicações - %s\nSeguidores - %s\nSeguindo + + %s Publicação + %s Publicações + + + %s Seguidor + %s Seguidores + + %s Seguindo Reprodução automática de vídeos Sempre silenciar vídeos Selecionar o que baixar @@ -63,9 +68,15 @@ Responder Responder… Resposta enviada! + + %d resposta em uma média de %s + %d respostas em uma média de %s + + Sua resposta: %s Responder o story Responder… Quiz + Deslizante Você já respondeu! Menções Esta conta é privada @@ -98,6 +109,9 @@ Desbloquear Restringir Deixar de restringir + Seguindo um ao outro + Seguido por você + Segue você Mapa Exportar Importar @@ -281,19 +295,19 @@ Baixar item %d de %d Excluir Comentar - Aparência + Visualização Abrindo publicação... Compartilhar - Estilo da aparência - Número de colunas + Estilo do layout + Colunas 2 3 Mostrar nomes Mostrar avatares - Tamanho do avatar + Avatar Bordas - Mostrar separação das grades - Desativar animação + Grades separadas + Animação Por favor, espere a tarefa atual ser concluída primeiro! Publicação não encontrada! Nenhum aplicativo para abrir urls encontrado @@ -305,4 +319,5 @@ %d comentário %d comentários + Permissão de armazenamento não concedida! diff --git a/app/src/main/res/values-ru/arrays.xml b/app/src/main/res/values-ru/arrays.xml index 343c631f..c58e27b3 100644 --- a/app/src/main/res/values-ru/arrays.xml +++ b/app/src/main/res/values-ru/arrays.xml @@ -2,7 +2,7 @@ Системный по умолчанию - Английский + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a4e410c7..a1c6d6c7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -42,10 +42,19 @@ Использовать Instadp для фотографий профиля с высокой четкостью Импорт/Экспорт Язык - %s\nПубликаций - %s Публикаций - %s\nПодписчиков - %s\nПоследователей + + %s Post + %s Posts + %s Posts + %s Posts + + + %s Follower + %s Followers + %s Followers + %s Followers + + %s Following Автовоспроизведение видео Всегда заглушать видео Выберите, что скачивать @@ -63,9 +72,17 @@ Отреагировать Ответить… Ответ успешно представлен! + + %d response averaging %s + %d responses averaging %s + %d responses averaging %s + %d responses averaging %s + + Your answer: %s Ответить на историю Ответить… Опрос + Slider Вы уже ответили! Упоминания Это частная учётная запись @@ -98,6 +115,9 @@ Разблокировать Ограничить Снять ограничение + Following each other + Followed by you + Following you Карта Экспорт Импорт @@ -309,4 +329,5 @@ %d комментариев %d комментарии + Storage permission not granted! diff --git a/app/src/main/res/values-tr/arrays.xml b/app/src/main/res/values-tr/arrays.xml index b9028585..85868a4e 100644 --- a/app/src/main/res/values-tr/arrays.xml +++ b/app/src/main/res/values-tr/arrays.xml @@ -2,7 +2,7 @@ Sistem Varsayılanı - İngilizce + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 199af33a..75e38c23 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -42,10 +42,15 @@ Yüksek kalite profil fotoğrafları için Instadp kullan İçe Aktar/Dışa Aktar Dil - %s\nGönderi - %s Gönderi - %s\nTakipçi - %s\nTakip + + %s Gönderi + %s Gönderi + + + %s Takipçi + %s Takipçi + + %s Takip Videoları otomatik oynat Videoları her zaman sustur İndirmek için seçin @@ -63,9 +68,15 @@ Yanıt ver Cevapla… Cevaplama başarılı! + + %d yanıt ortalaması %s + %d yanıt ortalaması %s + + Cevabın: %s Hikayeye cevap ver Yanıtla… Test + Kaydırıcı Zaten cevapladınız! Etiketlenenler Bu Hesap Gizlidir @@ -98,6 +109,9 @@ Engeli kaldır Kısıtla Kısıtlamayı Kaldır + Karşılıklı takip ediliyor + Takip ediliyor + Seni takip ediyor Harita Dışa aktar İçe aktar @@ -298,11 +312,12 @@ Gönderi bulunamadı! Linki açabilecek uygulama bulunamadı - %d like + %d beğeni %d beğeni %d yorum %d yorum + Depolama izni verilmedi! diff --git a/app/src/main/res/values-vi/arrays.xml b/app/src/main/res/values-vi/arrays.xml index c26f143f..c8c9a287 100644 --- a/app/src/main/res/values-vi/arrays.xml +++ b/app/src/main/res/values-vi/arrays.xml @@ -2,7 +2,7 @@ Mặc định hệ thống - Tiếng Anh + English Français [Merci à @kernoeb et @PierreM0] Español [Gracias a @sguinetti, @akrai y @retiolus] 简体中文 diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index fa6842a8..1fe21111 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -42,10 +42,13 @@ Dùng Instadp cho những ảnh đại diện có độ phân giải cao Nhập/Xuất Ngôn ngữ - %s\nBài đăng - %s Bài đăng - %s\nNgười theo dõi - %s\nĐang theo dõi + + %s Posts + + + %s Followers + + %s Following Tự động phát video Luôn luôn tắt âm thanh video Chọn cái để tải xuống @@ -63,9 +66,14 @@ Trả lời Phản hồi… Trả lời thành công! + + %d Trung bình %s + + Câu trả lời của bạn: %s Trả lời story - Reply… + Trả lời… Câu hỏi + Thanh trượt Bạn đã trả lời rồi! Đề cập Tài khoản này là riêng tư @@ -86,8 +94,8 @@ Đã lưu Đã gắn thẻ Tin nhắn - Like - Unlike + Thích + Bỏ thích Dấu trang Gỡ dấu trang Theo dõi @@ -98,6 +106,9 @@ Bỏ chặn Giới hạn Bỏ giới hạn + Following each other + Followed by you + Following you Bản đồ Xuất Nhập @@ -165,7 +176,7 @@ Xin hãy chấp nhận quyền và thử tải lại! Đã bắt đầu tải xuống Tải xuống hoàn tất - Downloading post… + Đang tải xuống bài viết… Đang tải xuống phương tiện Đang tải xuống ảnh đại diện Tệp đã được tải xuống trong thư mục Downloads! @@ -189,19 +200,19 @@ không theo dõi %s %s không theo dõi Lỗi khi tải cookies - Write a new comment… - Write a new message… + Viết bình luận mới… + Viết tin nhắn mới… Đã thích bài đăng của bạn Đã bình luận về bài đăng của bạn: Đã bắt đầu theo dõi bạn Đã nhắc đến bạn: - Tagged you in a post + Đã gắn thẻ bạn trong một bài viết Đã yêu cầu theo dõi bạn Duyệt yêu cầu Từ chối yêu cầu - Share this public post to… + Chia sẻ bài viết công khai này đến… Đây là một bài viết riêng tư! Hãy chia sẻ đến những ai có thể xem chúng! - This category is somehow empty… + Mục này đang bị bỏ trống… Đã có bản cập nhật! (%s) Nhắc nhở: Nếu bạn tải về từ F-Droid, bạn phải cập nhật từ nó! Điều tương tự cho GitHub. Cảm ơn bạn đã cập nhật Barinsta! @@ -209,7 +220,7 @@ Ối.. ứng dụng đã bị crash, nhưng đừng lo bạn có thể gửi báo cáo lỗi đến cho nhà phát triển để giúp anh ấy sửa vấn đề. (: Hoạt động Chọn hình ảnh - Uploading… + Đang tải lên… Bạn có: %d người theo dõi %d bình luận @@ -264,43 +275,44 @@ Tập tin: Nhập mật khẩu Chọn tệp sao lưu (.zaai/.backup) - Apply - Save - Caption - Video player timeline - Liking… - Like unsuccessful - Unlike unsuccessful - Unliking… - Controls - Saving… - Removing… - Save unsuccessful - Remove unsuccessful - Downloading… - Download item %d of %d - Delete - Comment - Layout - Opening post... - Share - Layout style - Column count + Áp dụng + Lưu + Chú thích + Thanh thời gian của trình phát video + Đang thích… + Không thể thích + Không thể bỏ thích + Đang bỏ thích… + Điều khiển + Đang lưu… + Đang xóa… + Không thể lưu + Không thể xóa + Đang tải xuống… + Tải tệp %d từ %d + Xóa + Bình luận + Giao diện + Đang mở bài đăng... + Chia sẻ + Phong cach giao diện + Số cột 2 3 - Show names - Show avatars - Avatar size - Corners - Show grid gap - Disable animation - Please wait for the current task to complete first! - Post not found! - No app found which opens urls + Hiển thị tên + Hiển thị Avatar + Kích thước avatar + Góc + Hiển thị khoảng trống lưới + Tắt hoạt ảnh + Xin hãy đợi công việc hiện tại hoàn thành trước! + Không tìm thấy bài viết! + Không có app nào để mở link này - %d likes + %d thích - %d comments + %d bình luận + Storage permission not granted! diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 7efbe335..fc166541 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -42,10 +42,13 @@ 使用 Instadp 获取高清头像 导入/导出 语言 - %s\n帖子 - %s 个帖子 - %s\n粉丝 - %s\n已关注 + + %s 帖子 + + + %s 粉丝 + + %s 关注 自动播放视频 视频默认静音 选择要下载的 @@ -63,9 +66,14 @@ 回复 回答… 回答成功! + + %d 个回答,平均 %s + + 您的回答:%s 回复快拍 回复… 测验 + 滑块 您已回答过了! 提及 私密账户 @@ -98,6 +106,9 @@ 解禁 限制 放开 + 互相关注 + 您已关注 + 关注了您 地图 导出 导入 @@ -303,4 +314,5 @@ %d 条评论 + 未授予存储权限! diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2089844b..fe7a306e 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -42,10 +42,13 @@ 透過 Instadp 檢視高清大頭貼照 匯入/匯出 語言 - %s\n貼文 - %s 貼文 - %s\n位追蹤者 - %s\n追蹤中 + + %s 貼文 + + + %s 追蹤者 + + %s 追蹤中 自動播放影片 永遠自動靜音影片 選擇要下載的內容 @@ -63,9 +66,14 @@ 回覆 回答… 回答成功! + + %d responses averaging %s + + Your answer: %s 回覆限時動態 回覆… 測驗 + Slider 您已經回答了! 提及 此帳戶為私人帳戶 @@ -98,6 +106,9 @@ 解除封鎖 限制 移除限制 + 正彼此追蹤 + 您已追蹤 + 關注了你 地圖 匯出 匯入 @@ -184,7 +195,7 @@ 您要搜尋主題標籤嗎? 追蹤者 追蹤中 - 比較關注者和關注 + Comparing followers & following 正彼此追蹤 尚未追蹤 %s %s 尚未追蹤 @@ -303,4 +314,5 @@ %d 個評論 + Storage permission not granted! From a983f44769f53a542eaf7b06814a695a2897fe8c Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sun, 20 Dec 2020 15:56:39 -0500 Subject: [PATCH 012/101] remove old "zh" locale --- app/src/main/res/values-zh/arrays.xml | 126 -------------------------- 1 file changed, 126 deletions(-) delete mode 100755 app/src/main/res/values-zh/arrays.xml diff --git a/app/src/main/res/values-zh/arrays.xml b/app/src/main/res/values-zh/arrays.xml deleted file mode 100755 index 0dd8f232..00000000 --- a/app/src/main/res/values-zh/arrays.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - 系统默认 - 英文 - 法文 [感谢 @kernoeb] - 西班牙文 [感谢 @sguinetti] - 简体中文 - 印尼文 [感谢 @Galang23] - 意大利文 [感谢 @RAR_Ramar] - 德文 [感谢 @peterge1998] - 波兰文 [感谢 @Lego8486] - 土耳其文 [感谢 @faydin90] - 巴西葡文 [感谢 @wagnim] - 波斯文 [感谢 @farzadx] - 马其顿文 [感谢 @snajdovski] - 越南文 [感谢 @fouze555] - Chinese Traditional - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - - - 自动 / 跟随系统 - 自动 / 跟随电池 - 暗黑 - 明亮 - - - 0 - 1 - 2 - 3 - - - - \@ - - - \| - - - - - 正在载入... - - - dd-MM-yyyy - dd/MM/yyyy - dd.MM.yyyy - dd-MM-yy - dd/MM/yy - dd.MM.yy - dd-MMM-yyyy - dd/MMM/yyyy - dd.MMM.yyyy - dd-MMM-yy - dd/MMM/yy - dd.MMM.yy - MM-dd-yyyy - MM/dd/yyyy - MM.dd.yyyy - yyyy-MM-dd - yyyy/MM/dd - yyyy.MM.dd - MM-dd-yy - MM/dd/yy - MM.dd.yy - yy-MM-dd - yy/MM/dd - yy.MM.dd - MMM-dd-yyyy - MMM/dd/yyyy - MMM.dd.yyyy - yyyy-MMM-dd - yyyy/MMM/dd - yyyy.MMM.dd - MMM-dd-yy - MMM/dd/yy - MMM.dd.yy - yy-MMM-dd - yy/MMM/dd - yy.MMM.dd - - - hh:mm:ss a - h:mm:ss a - HH:mm:ss - H:mm:ss - - - @string/title_dm - @string/feed - @string/profile - @string/title_discover - @string/more - - - @string/light_white_theme - @string/light_barinsta_theme - @string/light_bibliogram_theme - - - @style/AppTheme.Light.White - @style/AppTheme.Light.Barinsta - @style/AppTheme.Light.Bibliogram - - - @string/dark_black_theme - @string/dark_material_dark_theme - - - @style/AppTheme.Dark.Black - @style/AppTheme.Dark.MaterialDark - - From 484b0f96579ae8a0d4a50d7e547065e1b71b81ed Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Sun, 20 Dec 2020 17:04:25 -0500 Subject: [PATCH 013/101] fix favourites logic --- .../fragments/FavoritesFragment.java | 106 ------------------ .../fragments/HashTagFragment.java | 16 ++- .../fragments/LocationFragment.java | 14 +++ .../fragments/main/ProfileFragment.java | 14 +++ .../res/layout/layout_profile_details.xml | 30 +++-- 5 files changed, 61 insertions(+), 119 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java b/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java index 190e9a59..34c81322 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java @@ -81,7 +81,6 @@ public class FavoritesFragment extends Fragment { @Override public void onSuccess(final List favorites) { favoritesViewModel.getList().postValue(favorites); - fetchMissingInfo(favorites); } @Override @@ -156,109 +155,4 @@ public class FavoritesFragment extends Fragment { binding.favoriteList.setAdapter(adapter); } - - private void fetchMissingInfo(final List allFavorites) { - final Runnable runnable = () -> { - final List updatedList = new ArrayList<>(allFavorites); - // cyclic barrier is to make the async calls synchronous - final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> { - // Log.d(TAG, "fetchMissingInfo: barrier action"); - favoritesViewModel.getList().postValue(new ArrayList<>(updatedList)); - }); - try { - for (final Favorite model : allFavorites) { - cyclicBarrier.reset(); - // if the model has missing pic or display name (for user and location), fetch those details - switch (model.getType()) { - case LOCATION: - if (TextUtils.isEmpty(model.getDisplayName()) - || TextUtils.isEmpty(model.getPicUrl())) { - new LocationFetcher(model.getQuery(), result -> { - if (result == null) return; - final int i = updatedList.indexOf(model); - updatedList.remove(i); - final Favorite updated = new Favorite( - model.getId(), - model.getQuery(), - model.getType(), - result.getName(), - result.getSdProfilePic(), - model.getDateAdded() - ); - favoriteRepository.insertOrUpdateFavorite(updated, new RepositoryCallback() { - @Override - public void onSuccess(final Void result) { - updatedList.add(i, updated); - try { - cyclicBarrier.await(); - } catch (BrokenBarrierException | InterruptedException e) { - Log.e(TAG, "fetchMissingInfo: ", e); - } - } - - @Override - public void onDataNotAvailable() { - try { - cyclicBarrier.await(); - } catch (BrokenBarrierException | InterruptedException e) { - Log.e(TAG, "fetchMissingInfo: ", e); - } - } - }); - }).execute(); - cyclicBarrier.await(); - } - break; - case USER: - if (TextUtils.isEmpty(model.getDisplayName()) - || TextUtils.isEmpty(model.getPicUrl())) { - new ProfileFetcher(model.getQuery(), result -> { - if (result == null) return; - final int i = updatedList.indexOf(model); - updatedList.remove(i); - final Favorite updated = new Favorite( - model.getId(), - model.getQuery(), - model.getType(), - result.getName(), - result.getSdProfilePic(), - model.getDateAdded() - ); - favoriteRepository.insertOrUpdateFavorite(updated, new RepositoryCallback() { - @Override - public void onSuccess(final Void result) { - try { - cyclicBarrier.await(); - } catch (BrokenBarrierException | InterruptedException e) { - Log.e(TAG, "fetchMissingInfo: ", e); - } - } - - @Override - public void onDataNotAvailable() { - try { - cyclicBarrier.await(); - } catch (BrokenBarrierException | InterruptedException e) { - Log.e(TAG, "fetchMissingInfo: ", e); - } - } - }); - updatedList.add(i, updated); - }).execute(); - cyclicBarrier.await(); - } - break; - case HASHTAG: - default: - // hashtags don't require displayName or pic - // updatedList.add(model); - } - } - } catch (Exception e) { - Log.e(TAG, "fetchMissingInfo: ", e); - } - favoritesViewModel.getList().postValue(updatedList); - }; - new Thread(runnable).start(); - } } diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index c89f7970..ac20984d 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -464,6 +464,20 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe public void onSuccess(final Favorite result) { hashtagDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); hashtagDetailsBinding.favChip.setText(R.string.favorite_short); + favoriteRepository.insertOrUpdateFavorite(new Favorite( + result.getId(), + hashtag.substring(1), + FavoriteType.HASHTAG, + hashtagModel.getName(), + hashtagModel.getSdProfilePic(), + result.getDateAdded() + ), new RepositoryCallback() { + @Override + public void onSuccess(final Void result) {} + + @Override + public void onDataNotAvailable() {} + }); } @Override @@ -496,7 +510,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe hashtag.substring(1), FavoriteType.HASHTAG, hashtagModel.getName(), - null, + hashtagModel.getSdProfilePic(), new Date() ), new RepositoryCallback() { @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index d857c083..ba9cd08a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -456,6 +456,20 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR locationDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); locationDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); locationDetailsBinding.favChip.setText(R.string.favorite_short); + favoriteRepository.insertOrUpdateFavorite(new Favorite( + result.getId(), + locationId, + FavoriteType.LOCATION, + locationModel.getName(), + locationModel.getSdProfilePic(), + result.getDateAdded() + ), new RepositoryCallback() { + @Override + public void onSuccess(final Void result) {} + + @Override + public void onDataNotAvailable() {} + }); } @Override diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index f9e85d3e..45bcc334 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -578,6 +578,20 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe public void onSuccess(final Favorite result) { profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); profileDetailsBinding.favChip.setText(R.string.added_to_favs); + favoriteRepository.insertOrUpdateFavorite(new Favorite( + result.getId(), + finalUsername, + FavoriteType.USER, + profileModel.getName(), + profileModel.getSdProfilePic(), + result.getDateAdded() + ), new RepositoryCallback() { + @Override + public void onSuccess(final Void result) {} + + @Override + public void onDataNotAvailable() {} + }); } @Override diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index eb14c1f9..527d5952 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -27,13 +27,14 @@ android:layout_height="@dimen/profile_chip_size" android:layout_marginStart="4dp" android:clickable="false" - android:visibility="gone" - tools:visibility="visible" android:gravity="center" + android:visibility="gone" + app:chipBackgroundColor="@null" app:layout_constraintBottom_toTopOf="@id/mainFollowers" app:layout_constraintStart_toEndOf="@id/mainProfileImage" app:layout_constraintTop_toTopOf="@id/mainProfileImage" - tools:text="35 Posts" /> + tools:text="35 Posts" + tools:visibility="visible" /> + tools:text="omg what do u expect" + tools:visibility="visible" /> + tools:text="10 Followers" + tools:visibility="visible" /> + tools:text="10 Following" + tools:visibility="visible" /> Date: Mon, 21 Dec 2020 14:27:15 -0500 Subject: [PATCH 014/101] fix mentions (final), improve follower comparison --- app/build.gradle | 2 +- .../viewholder/FollowsViewHolder.java | 1 - .../fragments/FollowViewerFragment.java | 177 ++++++++++-------- .../fragments/main/ProfileFragment.java | 5 +- .../viewmodels/FollowViewModel.java | 19 ++ .../webservices/FriendshipService.java | 4 +- .../res/layout/layout_profile_details.xml | 2 +- 7 files changed, 125 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java diff --git a/app/build.gradle b/app/build.gradle index 5a6611dc..3e81b904 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,7 +87,7 @@ dependencies { annotationProcessor "androidx.room:room-compiler:$room_version" // implementation 'com.github.hendrawd:StorageUtil:1.1.0' - implementation 'com.github.ammargitham:AutoLinkTextViewV2:master-SNAPSHOT' + implementation 'me.austinhuang:AutoLinkTextViewV2:-SNAPSHOT' implementation 'org.jsoup:jsoup:1.13.1' implementation 'com.facebook.fresco:fresco:2.3.0' diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java index 6396d4b2..1f38cecb 100755 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/FollowsViewHolder.java @@ -23,7 +23,6 @@ public final class FollowsViewHolder extends RecyclerView.ViewHolder { public void bind(final ProfileModel model, final List admins, final View.OnClickListener onClickListener) { - Log.d("austin_debug", "bind "+model); if (model == null) return; itemView.setTag(model); itemView.setOnClickListener(onClickListener); diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index f27d2c91..1ccb3464 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -20,29 +20,22 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SearchView; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import java.util.ArrayList; -import java.util.Arrays; -import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.adapters.FollowAdapter; +import awais.instagrabber.customviews.helpers.RecyclerLazyLoader; import awais.instagrabber.databinding.FragmentFollowersViewerBinding; import awais.instagrabber.models.FollowModel; -import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse; import awais.instagrabber.repositories.responses.FriendshipRepoListFetchResponse; -import awais.instagrabber.utils.Constants; -import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.webservices.FriendshipService; import awais.instagrabber.webservices.ServiceCallback; -import awaisomereport.LogCollector; import thoughtbot.expandableadapter.ExpandableGroup; -import static awais.instagrabber.utils.Utils.logCollector; -import static awais.instagrabber.utils.Utils.settingsHelper; - public final class FollowViewerFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { private static final String TAG = "FollowViewerFragment"; @@ -51,9 +44,11 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh private final ArrayList followersModels = new ArrayList<>(); private final ArrayList allFollowing = new ArrayList<>(); - private boolean isFollowersList, isCompare = false, loading = false; - private String profileId, username, namePost, type; + private boolean moreAvailable = true, isFollowersList, isCompare = false, loading = false, shouldRefresh = true; + private String profileId, username, namePost, type, endCursor; private Resources resources; + private LinearLayoutManager layoutManager; + private RecyclerLazyLoader lazyLoader; private FollowModel model; private FollowAdapter adapter; private View.OnClickListener clickListener; @@ -61,9 +56,59 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh private AsyncTask currentlyExecuting; private SwipeRefreshLayout root; private FriendshipService friendshipService; - private boolean shouldRefresh = true; private AppCompatActivity fragmentActivity; + final ServiceCallback followingFetchCb = new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoListFetchResponse result) { + if (result != null) { + followingModels.addAll(result.getItems()); + if (!isFollowersList) followModels.addAll(result.getItems()); + if (result.isMoreAvailable()) { + endCursor = result.getNextMaxId(); + friendshipService.getList(false, profileId, endCursor, this); + } else if (followersModels.size() == 0) { + if (!isFollowersList) moreAvailable = false; + friendshipService.getList(true, profileId, null, followingFetchCb); + } else { + if (!isFollowersList) moreAvailable = false; + showCompare(); + } + } else binding.swipeRefreshLayout.setRefreshing(false); + } + + @Override + public void onFailure(final Throwable t) { + binding.swipeRefreshLayout.setRefreshing(false); + Log.e(TAG, "Error fetching list (double, following)", t); + } + }; + final ServiceCallback followersFetchCb = new ServiceCallback() { + @Override + public void onSuccess(final FriendshipRepoListFetchResponse result) { + if (result != null) { + followersModels.addAll(result.getItems()); + if (isFollowersList) followModels.addAll(result.getItems()); + if (result.isMoreAvailable()) { + endCursor = result.getNextMaxId(); + friendshipService.getList(true, profileId, endCursor, this); + } else if (followingModels.size() == 0) { + if (isFollowersList) moreAvailable = false; + friendshipService.getList(false, profileId, null, followingFetchCb); + } else { + if (isFollowersList) moreAvailable = false; + showCompare(); + } + } + } + + @Override + public void onFailure(final Throwable t) { + binding.swipeRefreshLayout.setRefreshing(false); + Log.e(TAG, "Error fetching list (double, follower)", t); + } + }; + @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -141,13 +186,13 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh public void onRefresh() { if (isCompare) listCompare(); else listFollows(); + endCursor = null; + lazyLoader.resetState(); } private void listFollows() { - loading = true; type = resources.getString(isFollowersList ? R.string.followers_type_followers : R.string.followers_type_following); setSubtitle(type); - followModels.clear(); final ServiceCallback cb = new ServiceCallback() { @Override public void onSuccess(final FriendshipRepoListFetchResponse result) { @@ -156,16 +201,18 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh return; } else { + int oldSize = followModels.size() == 0 ? 0 : followModels.size() - 1; followModels.addAll(result.getItems()); if (result.isMoreAvailable()) { - friendshipService.getList(isFollowersList, profileId, result.getNextMaxId(), this); - } - else { - binding.swipeRefreshLayout.setRefreshing(false); - if (isFollowersList) followersModels.addAll(followModels); - else followingModels.addAll(followModels); - refreshAdapter(followModels, null, null, null); + moreAvailable = true; + endCursor = result.getNextMaxId(); } + else moreAvailable = false; + binding.swipeRefreshLayout.setRefreshing(false); + if (isFollowersList) followersModels.addAll(result.getItems()); + else followingModels.addAll(result.getItems()); + refreshAdapter(followModels, null, null, null); + layoutManager.scrollToPosition(oldSize); } } @@ -175,64 +222,43 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh Log.e(TAG, "Error fetching list (single)", t); } }; - binding.swipeRefreshLayout.setRefreshing(true); - friendshipService.getList(isFollowersList, profileId, null, cb); + layoutManager = new LinearLayoutManager(getContext()); + lazyLoader = new RecyclerLazyLoader(layoutManager, (page, totalItemsCount) -> { + if (!TextUtils.isEmpty(endCursor)) { + binding.swipeRefreshLayout.setRefreshing(true); + friendshipService.getList(isFollowersList, profileId, endCursor, cb); + } + endCursor = null; + }); + binding.rvFollow.addOnScrollListener(lazyLoader); + binding.rvFollow.setLayoutManager(layoutManager); + layoutManager.setStackFromEnd(true); + if (moreAvailable) { + binding.swipeRefreshLayout.setRefreshing(true); + friendshipService.getList(isFollowersList, profileId, endCursor, cb); + } + else { + refreshAdapter(followModels, null, null, null); + layoutManager.scrollToPosition(0); + } } private void listCompare() { + layoutManager.setStackFromEnd(false); + binding.rvFollow.clearOnScrollListeners(); loading = true; setSubtitle(R.string.followers_compare); allFollowing.clear(); - followersModels.clear(); - followingModels.clear(); - final ServiceCallback followingFetchCb = new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoListFetchResponse result) { - if (result != null) { - followingModels.addAll(result.getItems()); - - if (result.isMoreAvailable()) { - friendshipService.getList(false, profileId, result.getNextMaxId(), this); - } else { - showCompare(); - } - } else binding.swipeRefreshLayout.setRefreshing(false); - } - - @Override - public void onFailure(final Throwable t) { - binding.swipeRefreshLayout.setRefreshing(false); - Log.e(TAG, "Error fetching list (double, following)", t); - } - }; - final ServiceCallback followersFetchCb = new ServiceCallback() { - @Override - public void onSuccess(final FriendshipRepoListFetchResponse result) { - if (result != null) { - followersModels.addAll(result.getItems()); - if (result.isMoreAvailable()) { - friendshipService.getList(true, profileId, result.getNextMaxId(), this); - } else if (followingModels.size() == 0) { - friendshipService.getList(false, profileId, null, followingFetchCb); - } else { - showCompare(); - } - } - } - - @Override - public void onFailure(final Throwable t) { - binding.swipeRefreshLayout.setRefreshing(false); - Log.e(TAG, "Error fetching list (double, follower)", t); - } - }; binding.swipeRefreshLayout.setRefreshing(true); - if (followersModels.size() == 0) { - friendshipService.getList(true, profileId, null, followersFetchCb); - } - else if (followingModels.size() == 0) { - friendshipService.getList(false, profileId, null, followingFetchCb); - } + if (moreAvailable) friendshipService.getList(isFollowersList, + profileId, + endCursor, + isFollowersList ? followersFetchCb : followingFetchCb); + else if (followersModels.size() == 0 || followingModels.size() == 0) + friendshipService.getList(!isFollowersList, + profileId, + null, + isFollowersList ? followingFetchCb : followersFetchCb); else showCompare(); } @@ -346,12 +372,12 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh final Context context = getContext(); if (loading) Toast.makeText(context, R.string.follower_wait_to_load, Toast.LENGTH_LONG).show(); else if (isCompare) { - listFollows(); isCompare = !isCompare; + listFollows(); } else { - listCompare(); isCompare = !isCompare; + listCompare(); } return true; } @@ -371,8 +397,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh if (allFollowing != null && allFollowing.size() > 0) groups.add(new ExpandableGroup(resources.getString(R.string.followers_both_following), allFollowing)); } else { - final ExpandableGroup group = new ExpandableGroup(type, followModels); - groups.add(group); + groups.add(new ExpandableGroup(type, followModels)); } adapter = new FollowAdapter(clickListener, groups); adapter.toggleGroup(0); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 45bcc334..7c2b4843 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -580,7 +580,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileDetailsBinding.favChip.setText(R.string.added_to_favs); favoriteRepository.insertOrUpdateFavorite(new Favorite( result.getId(), - finalUsername, + profileModel.getUsername(), FavoriteType.USER, profileModel.getName(), profileModel.getSdProfilePic(), @@ -619,10 +619,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe @Override public void onDataNotAvailable() { - final String finalUsername = username.startsWith("@") ? username.substring(1) : username; favoriteRepository.insertOrUpdateFavorite(new Favorite( -1, - finalUsername, + profileModel.getUsername(), FavoriteType.USER, profileModel.getName(), profileModel.getSdProfilePic(), diff --git a/app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java b/app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java new file mode 100644 index 00000000..dcd65d4a --- /dev/null +++ b/app/src/main/java/awais/instagrabber/viewmodels/FollowViewModel.java @@ -0,0 +1,19 @@ +package awais.instagrabber.viewmodels; + +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import java.util.List; + +import awais.instagrabber.models.FollowModel; + +public class FollowViewModel extends ViewModel { + private MutableLiveData> list; + + public MutableLiveData> getList() { + if (list == null) { + list = new MutableLiveData<>(); + } + return list; + } +} diff --git a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java index a370b7df..a31eb3b6 100644 --- a/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java +++ b/app/src/main/java/awais/instagrabber/webservices/FriendshipService.java @@ -153,13 +153,12 @@ public class FriendshipService extends BaseService { }); } - // log in required public void getList(final boolean follower, final String targetUserId, final String maxId, final ServiceCallback callback) { final Map queryMap = new HashMap<>(); - queryMap.put("max_id", maxId == null ? "" : maxId); + if (maxId != null) queryMap.put("max_id", maxId); final Call request = repository.getList(Constants.I_USER_AGENT, targetUserId, follower ? "followers" : "following", @@ -173,7 +172,6 @@ public class FriendshipService extends BaseService { } final String body = response.body(); if (TextUtils.isEmpty(body)) { - callback.onSuccess(null); return; } diff --git a/app/src/main/res/layout/layout_profile_details.xml b/app/src/main/res/layout/layout_profile_details.xml index 527d5952..23017654 100644 --- a/app/src/main/res/layout/layout_profile_details.xml +++ b/app/src/main/res/layout/layout_profile_details.xml @@ -274,7 +274,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="bottom" - app:constraint_referenced_ids="btnTagged, btnSaved, btnLiked, btnFollow, btnDM" /> + app:constraint_referenced_ids="btnSaved, btnLiked, btnFollow, btnDM" /> Date: Mon, 21 Dec 2020 21:22:38 -0500 Subject: [PATCH 015/101] full comment/caption/bio translation support, close #178 --- .../fragments/CommentsViewerFragment.java | 49 ++++++++------- .../fragments/FollowViewerFragment.java | 21 ++++--- .../fragments/PostViewV2Fragment.java | 24 ++++++- .../fragments/main/ProfileFragment.java | 48 ++++++++++++++ .../instagrabber/models/BasePostModel.java | 14 ++--- .../awais/instagrabber/models/FeedModel.java | 14 +++-- .../awais/instagrabber/models/PostModel.java | 2 + .../repositories/MediaRepository.java | 22 +++---- .../instagrabber/utils/ResponseBodyUtils.java | 1 + .../webservices/MediaService.java | 46 ++++++++++++-- app/src/main/res/layout/dialog_post_view.xml | 63 +++++++++++++++---- app/src/main/res/values/strings.xml | 5 ++ 12 files changed, 236 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java index f39b2ea1..2ddc1b7a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/CommentsViewerFragment.java @@ -287,29 +287,25 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl && (userIdFromCookie.equals(commentModel.getProfileModel().getId()) || userIdFromCookie.equals(userId))) { commentDialogList = new String[]{ resources.getString(R.string.open_profile), - resources.getString(R.string.view_pfp), -// resources.getString(R.string.comment_viewer_copy_user), resources.getString(R.string.comment_viewer_copy_comment), resources.getString(R.string.comment_viewer_reply_comment), commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) : resources.getString(R.string.comment_viewer_like_comment), + resources.getString(R.string.comment_viewer_translate_comment), resources.getString(R.string.comment_viewer_delete_comment) }; } else if (!TextUtils.isEmpty(cookie)) { commentDialogList = new String[]{ resources.getString(R.string.open_profile), - resources.getString(R.string.view_pfp), -// resources.getString(R.string.comment_viewer_copy_user), resources.getString(R.string.comment_viewer_copy_comment), resources.getString(R.string.comment_viewer_reply_comment), commentModel.getLiked() ? resources.getString(R.string.comment_viewer_unlike_comment) : resources.getString(R.string.comment_viewer_like_comment), + resources.getString(R.string.comment_viewer_translate_comment) }; } else { commentDialogList = new String[]{ resources.getString(R.string.open_profile), - resources.getString(R.string.view_pfp), -// resources.getString(R.string.comment_viewer_copy_user), resources.getString(R.string.comment_viewer_copy_comment) }; } @@ -322,23 +318,10 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl case 0: // open profile openProfile("@" + profileModel.getUsername()); break; - case 1: // view profile pic - final FragmentManager fragmentManager = getParentFragmentManager(); - final ProfilePicDialogFragment fragment = new ProfilePicDialogFragment(profileModel.getId(), - profileModel.getUsername(), - profileModel.getHdProfilePic()); - final FragmentTransaction ft = fragmentManager.beginTransaction(); - ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - .add(fragment, "profilePicDialog") - .commit(); - break; -// case 2: // copy username -// Utils.copyText(context, profileModel.getUsername()); -// break; - case 2: // copy comment + case 1: // copy comment Utils.copyText(context, "@" + profileModel.getUsername() + ": " + commentModel.getText()); break; - case 3: // reply to comment + case 2: // reply to comment commentsAdapter.setSelected(commentModel); String mention = "@" + profileModel.getUsername() + " "; binding.commentText.setText(mention); @@ -350,7 +333,7 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl imm.showSoftInput(binding.commentText, 0); }, 200); break; - case 4: // like/unlike comment + case 3: // like/unlike comment if (csrfToken == null) { return; } @@ -390,6 +373,28 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl } }); break; + case 4: // translate comment + mediaService.translate(commentModel.getId(), "2", new ServiceCallback() { + @Override + public void onSuccess(final String result) { + if (TextUtils.isEmpty(result)) { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + return; + } + new AlertDialog.Builder(context) + .setTitle(username) + .setMessage(result) + .setPositiveButton(R.string.ok, null) + .show(); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error translating comment", t); + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } + }); + break; case 5: // delete comment final String userId = CookieUtils.getUserIdFromCookie(cookie); if (userId == null) return; diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index 1ccb3464..4da57ca4 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -250,15 +250,20 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh setSubtitle(R.string.followers_compare); allFollowing.clear(); binding.swipeRefreshLayout.setRefreshing(true); - if (moreAvailable) friendshipService.getList(isFollowersList, - profileId, - endCursor, - isFollowersList ? followersFetchCb : followingFetchCb); - else if (followersModels.size() == 0 || followingModels.size() == 0) + if (moreAvailable) { + Toast.makeText(getContext(), R.string.follower_start_compare, Toast.LENGTH_LONG).show(); + friendshipService.getList(isFollowersList, + profileId, + endCursor, + isFollowersList ? followersFetchCb : followingFetchCb); + } + else if (followersModels.size() == 0 || followingModels.size() == 0) { + Toast.makeText(getContext(), R.string.follower_start_compare, Toast.LENGTH_LONG).show(); friendshipService.getList(!isFollowersList, - profileId, - null, - isFollowersList ? followingFetchCb : followersFetchCb); + profileId, + null, + isFollowersList ? followingFetchCb : followersFetchCb); + } else showCompare(); } diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 84fea98e..fbc821c2 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -743,11 +743,33 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { binding.captionParent.getBackground().mutate().setAlpha((int) (128 + (128 * (slideOffset < 0 ? 0 : slideOffset)))); } }); - binding.caption.setOnClickListener(v -> { + binding.captionFrame.setOnClickListener(v -> { if (bottomSheetBehavior == null) return; if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) return; bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }); + if (TextUtils.isEmpty(feedModel.getCaptionId())) + binding.translateTitle.setVisibility(View.GONE); + else binding.translateTitle.setOnClickListener(v -> { + mediaService.translate(feedModel.getCaptionId(), "1", new ServiceCallback() { + @Override + public void onSuccess(final String result) { + if (TextUtils.isEmpty(result)) { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + return; + } + binding.translateTitle.setOnClickListener(null); + binding.translatedCaption.setVisibility(View.VISIBLE); + binding.translatedCaption.setText(result); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error translating comment", t); + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } + }); + }); binding.captionToggle.setOnClickListener(v -> { if (bottomSheetBehavior == null) return; switch (bottomSheetBehavior.getState()) { diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 7c2b4843..9edb51f6 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -89,6 +89,7 @@ import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.Utils; import awais.instagrabber.viewmodels.HighlightsViewModel; import awais.instagrabber.webservices.FriendshipService; +import awais.instagrabber.webservices.MediaService; import awais.instagrabber.webservices.ServiceCallback; import awais.instagrabber.webservices.StoriesService; @@ -113,6 +114,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe private Handler usernameSettingHandler; private FriendshipService friendshipService; private StoriesService storiesService; + private MediaService mediaService; private boolean shouldRefresh = true; private boolean hasStories = false; private HighlightsAdapter highlightsAdapter; @@ -298,6 +300,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe fragmentActivity = (MainActivity) requireActivity(); friendshipService = FriendshipService.getInstance(); storiesService = StoriesService.getInstance(); + mediaService = MediaService.getInstance(); accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); setHasOptionsMenu(true); @@ -695,6 +698,51 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe .trim())); profileDetailsBinding.mainBiography .addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim())); + profileDetailsBinding.mainBiography.setOnClickListener(v -> { + String[] commentDialogList; + if (!TextUtils.isEmpty(cookie)) { + commentDialogList = new String[]{ + getResources().getString(R.string.bio_copy), + getResources().getString(R.string.bio_translate) + }; + } else { + commentDialogList = new String[]{ + getResources().getString(R.string.bio_copy) + }; + } + new AlertDialog.Builder(context) + .setItems(commentDialogList, (d,w) -> { + switch (w) { + case 0: + Utils.copyText(context, biography); + break; + case 1: + mediaService.translate(profileModel.getId(), "3", new ServiceCallback() { + @Override + public void onSuccess(final String result) { + if (TextUtils.isEmpty(result)) { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); + return; + } + new AlertDialog.Builder(context) + .setTitle(profileModel.getUsername()) + .setMessage(result) + .setPositiveButton(R.string.ok, null) + .show(); + } + + @Override + public void onFailure(final Throwable t) { + Log.e(TAG, "Error translating bio", t); + Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show(); + } + }); + break; + } + }) + .setNegativeButton(R.string.cancel, null) + .show(); + }); profileDetailsBinding.mainBiography.setOnLongClickListener(v -> { Utils.copyText(context, biography); return true; diff --git a/app/src/main/java/awais/instagrabber/models/BasePostModel.java b/app/src/main/java/awais/instagrabber/models/BasePostModel.java index 38f5f8fd..4f8486d3 100755 --- a/app/src/main/java/awais/instagrabber/models/BasePostModel.java +++ b/app/src/main/java/awais/instagrabber/models/BasePostModel.java @@ -11,16 +11,12 @@ import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.utils.Utils; public abstract class BasePostModel implements Serializable, Selectable { - protected String postId; - protected String displayUrl; - protected String shortCode; + protected String postId, displayUrl, shortCode, captionId; protected CharSequence postCaption; protected MediaItemType itemType; - protected boolean isSelected; - protected boolean isDownloaded; + protected boolean isSelected, isDownloaded; protected long timestamp; - boolean liked; - boolean saved; + boolean liked, saved; public boolean getLike() { return liked; @@ -46,6 +42,10 @@ public abstract class BasePostModel implements Serializable, Selectable { return postCaption; } + public final String getCaptionId() { + return captionId; + } + public final String getShortCode() { return shortCode; } diff --git a/app/src/main/java/awais/instagrabber/models/FeedModel.java b/app/src/main/java/awais/instagrabber/models/FeedModel.java index d9178640..f4e51664 100755 --- a/app/src/main/java/awais/instagrabber/models/FeedModel.java +++ b/app/src/main/java/awais/instagrabber/models/FeedModel.java @@ -24,7 +24,7 @@ public final class FeedModel extends PostModel { private String displayUrl; private String thumbnailUrl; private String shortCode; - private String postCaption; + private String postCaption, captionId; private long commentsCount; private long timestamp; private boolean liked; @@ -76,6 +76,11 @@ public final class FeedModel extends PostModel { return this; } + public Builder setCaptionId(final String captionId) { + this.captionId = captionId; + return this; + } + public Builder setCommentsCount(final long commentsCount) { this.commentsCount = commentsCount; return this; @@ -127,8 +132,8 @@ public final class FeedModel extends PostModel { } public FeedModel build() { - return new FeedModel(profileModel, itemType, viewCount, postId, displayUrl, thumbnailUrl, shortCode, postCaption, commentsCount, - timestamp, liked, bookmarked, likesCount, locationName, locationId, sliderItems, imageHeight, imageWidth); + return new FeedModel(profileModel, itemType, viewCount, postId, displayUrl, thumbnailUrl, shortCode, postCaption, captionId, + commentsCount, timestamp, liked, bookmarked, likesCount, locationName, locationId, sliderItems, imageHeight, imageWidth); } } @@ -140,6 +145,7 @@ public final class FeedModel extends PostModel { final String thumbnailUrl, final String shortCode, final String postCaption, + final String captionId, final long commentsCount, final long timestamp, final boolean liked, @@ -150,7 +156,7 @@ public final class FeedModel extends PostModel { final List sliderItems, final int imageHeight, final int imageWidth) { - super(itemType, postId, displayUrl, thumbnailUrl, shortCode, postCaption, timestamp, liked, bookmarked); + super(itemType, postId, displayUrl, thumbnailUrl, shortCode, postCaption, captionId, timestamp, liked, bookmarked); this.profileModel = profileModel; this.commentsCount = commentsCount; this.likesCount = likesCount; diff --git a/app/src/main/java/awais/instagrabber/models/PostModel.java b/app/src/main/java/awais/instagrabber/models/PostModel.java index e74924d7..75bb6753 100755 --- a/app/src/main/java/awais/instagrabber/models/PostModel.java +++ b/app/src/main/java/awais/instagrabber/models/PostModel.java @@ -19,6 +19,7 @@ public class PostModel extends BasePostModel { final String thumbnailUrl, final String shortCode, final CharSequence postCaption, + final String captionId, long timestamp, boolean liked, boolean bookmarked) { @@ -28,6 +29,7 @@ public class PostModel extends BasePostModel { this.thumbnailUrl = thumbnailUrl; this.shortCode = shortCode; this.postCaption = postCaption; + this.captionId = captionId; this.timestamp = timestamp; this.liked = liked; this.saved = bookmarked; diff --git a/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java b/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java index f8e42a21..525a666f 100644 --- a/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/MediaRepository.java @@ -9,40 +9,38 @@ import retrofit2.http.GET; import retrofit2.http.Header; import retrofit2.http.POST; import retrofit2.http.Path; +import retrofit2.http.QueryMap; public interface MediaRepository { @GET("/api/v1/media/{mediaId}/likers/") - Call fetchLikes(@Header("User-Agent") final String userAgent, - @Path("mediaId") final String mediaId); + Call fetchLikes(@Path("mediaId") final String mediaId); @FormUrlEncoded @POST("/api/v1/media/{mediaId}/{action}/") - Call action(@Header("User-Agent") final String userAgent, - @Path("action") final String action, + Call action(@Path("action") final String action, @Path("mediaId") final String mediaId, @FieldMap final Map signedForm); @FormUrlEncoded @POST("/api/v1/media/{mediaId}/comment/") - Call comment(@Header("User-Agent") final String userAgent, - @Path("mediaId") final String mediaId, + Call comment(@Path("mediaId") final String mediaId, @FieldMap final Map signedForm); @FormUrlEncoded @POST("/api/v1/media/{mediaId}/comment/bulk_delete/") - Call commentsBulkDelete(@Header("User-Agent") final String userAgent, - @Path("mediaId") final String mediaId, + Call commentsBulkDelete(@Path("mediaId") final String mediaId, @FieldMap final Map signedForm); @FormUrlEncoded @POST("/api/v1/media/{commentId}/comment_like/") - Call commentLike(@Header("User-Agent") final String userAgent, - @Path("commentId") final String commentId, + Call commentLike(@Path("commentId") final String commentId, @FieldMap final Map signedForm); @FormUrlEncoded @POST("/api/v1/media/{commentId}/comment_unlike/") - Call commentUnlike(@Header("User-Agent") final String userAgent, - @Path("commentId") final String commentId, + Call commentUnlike(@Path("commentId") final String commentId, @FieldMap final Map signedForm); + + @GET("/api/v1/language/translate/") + Call translate(@QueryMap final Map form); } diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index c9029a00..8739f0c9 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -640,6 +640,7 @@ public final class ResponseBodyUtils { .setThumbnailUrl(mediaType != MediaItemType.MEDIA_TYPE_SLIDER ? ResponseBodyUtils.getLowQualityImage(itemJson) : null) .setShortCode(itemJson.getString("code")) .setPostCaption(captionJson != null ? captionJson.optString("text") : null) + .setCaptionId(captionJson != null ? captionJson.optString("pk") : null) .setCommentsCount(itemJson.optInt("comment_count")) .setTimestamp(itemJson.optLong("taken_at", -1)) .setLiked(itemJson.optBoolean("has_liked")) diff --git a/app/src/main/java/awais/instagrabber/webservices/MediaService.java b/app/src/main/java/awais/instagrabber/webservices/MediaService.java index f41c14cd..3e0c8a04 100644 --- a/app/src/main/java/awais/instagrabber/webservices/MediaService.java +++ b/app/src/main/java/awais/instagrabber/webservices/MediaService.java @@ -86,7 +86,7 @@ public class MediaService extends BaseService { form.put("_uuid", UUID.randomUUID().toString()); // form.put("radio_type", "wifi-none"); final Map signedForm = Utils.sign(form); - final Call request = repository.action(Constants.I_USER_AGENT, action, mediaId, signedForm); + final Call request = repository.action(action, mediaId, signedForm); request.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @@ -135,7 +135,7 @@ public class MediaService extends BaseService { form.put("replied_to_comment_id", replyToCommentId); } final Map signedForm = Utils.sign(form); - final Call commentRequest = repository.comment(Constants.I_USER_AGENT, mediaId, signedForm); + final Call commentRequest = repository.comment(mediaId, signedForm); commentRequest.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -181,7 +181,7 @@ public class MediaService extends BaseService { form.put("_uid", userId); form.put("_uuid", UUID.randomUUID().toString()); final Map signedForm = Utils.sign(form); - final Call bulkDeleteRequest = repository.commentsBulkDelete(Constants.USER_AGENT, mediaId, signedForm); + final Call bulkDeleteRequest = repository.commentsBulkDelete(mediaId, signedForm); bulkDeleteRequest.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -217,7 +217,7 @@ public class MediaService extends BaseService { // form.put("_uid", userId); // form.put("_uuid", UUID.randomUUID().toString()); final Map signedForm = Utils.sign(form); - final Call commentLikeRequest = repository.commentLike(Constants.USER_AGENT, commentId, signedForm); + final Call commentLikeRequest = repository.commentLike(commentId, signedForm); commentLikeRequest.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -253,7 +253,7 @@ public class MediaService extends BaseService { // form.put("_uid", userId); // form.put("_uuid", UUID.randomUUID().toString()); final Map signedForm = Utils.sign(form); - final Call commentUnlikeRequest = repository.commentUnlike(Constants.USER_AGENT, commentId, signedForm); + final Call commentUnlikeRequest = repository.commentUnlike(commentId, signedForm); commentUnlikeRequest.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -283,7 +283,7 @@ public class MediaService extends BaseService { public void fetchLikes(final String mediaId, @NonNull final ServiceCallback> callback) { - final Call likesRequest = repository.fetchLikes(Constants.I_USER_AGENT, mediaId); + final Call likesRequest = repository.fetchLikes(mediaId); likesRequest.enqueue(new Callback() { @Override public void onResponse(@NonNull final Call call, @NonNull final Response response) { @@ -324,4 +324,38 @@ public class MediaService extends BaseService { } }); } + + public void translate(final String id, + final String type, // 1 caption 2 comment 3 bio + @NonNull final ServiceCallback callback) { + final Map form = new HashMap<>(); + form.put("id", id); + form.put("type", type); + final Call request = repository.translate(form); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + final String body = response.body(); + if (body == null) { + Log.e(TAG, "Error occurred while translating"); + callback.onSuccess(null); + return; + } + try { + final JSONObject jsonObject = new JSONObject(body); + final String translation = jsonObject.optString("translation"); + callback.onSuccess(translation); + } catch (JSONException e) { + // Log.e(TAG, "Error parsing body", e); + callback.onFailure(e); + } + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + Log.e(TAG, "Error translating", t); + callback.onFailure(t); + } + }); + } } diff --git a/app/src/main/res/layout/dialog_post_view.xml b/app/src/main/res/layout/dialog_post_view.xml index b0a4227c..f1f220ad 100644 --- a/app/src/main/res/layout/dialog_post_view.xml +++ b/app/src/main/res/layout/dialog_post_view.xml @@ -159,20 +159,57 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@null"> - - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b82e1caf..728d29d6 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -112,6 +112,8 @@ Unblock Restrict Unrestrict + Copy bio + Translate bio Following each other Followed by you Following you @@ -195,6 +197,7 @@ Reply to comment Like comment Unlike comment + Translate comment Delete comment No empty comments! Do you want to search the username? @@ -288,6 +291,7 @@ Apply Save Caption + Translate caption... Video player timeline 1x 2x @@ -323,6 +327,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From eb2e5c2ee8751908ac843098ff6ce92af574f168 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:12 -0500 Subject: [PATCH 016/101] New translations strings.xml (Spanish) --- app/src/main/res/values-es/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index e398ae01..1c06e0c2 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -109,6 +109,8 @@ Desbloquear Restringir Desrestringir + Copy bio + Translate bio Siguiéndose mutuamente Seguido por ti Siguiéndote @@ -192,6 +194,7 @@ Responder a comentario Dar me gusta a comentario Quitar me gusta a comentario + Translate comment Eliminar comentario ¡No hay comentarios vacíos! ¿Quieres buscar el nombre de usuario? @@ -281,6 +284,7 @@ Aplicar Guardar Leyenda + Translate caption... Línea de tiempo del reproductor de vídeo Gustando… Me gusta fallido @@ -309,6 +313,7 @@ Mostrar espaciado de cuadrícula Desactivar animaciones ¡Por favor, espera a que la tarea actual se complete primero! + Depending on user counts, this can take a while to load. Please be patient. ¡Publicación no encontrada! No se encontró ninguna aplicación que abra los enlaces From ad01b68c9bbc70c38a92151121c9d9508ce56703 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:16 -0500 Subject: [PATCH 017/101] New translations strings.xml (French) --- app/src/main/res/values-fr/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 87879cf3..1900b978 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -109,6 +109,8 @@ Débloquer Restreindre Retirer des restrictions + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Répondre au commentaire Aimer le commentaire Retirer le j\'aime du commentaire + Translate comment Supprimer le commentaire Aucun commentaire vide ! Souhaitez-vous faire une recherche sur le nom d\'utilisateur ? @@ -281,6 +284,7 @@ Appliquer Sauvegarder Légende + Translate caption... Chronologie du lecteur vidéo Entrain d\'aimer… Erreur lors du \"j\'aime\" @@ -309,6 +313,7 @@ Afficher les lacunes de la grille Désactiver les animations Veuillez d\'abord attendre que la tâche en cours soit terminée ! + Depending on user counts, this can take a while to load. Please be patient. Publication non trouvée! Aucune application trouvée qui ouvre les urls From 31bba15eb175be44c9a5be8bc045ed3640452ffb Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:17 -0500 Subject: [PATCH 018/101] New translations strings.xml (Dutch) --- app/src/main/res/values-nl/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 37f18a9f..020f38ec 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -109,6 +109,8 @@ Deblokkeer Beperk De-restrict + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Reageer op opmerking Vind reactie leuk Vind reactie niet meer leuk + Translate comment Verwijder opmerking Geen lege reacties! Wil je de gebruikersnaam zoeken? @@ -281,6 +284,7 @@ Toepassen Opslaan Bijschrift + Translate caption... Videospeler tijdlijn Liken… Like niet gelukt @@ -309,6 +313,7 @@ Rasterruimte weergeven Animatie uitschakelen Wacht eerst tot de huidige taak voltooid is! + Depending on user counts, this can take a while to load. Please be patient. Bericht niet gevonden! Geen app gevonden om URL\'s te openen From db48c83a15f327a64f718cf8661ddef09cb24554 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:20 -0500 Subject: [PATCH 019/101] New translations strings.xml (Russian) --- app/src/main/res/values-ru/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a1c6d6c7..73cf5724 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -115,6 +115,8 @@ Разблокировать Ограничить Снять ограничение + Copy bio + Translate bio Following each other Followed by you Following you @@ -198,6 +200,7 @@ Ответить на комментарий Мне нравится комментарий Не нравится комментарий + Translate comment Удалить комментарий Нет пустых комментариев! Вы хотите найти имя пользователя? @@ -287,6 +290,7 @@ Применить Сохранить Заголовок + Translate caption... Лента времени видеопроигрывателя Нравится… Нравится неудачно @@ -315,6 +319,7 @@ Показать разрыв сетки Отключить анимацию Пожалуйста, дождитесь сначала выполнения текущей задачи! + Depending on user counts, this can take a while to load. Please be patient. Публикация не найдена! Нет приложения, чтоб открыть ссылку From 9154640da9da109ca5a2ca4a5074d53a338b7d21 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:23 -0500 Subject: [PATCH 020/101] New translations strings.xml (Catalan) --- app/src/main/res/values-ca/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index c14d0abc..c15d09ff 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -109,6 +109,8 @@ Desbloquejar Restringir Deixar de restringir + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Respondre al comentari Donar \"m\'agrada\" al comentari Treure \"m\'agrada\" al comentari + Translate comment Esborrar comentari No als comentaris buits! Vols cercar el nom d\'usuari? @@ -281,6 +284,7 @@ Aplicar Desar Llegenda + Translate caption... Línia de temps del reproductor de vídeo Donant m\'agrada… El \"m\'agrada\" ha fallat @@ -309,6 +313,7 @@ Mostrar la separació de la graella Desactivar l\'animació Espera primer que la tasca actual s\'hagi completat! + Depending on user counts, this can take a while to load. Please be patient. Publicació no trobada! No s\'ha trobat cap aplicació que obri l\'enllaç From 19728ba3483dab2e194121e76fff4c8245dce517 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:26 -0500 Subject: [PATCH 021/101] New translations strings.xml (Odia) --- app/src/main/res/values-or/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index 1bce7999..a313ff73 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -109,6 +109,8 @@ Unblock Restrict Unrestrict + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Reply to comment Like comment Unlike comment + Translate comment Delete comment No empty comments! Do you want to search the username? @@ -281,6 +284,7 @@ Apply Save Caption + Translate caption... Video player timeline Liking… Like unsuccessful @@ -309,6 +313,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From 57a72798b2f2681796c7af69968dede7e6f3a158 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:28 -0500 Subject: [PATCH 022/101] New translations strings.xml (Hindi) --- app/src/main/res/values-hi/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index c7fc7be2..b8eb49e8 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -110,6 +110,8 @@ अनब्ल़ॉक करें प्रतिबंध लगाए प्रतिबंध न लगाए + Copy bio + Translate bio Following each other Followed by you Following you @@ -193,6 +195,7 @@ टिप्पणी का जवाब दें टिप्पणी को पसन्द करें टिप्पणी को पसन्द न करें + Translate comment टिप्पणी हटा दें रिक्त टिप्पणी न करें! ब्यबहारकारी के नाम ढूंढने चाहते हैं? @@ -282,6 +285,7 @@ Apply Save Caption + Translate caption... Video player timeline Liking… Like unsuccessful @@ -310,6 +314,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From 7457d43a2948b15082e00067fe603a32f10ed693 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:31 -0500 Subject: [PATCH 023/101] New translations strings.xml (Persian) --- app/src/main/res/values-fa/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 38e0948f..6d6ca256 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -110,6 +110,8 @@ رفع مسدودیت محدود کردن حذف محدودیت + Copy bio + Translate bio Following each other Followed by you Following you @@ -193,6 +195,7 @@ پاسخ به دیدگاه پسندیدن دیدگاه نپسندیدن دیدگاه + Translate comment هذف دیدگاه بدون دیدگاه تهی! ایا میخواهید نام کاربری جستوجو کنید ؟ @@ -282,6 +285,7 @@ گماشتن Save Caption + Translate caption... Video player timeline پسندیدن… Like unsuccessful @@ -310,6 +314,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From 5f9246ea25be58003419b4f042355f2dfd0af8fd Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:34 -0500 Subject: [PATCH 024/101] New translations strings.xml (Indonesian) --- app/src/main/res/values-in/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 71868b83..a2377e31 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -106,6 +106,8 @@ Batalkan Blokir Batasi Hilangkan Batasan + Copy bio + Translate bio Following each other Followed by you Following you @@ -189,6 +191,7 @@ Balas komentar Suka komentar Batal suka komentar + Translate comment Hapus komentar Ups, komentar kosong! Apakah anda ingin mencari nama pengguna ini? @@ -278,6 +281,7 @@ Terapkan Simpan Keterangan + Translate caption... Bilah waktu pemutar video Menyukai… Gagal menyukai @@ -306,6 +310,7 @@ Tampilkan batas kisi Matikan animasi Harap tunggu hingga tugas saat ini selesai! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From 521b58844ab0365fe881a596af5c389e39108d24 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:36 -0500 Subject: [PATCH 025/101] New translations strings.xml (Portuguese, Brazilian) --- app/src/main/res/values-pt/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index fb874ff2..27106aef 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -109,6 +109,8 @@ Desbloquear Restringir Deixar de restringir + Copy bio + Translate bio Seguindo um ao outro Seguido por você Segue você @@ -192,6 +194,7 @@ Responder comentário Curtir comentário Descurtir comentário + Translate comment Excluir comentário Comentário em branco! Você quer pesquisar o nome de usuário? @@ -281,6 +284,7 @@ Aplicar Salvar Legenda + Translate caption... Barra de progresso do reprodutor de vídeo Curtindo… Falha ao curtir @@ -309,6 +313,7 @@ Grades separadas Animação Por favor, espere a tarefa atual ser concluída primeiro! + Depending on user counts, this can take a while to load. Please be patient. Publicação não encontrada! Nenhum aplicativo para abrir urls encontrado From cde8ec463e445605c954b451433b21e70163b5ad Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:40 -0500 Subject: [PATCH 026/101] New translations strings.xml (Vietnamese) --- app/src/main/res/values-vi/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 1fe21111..74f92306 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -106,6 +106,8 @@ Bỏ chặn Giới hạn Bỏ giới hạn + Copy bio + Translate bio Following each other Followed by you Following you @@ -189,6 +191,7 @@ Trả lời bình luận Thích bình luận Bỏ thích bình luận + Translate comment Xóa bình luận Không được để trống bình luận! Bạn có muốn tìm tên người dùng không? @@ -278,6 +281,7 @@ Áp dụng Lưu Chú thích + Translate caption... Thanh thời gian của trình phát video Đang thích… Không thể thích @@ -306,6 +310,7 @@ Hiển thị khoảng trống lưới Tắt hoạt ảnh Xin hãy đợi công việc hiện tại hoàn thành trước! + Depending on user counts, this can take a while to load. Please be patient. Không tìm thấy bài viết! Không có app nào để mở link này From 2fa583bf2a027558a2cb61357ea220eeb2ba4a8e Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:44 -0500 Subject: [PATCH 027/101] New translations strings.xml (Czech) --- app/src/main/res/values-cs/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 7cb1d43c..03ea8184 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -115,6 +115,8 @@ Unblock Restrict Unrestrict + Copy bio + Translate bio Following each other Followed by you Following you @@ -198,6 +200,7 @@ Reply to comment Like comment Unlike comment + Translate comment Delete comment No empty comments! Do you want to search the username? @@ -287,6 +290,7 @@ Apply Save Caption + Translate caption... Video player timeline Liking… Like unsuccessful @@ -315,6 +319,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From b87246e23434dae5230dd89334d19a84eb48d2a1 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:47 -0500 Subject: [PATCH 028/101] New translations strings.xml (German) --- app/src/main/res/values-de/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a852568c..dce72b45 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -109,6 +109,8 @@ Nicht mehr blockieren Einschränken Nicht mehr einschränken + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Auf Kommentar antworten Kommentar gefällt mir Kommentar gefällt mir nicht mehr + Translate comment Kommentar löschen Keine leeren Kommentare! Möchtest du nach dem Benutzernamen suchen? @@ -281,6 +284,7 @@ Anwenden Speichern Bildunterschrift + Translate caption... Zeitleiste des Videoplayers Liking… Like unsuccessful @@ -309,6 +313,7 @@ Rasterabstand anzeigen Animationen deaktivieren Bitte warte bis die aktuelle Aufgabe abgeschlossen ist! + Depending on user counts, this can take a while to load. Please be patient. Beitrag nicht gefunden! Keine App gefunden, die URLs öffnet From b05c928134315264cdcdfd11f493990adeea592d Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:49 -0500 Subject: [PATCH 029/101] New translations strings.xml (Italian) --- app/src/main/res/values-it/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 045b4898..6bc63b1b 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -109,6 +109,8 @@ Sblocca Limita Rimuovi limitazione + Copy bio + Translate bio Si seguono a vicenda Seguito da te Ti segue @@ -192,6 +194,7 @@ Rispondi al commento Mi Piace il commento Il commento Non mi Piace Più + Translate comment Elimina commento Nessun commento vuoto! Vuoi cercare il nome utente? @@ -281,6 +284,7 @@ Applica Salva Didascalia + Translate caption... Barra temporale del lettore video Mettendo Mi Piace… Impossibile mettere Mi Piace @@ -309,6 +313,7 @@ Mostra divario griglia Disabilita animazione Prima, sei pregato di attendere che l\'attività corrente sia completata! + Depending on user counts, this can take a while to load. Please be patient. Post non trovato! Nessuna applicazione trovata che apre gli urls From 7c5523406ef0a64cc4f45d4cbae8d4c54c55f45b Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:51 -0500 Subject: [PATCH 030/101] New translations strings.xml (Macedonian) --- app/src/main/res/values-mk/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index e38c3345..a2b71cf2 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -109,6 +109,8 @@ Одблокни Ограничи Одограничи + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Одговори на коментар Лајкни коментар Одлајкни коментар + Translate comment Избриши коментар Не смее празни коментари! Дали сакате да го пребарате ова корисничко име? @@ -281,6 +284,7 @@ Apply Save Caption + Translate caption... Video player timeline Liking… Like unsuccessful @@ -309,6 +313,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From bca45e320113984290a9cbc963fa19c5e2f6b1f7 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:53 -0500 Subject: [PATCH 031/101] New translations strings.xml (Chinese Traditional) --- app/src/main/res/values-zh-rTW/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fe7a306e..f6f9043a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -106,6 +106,8 @@ 解除封鎖 限制 移除限制 + Copy bio + Translate bio 正彼此追蹤 您已追蹤 關注了你 @@ -189,6 +191,7 @@ 回覆評論 對此評論說讚 收回評論的讚 + Translate comment 刪除評論 無空評論! 您要搜尋用戶名嗎? @@ -278,6 +281,7 @@ 套用 儲存 說明 + Translate caption... 影片播放器時間軸 按讚中… 按讚失敗 @@ -306,6 +310,7 @@ 網格間保留間距 停用動畫 請先等候目前的工作完成! + Depending on user counts, this can take a while to load. Please be patient. 貼文不存在! No app found which opens urls From 6e494d1012e7b263f1e85acfb382d29352ac9d59 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:56 -0500 Subject: [PATCH 032/101] New translations strings.xml (Polish) --- app/src/main/res/values-pl/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index d89333ab..cd55c037 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -115,6 +115,8 @@ Odblokuj Ogranicz Nieograniczone + Copy bio + Translate bio Following each other Followed by you Following you @@ -198,6 +200,7 @@ Odpowiedz na komentarz Polub komentarz Usuń polubienie komentarza + Translate comment Usuń komentarz Brak komentarzy! Czy chcesz wyszukać przy pomocy nazwy użytkownika? @@ -287,6 +290,7 @@ Zastosuj Zapisz Nagłówek + Translate caption... Oś czasu odtwarzacza wideo Przesyłanie polubienia… Nie udało się polubić @@ -315,6 +319,7 @@ Pokaż widok siatki Wyłączenie animacji Poczekaj aż bieżące zadanie zostanie ukończone! + Depending on user counts, this can take a while to load. Please be patient. Nie znaleziono posta! Nie znaleziono aplikacji, która otwiera adresy URL From a2f0db9b52c993b76dbb9ad0e78c22004253ca8a Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:32:58 -0500 Subject: [PATCH 033/101] New translations strings.xml (Turkish) --- app/src/main/res/values-tr/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 75e38c23..758a4afa 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -109,6 +109,8 @@ Engeli kaldır Kısıtla Kısıtlamayı Kaldır + Copy bio + Translate bio Karşılıklı takip ediliyor Takip ediliyor Seni takip ediyor @@ -192,6 +194,7 @@ Yoruma cevap ver Yorumu beğen Yorum beğenisini geri al + Translate comment Yorumu sil Boş yorum yapılamaz! Kullanıcı adını aratmak istiyor musun? @@ -281,6 +284,7 @@ Uygula Kaydet Başlık + Translate caption... Video oynatıcı zaman çizelgesi Beğeniliyor… Beğenme başarısız oldu @@ -309,6 +313,7 @@ Izgara boşluklarını göster Animasyonları devre dışı bırak Lütfen önce aktif görevin tamamlanmasını bekle! + Depending on user counts, this can take a while to load. Please be patient. Gönderi bulunamadı! Linki açabilecek uygulama bulunamadı From d6187f1be0afe23329a2bf0188c331958d771a22 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:33:01 -0500 Subject: [PATCH 034/101] New translations strings.xml (Chinese Simplified) --- app/src/main/res/values-zh-rCN/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index fc166541..cb2dde4a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -106,6 +106,8 @@ 解禁 限制 放开 + Copy bio + Translate bio 互相关注 您已关注 关注了您 @@ -189,6 +191,7 @@ 回复评论 赞评论 取消赞 + Translate comment 删除评论 评论要写字的! 要搜索用户名吗? @@ -278,6 +281,7 @@ 应用 保存 说明 + Translate caption... 视频播放器时间线 正在赞… 点赞失败 @@ -306,6 +310,7 @@ 显示网格间距 禁用动画 请等待当前任务完成! + Depending on user counts, this can take a while to load. Please be patient. 找不到该帖! 没有找到打开网址的应用 From 86d963eab9d8fe1e74e460ab0a5f5bb965ebe0f8 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 21:33:04 -0500 Subject: [PATCH 035/101] New translations strings.xml (Kannada) --- app/src/main/res/values-kn/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index c68149fb..b102c23d 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -109,6 +109,8 @@ Unblock Restrict Unrestrict + Copy bio + Translate bio Following each other Followed by you Following you @@ -192,6 +194,7 @@ Reply to comment Like comment Unlike comment + Translate comment Delete comment No empty comments! Do you want to search the username? @@ -281,6 +284,7 @@ Apply Save Caption + Translate caption... Video player timeline Liking… Like unsuccessful @@ -309,6 +313,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From 3e67576f57941fd0d8e2e8d3393a9124dca8f263 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 23:25:51 -0500 Subject: [PATCH 036/101] Update source file strings.xml --- app/src/main/res/values/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b82e1caf..728d29d6 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -112,6 +112,8 @@ Unblock Restrict Unrestrict + Copy bio + Translate bio Following each other Followed by you Following you @@ -195,6 +197,7 @@ Reply to comment Like comment Unlike comment + Translate comment Delete comment No empty comments! Do you want to search the username? @@ -288,6 +291,7 @@ Apply Save Caption + Translate caption... Video player timeline 1x 2x @@ -323,6 +327,7 @@ Show grid gap Disable animation Please wait for the current task to complete first! + Depending on user counts, this can take a while to load. Please be patient. Post not found! No app found which opens urls From b2fb9c2628d9d71be5a4bb5a2226a21cfe139d49 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Mon, 21 Dec 2020 23:25:54 -0500 Subject: [PATCH 037/101] New translations strings.xml (Chinese Simplified) --- app/src/main/res/values-zh-rCN/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cb2dde4a..572e4c2f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -106,8 +106,8 @@ 解禁 限制 放开 - Copy bio - Translate bio + 复制个人简介 + 翻译简介 互相关注 您已关注 关注了您 @@ -191,7 +191,7 @@ 回复评论 赞评论 取消赞 - Translate comment + 翻译评论 删除评论 评论要写字的! 要搜索用户名吗? @@ -281,7 +281,7 @@ 应用 保存 说明 - Translate caption... + 翻译字幕...... 视频播放器时间线 正在赞… 点赞失败 @@ -310,7 +310,7 @@ 显示网格间距 禁用动画 请等待当前任务完成! - Depending on user counts, this can take a while to load. Please be patient. + 根据用户数量的不同,加载过程可能需要一段时间。请耐心等待。 找不到该帖! 没有找到打开网址的应用 From 8858779770b2cba95aae6db0ad8acf888843a831 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 01:39:34 -0500 Subject: [PATCH 038/101] New translations strings.xml (Spanish) --- app/src/main/res/values-es/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 1c06e0c2..432b173f 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -109,8 +109,8 @@ Desbloquear Restringir Desrestringir - Copy bio - Translate bio + Copiar biografía + Traducir biografía Siguiéndose mutuamente Seguido por ti Siguiéndote @@ -194,7 +194,7 @@ Responder a comentario Dar me gusta a comentario Quitar me gusta a comentario - Translate comment + Traducir comentario Eliminar comentario ¡No hay comentarios vacíos! ¿Quieres buscar el nombre de usuario? @@ -284,7 +284,7 @@ Aplicar Guardar Leyenda - Translate caption... + Traducir leyenda... Línea de tiempo del reproductor de vídeo Gustando… Me gusta fallido @@ -313,7 +313,7 @@ Mostrar espaciado de cuadrícula Desactivar animaciones ¡Por favor, espera a que la tarea actual se complete primero! - Depending on user counts, this can take a while to load. Please be patient. + Dependiendo de la cuenta de usuario, esto puede tardar un tiempo. Por favor, sea paciente. ¡Publicación no encontrada! No se encontró ninguna aplicación que abra los enlaces From 2ad3684db1432c6811bdfd41e7c96fd7b2ad455f Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 02:14:41 -0500 Subject: [PATCH 039/101] New translations strings.xml (French) --- app/src/main/res/values-fr/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 1900b978..fb57dbbf 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -109,8 +109,8 @@ Débloquer Restreindre Retirer des restrictions - Copy bio - Translate bio + Copier la bio + Traduire la bio Following each other Followed by you Following you @@ -194,7 +194,7 @@ Répondre au commentaire Aimer le commentaire Retirer le j\'aime du commentaire - Translate comment + Traduire le commentaire Supprimer le commentaire Aucun commentaire vide ! Souhaitez-vous faire une recherche sur le nom d\'utilisateur ? @@ -284,7 +284,7 @@ Appliquer Sauvegarder Légende - Translate caption... + Traduire la légende... Chronologie du lecteur vidéo Entrain d\'aimer… Erreur lors du \"j\'aime\" @@ -313,7 +313,7 @@ Afficher les lacunes de la grille Désactiver les animations Veuillez d\'abord attendre que la tâche en cours soit terminée ! - Depending on user counts, this can take a while to load. Please be patient. + Selon le nombre d\'utilisateurs, cela peut prendre un certain temps à charger. Veuillez patienter. Publication non trouvée! Aucune application trouvée qui ouvre les urls From c98a694a27d249d7e540527556e2623c898efc25 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 05:35:41 -0500 Subject: [PATCH 040/101] New translations strings.xml (Portuguese, Brazilian) --- app/src/main/res/values-pt/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 27106aef..d73b5cc8 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -109,8 +109,8 @@ Desbloquear Restringir Deixar de restringir - Copy bio - Translate bio + Copiar bio + Traduzir bio Seguindo um ao outro Seguido por você Segue você @@ -194,7 +194,7 @@ Responder comentário Curtir comentário Descurtir comentário - Translate comment + Traduzir comentário Excluir comentário Comentário em branco! Você quer pesquisar o nome de usuário? @@ -284,7 +284,7 @@ Aplicar Salvar Legenda - Translate caption... + Traduzir legenda... Barra de progresso do reprodutor de vídeo Curtindo… Falha ao curtir @@ -313,7 +313,7 @@ Grades separadas Animação Por favor, espere a tarefa atual ser concluída primeiro! - Depending on user counts, this can take a while to load. Please be patient. + Dependendo da contagem de usuários, isso pode levar um tempo para carregar. Por favor, seja paciente. Publicação não encontrada! Nenhum aplicativo para abrir urls encontrado From 0a731e5abad64a79f0c47b0a307c7573a947b5aa Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 08:25:12 -0500 Subject: [PATCH 041/101] New translations strings.xml (Spanish) --- app/src/main/res/values-es/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 432b173f..f75cb722 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -43,7 +43,7 @@ Importar/Exportar Idioma - %s Post + %s publicación %s publicaciones From 05fd50aa1ebbf519eacf8e6f2024a888bdd7259d Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 09:01:34 -0500 Subject: [PATCH 042/101] New translations strings.xml (Italian) --- app/src/main/res/values-it/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 6bc63b1b..d51edc31 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -109,8 +109,8 @@ Sblocca Limita Rimuovi limitazione - Copy bio - Translate bio + Copia bio + Traduci bio Si seguono a vicenda Seguito da te Ti segue From 3661d95c6666b8a409f9c90be55c6ed3c8f27ad7 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 09:27:10 -0500 Subject: [PATCH 043/101] New translations strings.xml (Italian) --- app/src/main/res/values-it/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d51edc31..75e70a49 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -194,7 +194,7 @@ Rispondi al commento Mi Piace il commento Il commento Non mi Piace Più - Translate comment + Traduci commento Elimina commento Nessun commento vuoto! Vuoi cercare il nome utente? @@ -284,7 +284,7 @@ Applica Salva Didascalia - Translate caption... + Traduci didascalia... Barra temporale del lettore video Mettendo Mi Piace… Impossibile mettere Mi Piace @@ -313,7 +313,7 @@ Mostra divario griglia Disabilita animazione Prima, sei pregato di attendere che l\'attività corrente sia completata! - Depending on user counts, this can take a while to load. Please be patient. + A seconda del numero di utenti, questo può richiedere un po\' di tempo. Si prega di essere pazienti. Post non trovato! Nessuna applicazione trovata che apre gli urls From 22fc894c9d94bb527f59c754f0ea0aaa0c747913 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 11:54:52 -0500 Subject: [PATCH 044/101] implement app feed endpoint instead of browser --- .../asyncs/FeedPostFetchService.java | 33 ++++- .../repositories/FeedRepository.java | 14 ++ .../instagrabber/webservices/FeedService.java | 137 ++++++++++++++++++ .../webservices/GraphQLService.java | 36 ----- .../webservices/LocationService.java | 2 - .../webservices/ProfileService.java | 2 - .../instagrabber/webservices/TagsService.java | 2 - 7 files changed, 178 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/awais/instagrabber/repositories/FeedRepository.java create mode 100644 app/src/main/java/awais/instagrabber/webservices/FeedService.java diff --git a/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java b/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java index a3792921..65cf3e12 100644 --- a/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java +++ b/app/src/main/java/awais/instagrabber/asyncs/FeedPostFetchService.java @@ -1,34 +1,55 @@ package awais.instagrabber.asyncs; +import android.util.Log; + +import java.util.ArrayList; import java.util.List; import awais.instagrabber.customviews.helpers.PostFetcher; import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.FeedModel; import awais.instagrabber.repositories.responses.PostsFetchResponse; -import awais.instagrabber.webservices.GraphQLService; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.CookieUtils; +import awais.instagrabber.webservices.FeedService; import awais.instagrabber.webservices.ServiceCallback; +import static awais.instagrabber.utils.Utils.settingsHelper; + public class FeedPostFetchService implements PostFetcher.PostFetchService { private static final String TAG = "FeedPostFetchService"; - private final GraphQLService graphQLService; + private final FeedService feedService; private String nextCursor; private boolean hasNextPage; public FeedPostFetchService() { - graphQLService = GraphQLService.getInstance(); + feedService = FeedService.getInstance(); } @Override public void fetch(final FetchListener> fetchListener) { - graphQLService.fetchFeed(25, nextCursor, new ServiceCallback() { + final List feedModels = new ArrayList<>(); + final String cookie = settingsHelper.getString(Constants.COOKIE); + final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); + feedModels.clear(); + feedService.fetch(csrfToken, nextCursor, new ServiceCallback() { @Override public void onSuccess(final PostsFetchResponse result) { - if (result == null) return; + if (result == null && feedModels.size() > 0) { + fetchListener.onResult(feedModels); + return; + } + else if (result == null) return; nextCursor = result.getNextCursor(); hasNextPage = result.hasNextPage(); + feedModels.addAll(result.getFeedModels()); if (fetchListener != null) { - fetchListener.onResult(result.getFeedModels()); + if (feedModels.size() < 15 && hasNextPage) { + feedService.fetch(csrfToken, nextCursor, this); + } + else { + fetchListener.onResult(feedModels); + } } } diff --git a/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java b/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java new file mode 100644 index 00000000..24ac5e01 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/repositories/FeedRepository.java @@ -0,0 +1,14 @@ +package awais.instagrabber.repositories; + +import java.util.Map; + +import retrofit2.Call; +import retrofit2.http.FieldMap; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.POST; + +public interface FeedRepository { + @FormUrlEncoded + @POST("/api/v1/feed/timeline/") + Call fetch(@FieldMap final Map signedForm); +} diff --git a/app/src/main/java/awais/instagrabber/webservices/FeedService.java b/app/src/main/java/awais/instagrabber/webservices/FeedService.java new file mode 100644 index 00000000..fd491293 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/webservices/FeedService.java @@ -0,0 +1,137 @@ +package awais.instagrabber.webservices; + +import android.os.Handler; +import android.util.Log; + +import androidx.annotation.NonNull; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; + +import awais.instagrabber.models.FeedModel; +import awais.instagrabber.models.PostChild; +import awais.instagrabber.models.ProfileModel; +import awais.instagrabber.models.enums.MediaItemType; +import awais.instagrabber.repositories.FeedRepository; +import awais.instagrabber.repositories.responses.PostsFetchResponse; +import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.ResponseBodyUtils; +import awais.instagrabber.utils.TextUtils; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +public class FeedService extends BaseService { + private static final String TAG = "FeedService"; + + private final FeedRepository repository; + + private static FeedService instance; + + private FeedService() { + final Retrofit retrofit = getRetrofitBuilder() + .baseUrl("https://i.instagram.com") + .build(); + repository = retrofit.create(FeedRepository.class); + } + + public static FeedService getInstance() { + if (instance == null) { + instance = new FeedService(); + } + return instance; + } + + public void fetch(final String csrfToken, + final String cursor, + final ServiceCallback callback) { + final Map form = new HashMap<>(); + form.put("_uuid", UUID.randomUUID().toString()); + form.put("_csrftoken", csrfToken); + form.put("phone_id", UUID.randomUUID().toString()); + form.put("device_id", UUID.randomUUID().toString()); + form.put("client_session_id", UUID.randomUUID().toString()); + form.put("is_prefetch", "0"); + form.put("timezone_offset", String.valueOf(TimeZone.getDefault().getRawOffset() / 1000)); + if (!TextUtils.isEmpty(cursor)) { + form.put("max_id", cursor); + form.put("reason", "pagination"); + } + else { + form.put("is_pull_to_refresh", "1"); + form.put("reason", "pull_to_refresh"); + } + final Call request = repository.fetch(form); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, @NonNull final Response response) { + try { + // Log.d(TAG, "onResponse: body: " + response.body()); + final PostsFetchResponse postsFetchResponse = parseResponse(response); + if (callback != null) { + callback.onSuccess(postsFetchResponse); + } + } catch (JSONException e) { + Log.e(TAG, "onResponse", e); + if (callback != null) { + callback.onFailure(e); + } + } + } + + @Override + public void onFailure(@NonNull final Call call, @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); + + } + + @NonNull + private PostsFetchResponse parseResponse(@NonNull final Response response) throws JSONException { + if (TextUtils.isEmpty(response.body())) { + Log.e(TAG, "parseResponse: feed response body is empty with status code: " + response.code()); + return new PostsFetchResponse(Collections.emptyList(), false, null); + } + return parseResponseBody(response.body()); + } + + @NonNull + private PostsFetchResponse parseResponseBody(@NonNull final String body) + throws JSONException { + final JSONObject root = new JSONObject(body); + final boolean moreAvailable = root.optBoolean("more_available"); + final String nextMaxId = root.optString("next_max_id"); + final JSONArray feedItems = root.optJSONArray("items"); + final List feedModels = new ArrayList<>(); + for (int i = 0; i < feedItems.length(); ++i) { + final JSONObject itemJson = feedItems.optJSONObject(i); + if (itemJson == null || itemJson.has("injected") + ) { + continue; + } + final FeedModel feedModel = ResponseBodyUtils.parseItem(itemJson); + if (feedModel != null) { + feedModels.add(feedModel); + } + } + return new PostsFetchResponse(feedModels, moreAvailable, nextMaxId); + } +} \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java index 94d9f38f..d21c7870 100644 --- a/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java +++ b/app/src/main/java/awais/instagrabber/webservices/GraphQLService.java @@ -88,42 +88,6 @@ public class GraphQLService extends BaseService { }); } - public void fetchFeed(final int maxItemsToLoad, - final String cursor, - final ServiceCallback callback) { - if (loadFromMock) { - final Handler handler = new Handler(); - handler.postDelayed(() -> { - final ClassLoader classLoader = getClass().getClassLoader(); - if (classLoader == null) { - Log.e(TAG, "fetch: classLoader is null!"); - return; - } - try (InputStream resourceAsStream = classLoader.getResourceAsStream("feed_response.json"); - Reader in = new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8)) { - final int bufferSize = 1024; - final char[] buffer = new char[bufferSize]; - final StringBuilder out = new StringBuilder(); - int charsRead; - while ((charsRead = in.read(buffer, 0, buffer.length)) > 0) { - out.append(buffer, 0, charsRead); - } - callback.onSuccess(parseResponseBody(out.toString(), Constants.EXTRAS_USER, "edge_web_feed_timeline")); - } catch (IOException | JSONException e) { - Log.e(TAG, "fetch: ", e); - } - }, 1000); - return; - } - fetch("c699b185975935ae2a457f24075de8c7", - "{\"fetch_media_item_count\":" + maxItemsToLoad + "," + - "\"fetch_like\":3,\"has_stories\":false,\"has_stories\":false,\"has_threaded_comments\":true," + - "\"fetch_media_item_cursor\":\"" + (cursor == null ? "" : cursor) + "\"}", - Constants.EXTRAS_USER, - "edge_web_feed_timeline", - callback); - } - public void fetchLocationPosts(@NonNull final String locationId, final String maxId, final ServiceCallback callback) { diff --git a/app/src/main/java/awais/instagrabber/webservices/LocationService.java b/app/src/main/java/awais/instagrabber/webservices/LocationService.java index d0bbe7c2..a9b40981 100644 --- a/app/src/main/java/awais/instagrabber/webservices/LocationService.java +++ b/app/src/main/java/awais/instagrabber/webservices/LocationService.java @@ -89,8 +89,6 @@ public class LocationService extends BaseService { final JSONObject root = new JSONObject(body); final boolean moreAvailable = root.optBoolean("more_available"); final String nextMaxId = root.optString("next_max_id"); - final int numResults = root.optInt("num_results"); - final String status = root.optString("status"); final JSONArray itemsJson = root.optJSONArray("items"); final List items = parseItems(itemsJson); return new PostsFetchResponse( diff --git a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java index 8e3c4c6a..056463d9 100644 --- a/app/src/main/java/awais/instagrabber/webservices/ProfileService.java +++ b/app/src/main/java/awais/instagrabber/webservices/ProfileService.java @@ -228,8 +228,6 @@ public class ProfileService extends BaseService { final JSONObject root = new JSONObject(body); final boolean moreAvailable = root.optBoolean("more_available"); final String nextMaxId = root.optString("next_max_id"); - final int numResults = root.optInt("num_results"); - final String status = root.optString("status"); final JSONArray itemsJson = root.optJSONArray("items"); final List items = parseItems(itemsJson, isInMedia); return new PostsFetchResponse( diff --git a/app/src/main/java/awais/instagrabber/webservices/TagsService.java b/app/src/main/java/awais/instagrabber/webservices/TagsService.java index 5786e82f..7f3dc490 100644 --- a/app/src/main/java/awais/instagrabber/webservices/TagsService.java +++ b/app/src/main/java/awais/instagrabber/webservices/TagsService.java @@ -158,8 +158,6 @@ public class TagsService extends BaseService { final JSONObject root = new JSONObject(body); final boolean moreAvailable = root.optBoolean("more_available"); final String nextMaxId = root.optString("next_max_id"); - final int numResults = root.optInt("num_results"); - final String status = root.optString("status"); final JSONArray itemsJson = root.optJSONArray("items"); final List items = parseItems(itemsJson); return new PostsFetchResponse( From 9ca9cca33d2b7961cd00f43608ee6c2d8b97d7f2 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 13:42:26 -0500 Subject: [PATCH 045/101] restore dm indicator, release prep, partially address #431 --- app/build.gradle | 4 +- .../fragments/FollowViewerFragment.java | 3 +- .../instagrabber/utils/ResponseBodyUtils.java | 7 ++- .../layout/dialog_post_layout_preferences.xml | 44 +++++++++++++++---- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3e81b904..e0d766c3 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { minSdkVersion 21 targetSdkVersion 29 - versionCode 54 - versionName '19.0.2' + versionCode 55 + versionName '19.0.3' multiDexEnabled true diff --git a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java index 4da57ca4..260b5da5 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FollowViewerFragment.java @@ -249,8 +249,8 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh loading = true; setSubtitle(R.string.followers_compare); allFollowing.clear(); - binding.swipeRefreshLayout.setRefreshing(true); if (moreAvailable) { + binding.swipeRefreshLayout.setRefreshing(true); Toast.makeText(getContext(), R.string.follower_start_compare, Toast.LENGTH_LONG).show(); friendshipService.getList(isFollowersList, profileId, @@ -258,6 +258,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh isFollowersList ? followersFetchCb : followingFetchCb); } else if (followersModels.size() == 0 || followingModels.size() == 0) { + binding.swipeRefreshLayout.setRefreshing(true); Toast.makeText(getContext(), R.string.follower_start_compare, Toast.LENGTH_LONG).show(); friendshipService.getList(!isFollowersList, profileId, diff --git a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java index 8739f0c9..ad38dbb2 100644 --- a/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ResponseBodyUtils.java @@ -27,6 +27,8 @@ import awais.instagrabber.models.enums.RavenExpiringMediaType; import awais.instagrabber.models.enums.RavenMediaViewType; import awaisomereport.LogCollector; +import static awais.instagrabber.utils.Utils.settingsHelper; + public final class ResponseBodyUtils { private static final String TAG = "ResponseBodyUtils"; @@ -261,7 +263,10 @@ public final class ResponseBodyUtils { final String threadPrevCursor = data.has("prev_cursor") ? data.getString("prev_cursor") : null; final boolean threadHasOlder = data.getBoolean("has_older"); - final long unreadCount = data.optLong("read_state", 0); + + final String cookie = settingsHelper.getString(Constants.COOKIE); + final String userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); + final long unreadCount = data.getJSONObject("last_seen_at").getJSONObject(userIdFromCookie).getString("item_id").equals(threadNewestCursor) ? 0 : 1; final long lastActivityAt = data.optLong("last_activity_at"); final boolean named = data.optBoolean("named"); diff --git a/app/src/main/res/layout/dialog_post_layout_preferences.xml b/app/src/main/res/layout/dialog_post_layout_preferences.xml index 7bf0eefc..43f49b1d 100644 --- a/app/src/main/res/layout/dialog_post_layout_preferences.xml +++ b/app/src/main/res/layout/dialog_post_layout_preferences.xml @@ -21,11 +21,14 @@ GX~RMOi!<`f6i%Ugd;Kv3J{5mFGKIX(UnMPnQ~7`mLF9v+RnM zjY9X;Y9#7@+~?aoO~CE$6-OqW&&5BTA!~Dt#r~Vg9f36)B$G><(%ueCj`>2sZ&OWMDkOJB)6M7?9oYrR z_U!<~5N)^j`x*0OjM2zQ$$p!Y|IhZ9S0Q=0a=SeR$~j?Y$J3T%mG%Rxj<@^!l&r|J z0j-$}kS*$wOvG~oS@WCfqww8EjTTEFxFz>4VM!?$Gj3J%Zpn^rsY|FDG!uwqR`XKnL)Rr;U5O! zQpHFVjUpJ&2ydJoH*BkGMZ4@YGYIC%Kk(bIc9HX=uP>SKW5Sq!kX25lq|ucb`H$63FYTo!yJslr~vdQd4T*GCRAQNzUL%pmxp z9eA)pG4?0M&j~TuuAGD~CIQ%??WvZdIq`m!jQ;k0_#3`htt>a?Y~vX-mD%?h)aq|+ z=+FYw@gp5qu(zC^W}o1a!X_U!+o9UsNu^Aj4f6?pFGx`wev%cB^}h7h)^>gIGN5Gz z$ol;R1D;(61ECnV%`}l%vkIeg->NcyUU6NrcW5c^%vWr^|L`V4)!@Z=2hFWYmR9En zlDr42*Vf3hN^urMD#yQO+h|)w_@`${i+t49+8jhX@k#O)^1fIOFm)48{w$=(78s5saBn*qrQi(`otJAfpFsXAQRi8q!y^ z$Mz4zn8VX;_%{=0Nq1Yn0fN|+oC=5BNLqt;$NWiU-Xn~%;}mjt(b66XOvxr^WX4UK z(q#8x-e0^68{)1Vy>D_07dxsS45okZ$LU#Ce(OPQ?M?cD9;GRB|cT^d~=*{WgCq#}%*-uAB zYDWJ@gGEmMr4s)C`}vvX?4b1E-{>C}v2$N{d+Lic`+p822?u$>>fNY5e+QW0l%Lry zuX*q{5;+@%^8N#+MC$t2#kA5NwMLqWfhh&pOj&0WaFn>e3K|5^tNyt-jo|tdFTMV# zDxm}No0)*mjQ<57{3HJp-in+dkpqsIKUb$eH@ljMY{&!9kn(PPl0Y!+gh)X@`=mU( z>jZil;dWf|<6m*@XQL3VKY1aiqmVkJ@<9mqCl-;w`TViNGr>fpK} z`XBD-r0)JdO+ET20F?00>+$i3e-@$H@=vh);N3s3kN*jnc=k`>KQBBE)?O3&(ii-} zpXe7zU)J3I!NWh@zZp&@LkdriiM8}WDqVhmvW#+htJG^B{jp?lwHOwph4-Jz{|NtI z1i_zt4gWSfp}*>n(zt(91byk}ow(XRuc5ySlTt*KxV?&h4`{C$?^%1yFZQ<@&Vrb; z#O*3n@BXfcvk9Q5dHq%2)4vCZ+%ppkA*ZE(Z^qfgk9F9;DdLZLCyIAxpa0&@E-qeq zbkGF6_iszVNA?P?6Zofp3;28G|B*%T$Gph8)SSv!9P}(ePaNb#1>Xe~yB8DgG6-D5 zBGvee-!LWbD#|dORNNCH?t;ce9}4dd0;=KiY08ksV?u(17&f~Nl~Xmm6Dv%LPk59d zr_tCX$Zhz&*uk<8NdoXXrU*dkn)Gt@EI7k8$_o1M#uf zKO_BZATvt%XAz|FaX_fI3WSauD05y=5)xAgzx!-E9i|Hs2g@E3UWA2FZn z|M5Vo5&aRKM*r2Q`?*5?B%wR~B|QEsK12H}*97FR)&%*-00Q~X{p;sn@z`JSIQ&m% zIl(m(14q8xW>n!be^iP5WdK9(A60M=;h$1YLeZs=Jz_V!HUcRGXvY14{eK_+l=wde zfaX8s;?REp^8OnV#1r-Aw1sxSRN=5$t zgJuq>rtTaBHA|@F%I}^!7I!iYj6eB{WeyDmMGQIH@6dJnM6l8~Ls*|19+4THnv2z~ zc}wvtT*uC2Y?5RKtH)w1J#5x~(`JyViy)!K&9CFTTATKb5XgKq6;mf$VEGCx|Ku)b zqI1<>KK;$){tvHrUOd%5d_XcG?p$t}lr2Dk zx+cka4_yOvgjdFBVts;ss56GoPgZDPWKE&2WID!oH1ul7;=}uA9$WfImv{$@N@WM9 zN1);N#IWQqv|_bCw`4c%ZaOD0dY2}L6(%5X2Auu*-z+qv2@665=6_KYQ_L=?ry z8~B3E^Q$iqCC`OpvgzB*a3mg^pfAi6inM6Z{}fFolilf=zfi*Z=0nA5<*c}$U67Sgcp)E_+={gs z#>?tuaWb7G*UsMn`WGkl6^o?GABdVsQ{9ZsUf_IL`i_B`Tx#fbK{$QJNk*=xmzt(F zMy2>P^-Z*Y{jew2_RM$Nr;QFeCOkLAy8JYAx833}@=qG&r~QOsPt}cB+)nV+CB)gV zE{cFZ=E#(1uMVf}0UdQ&UrR?d+h4d%op702XquD<3BGu7Ysc43O`&<77Ks16sSPhW zy7u1nJ1me{c>@^y;rrRme%QDTN`=!`SaDPVVg(mNbkgn7XSDbmvsy;`YuL=6t*BfCtfzs zQ}h%tgjENX%9}<)HpE<&7jUf$QCc2Kh=Hgbb@U1f3yPtaE>dne5jy6=mgAivwb;@bx*>@7)7RwgVoSnFV{H2`_g6dVKj;hW z&&)Rxk{^G3X<_H~RvLvp0N|DocLIWaEOShJABhR3NVeBz4RFA_LQz(`*Q!A=1p-7l>3 z6#S{)qIv3aY^d%A1hHucD@KFrUKppS5FtB57{~1{RT9{8*koI1hl2*X|G&uduxGO?pMFI=XKOek&JI_JmhMBPkl6U zL7m*gGhBb?XV^u+6@JxTY_@}Y*7`mz5Z8+O$nkwLc)*XzgX!maN%~`-0 z2b)phMnB8yPQMqFu&WGD)FO{?(zzb+u|Vs|6J3tTrSjwt$9Bd7kJ?;~+PpV5P7GM6 z>EAYd*pw0gqLY-IzcBWA)WSicEqd9_O-At_cR2g~zr@sLj>q?Go99(iTUjn~& zc`uV4bv(0>4|~1BBmUC(H{kIpw+OoqOQG&HTT=ElLsK{?WjGeBY(@~jb}D5|LA<7r z!e^FVn37gM{AQe;1`8PNoBYCrB!xiSxiwCewZ-wevBcWSlO=h?myGRbU#r|0MWa~m zt-_WZhInVnbgBy|u12mq(i}Yu6MRq3f~xi=>xDLr3`!dRY_@E#NP9StPkEu(tbn zic1{HE(`rH?6SyyAEIQ)#WWA?hvlJHOb(;x^S*Z5K8Xwr3U&8;gpZP;hEH#6dJCy( zzPfeUr;B9FY*TRWP@4_%#u2J?~v7t!k&6cH$Xm$6MZZ;?1qw@TWjzD9u&pDzg-d-%g?nvzJJB;-uN?c4H*wakM z>rVx&&i=yqdDFPYl=^a4X=$!PO#IG9zxD0+KBIQUBu|y(&wdH#Tqm;VLvh$!QHfS~ z(SRYT#>g0lSt7aI`Dnt(fg{Xemk-T{fQaNDmPB#+gm+hxsntQe3*^L{z7->fMo3n} z#%-A{YCa)O@@GVlDk^))c6mp)9vm8rK;FPO60jrR2Z#KZMcLUrnxweY9w9%Yt#2jpN#hQ|oCCYDIix33O_c49$HRj_PmP$E4|FjB zXn82{tmqv2BXn|3Dm%Qa1RGcNXMylC=1I}?!?GaeS5@Qy@uJ5q5 zaLg=z1BmX62K9Q$#C)}1CJJp z+ccc!_6_00=QcIi_&ip}3zHrklrH&j80S{0HNuF&)|D|^rAC9=7> zJ+B;PacD9+sLG@;0u#VdBc1b#CT+RS^RDQ9zrq|SR3R#u2T<~;{py^O6Zmj3EMK4& zoCilkGU0IlqGSWRS;%E2Laaq^pMftD)nX$T?%T9u`tUfav)I?+TTo-h9)GN0VmK+z zts{;yS>90lq%d-YI|%8PBqa-B`VDw5u#F93eD*+-drib2gevu7^EV)YipL;dozue8 zxJx?W{RdF6DPcT=wVi2BBGEfSOpKw?w@;1vS?)RKC?DQ&ioIZAc@orw!Ty++n^`_# z!zHgLz5+Cl@S}0P{3Lh`=7pWlqE5c!(K|{OuS=B(9F97L(ZtqzxwyZ{V3bba_8Uu6 z8y^9!fO0!{%JQ}Xw0DRlEyKR?Hg!%vx919)UlWldG-k*(Zt;Al%MXS7%*~DDB=NL4BPC)q0gQmu5xw%`iogxvCiJha{(95VZih!P zy7>?_KqAK_wcUeVt?DXxgLCg;>>pBna7znT^&Nhus~3-z7kCaB^xzv&i1HHNJ{BlY zW4Ly8uD4)FnC5$xd*`C`B_C7zqBobEIYc_1@c|3=;pd91uMN9|fpqZD%hRlw-Gs?? zK|`^rt4eBmovdlkhh(#j>&)!svQI|Oah}G>?`DGb!U+_*-`l(--*ebcd>I~ZEyX{M zrpyrDC1YM3Ll0uqEZil(=1L_A;*;!V#Y%8`aKe6eb*OLCU^#B?^^{GPdIN(nMR|RMve1gD zz$dcZdRb2}_ajmICYh&Rua&!FrXRP^2i7iyn{-a4>^x2B*u@Jo2hokhyt=ntB#A-? zo(uR1w4Sj~<2Pt|M&DjzGHQvtL~>8N_?3MTcZe2G--)UGh3!J3s7#fr9Z1bc7a#ih zB((S`4IhqEnIBCHKa=ZAc?JU^y&2@kCczn;{2`YXZp?eAu6~=`()g9#g?yA@+_{*c z&F%6BkpOt5poqmO;j8uH9NNtpB0P;+{EXM3(<6ly?^H&aqT08Kz7R9eiF#drMEba zF=11PCdtzd=djRy+w)B*rj}!)EbS$blM&ZJF^0v#z{!*&*dQ1Do=-2^eVCZ*ilva<-O zORS_Eo+e(-`>Mk%q*oMf=HOEP$Sx%bN;HksOzq%`7c^-M9{&jYxgna91|jBIo##Oa z={qKTT&0fYm`wD1;jQSQse0CB3z0hceL-d5-&XtcI;z;tFxt)ylx!?g79eR8qE zO~$Q?Q!_7n?|^*xN%gV&`6Q0^q=g+!gZbn9FX#55rKq8vzO4|GaeTUM7W=tzX*tSx zCRM5~wO*EB3tb7HNO(7_`(}yF$OUY8+A>;1xGNBw zhjTJOAer7yFOvO!V&xYi3M1S@#M?ZWLTz^NOxQD^dqg|v(c2q74M14JwuYCoOo zJ#u`5^SIqS8wz^dmW5p|y^6JOhAM?FE6&|ww65z3H2=tTooiTbUa&!X6d05w)xjNE z{Pt`H%AV$!g`F3{vi zc+>Mr?D1NubmWz84_(>Fg_o7@I=Om74Rv7zFj-o-28Q4o)l5K92Yx!Wk?_+bJ-~LW zG?Y+EhFB&@Y!wZSx)}I(f_wO8>g;2Zt%WxTSryIteazA55pfrZ?6}T?D3;>VRFBgK zfOOfMguyaEg#U^-_WPPuCDzu=1utrGU>1&QUQWb$Tqt5*sC$5&4!wU`gBdlDbrP~} z6D(nOn0RUqntJs3hZem!qj6BM8ushYT+48gV`-VRG*+|AiK$Mo8c!&x#E72g*}3BY zLX`)Ymi$d@K951G&zTnNOZU8cmWI~~$O-1eRO+SuYW^vpOg^1%ipv))hGO^V?PH)h z!->q(05}HG4YoL4 zi7hr?9+V=^X5KAyIV#f&2!2DXaMOGa2wr1Nt_R6D zLJ9={wBEx}50B>q^)hsDym&WwFYfh}LO3NH_RAz=@#LyVioIC*SPvk5?E4bzZ?+Q} zN_?Rp`0him1*RHc&~u2=mgg9tsGZv6yD;KNTD1*z!#BE!R1aFy9_9+hp*6FX`8E?K zrk{Z;gj(eOkad^=PjxOG9u6fI5?&T}8xa?ntd8*mu#d|KsX?hvFf`KBULG88ILxc1 zP`f;}|G+{&=#bgy)uR)W%NpsI_5A&nrO4OHYr^XkY+2C!rhgy#QHksfdl}_XeBi5a z`^vQ`BKD0O!PKMBL@bVTb9sx@ouBJUp;-d$h#|#AlPSeD>U`7P49>i7o8#T^#4v{P zXdgjg2~ZK}dX%}(MLP$$${&dbTSEt-ieDwp2Gr4C-0OPx)B=4DzISAGbRYuZEYiS1u(dpx&*j$J1-7!w-2NM&!d};`5^htx76R>~hTmu3=HPBtzZs7ocorbX-I+3|u{~L|x0$EWj&E3tji1VlCLw)$>^ot;2 zQ#ah9k8>TzQsxGgEbP$FNbc2aAM;#sNlx8vYe^>txgYCRX#E{?3GGPN**K$u=?bV_ z4}H`oHqOc(G(gsbqbjkR@8c4B-jtOjHM%YAuri`Zb~41luzyvk=i#t7rjBIT@Bpl) z77E03dL*1PcOPOdPNGk|In$4qH_XHqEvJw9PLSGwJE~Q(?2SkT3g>|Q7zW8LfMVe%@7Dg$ye(FqcV=wjy3BNz zd=Ktq#${HrcVpO%pmf;V)TOHq*;8ymW}sRk-O#X-ICEyM3Ua^MThND+t!JKxp&`qmE7C0Edy#5yiIIdRc7KKW08a309vg0JXt&5s@1P}K6F2@Vm@w}_=ZowzO4eHbP0KE?w;%JBNw1=vo$DH`ONP)x?36Hc^J4w zQPOJ6MJy|7;9{IKL;h&5WmIKnT>MKjt%IJxNfN%LaB&qq-Hmy$Y@I?)SgGOjZIt3o z1Padr+0mEl9tKhB)g#jQ;#qf(0YacCpZOxFSLW@RxwmCMtHF@il~O(dg(B6^SA=o_ z)~oo$c@oc@?}<*P?8Np3C)i}%1EI;Z$qa(&n>gv&WQ|{FBDId!pJ5SeAjGSwzS~P| zN+WjHaagNE3LD1wG^j)?*Vx{HwYDnMZHm^ z?~qSP5Kj62OvT*wJX;V}ko;mW>KdLt;8`LAX5@u@p7YH$TU7w0DLCY+;1?t0W9f+P z(!1^lHb6LBj2GtdAi>Zm18`mTq-H`4Fv+yG+q+zs!lLzEy2BSancgCd<^;c`Ltsblx)u=g!#GjrUvMAu;UBNQCKsaF)~0(eFfdl zm6VU!kO#>Z?Sa2B419g1gg-J?%U$3V{3H0unz{2=QXpnv{94{Qe+ae%3eSi^+`aL+ z(|nTcg`BTiJk-wJEVKxviqmUafs04Kf`78aO|;&Zq{35UEoc6j1;r*um9QiKC)3Y+ z?%$IgQM3$Pn@nsj3> z>>wgrrhuMfefvkZF`1iXaQJf}d?U+OPFuw8B)-y$WN_0wc5ddRb~GR!5h8eB-Y&ZG z?KmV@rN=Qc%DnU@$|~k1jwB-uGo7*(xXw1X@ryCDVN>`-d4Q&v{7evAuDITX`HdhA z8%zc{0jVoE?Ho)HWb(@GpsQ+N$owWtMi5)q<(_DMw9NycN{e#ybifI#futeYOI3Fi@+1Q2(JF181fJu`?HrS|xWn+X zW@0$SEIkIgW8}EFzYATVI z6!YmL&FV3isIZvk>27?Ag_%c8W`I-W%%Yq8C3I`AXbq#fW}PlxAj(?o>THIQJ7i|} zmynT%I{OG{kGDs^n^ujKn!yIPa5O_aOB5AGxnb76*t`8{eq6nNwS=*HFKK}vO}qlj zu>e&6v}4x-6Wt7#I6Zsp>q+d+A1Q=kSamV}YnZibLI@zfHUYVSp#K!{wvt&qaR!yLO&)Yu|)N8u@`e4 zSIUHIz8qWLz>4zwrrm@m7LJG60Do%WmeKYI7bp+fp>>E0Y$M`LUiK1dE66#Jb?@Pnmn{;2fYrYZNt{?Ex77=j?XGN!&yQ zjpJEr!jmVPn=G@nF@=UZ{PDuwH3mM&ZU5xU&Tf$j2T#zd=;+&2R|Qd-X(d{-62k&N zkUXoe22(*_9{H!)gpI$vnLiQj>|x65RTjE(o$6?2poTTszTyU>juZdjenme6Tb*U~ z9Ej0#dEypovcsGv&82Fy$sqAk{_fYvP_n*ko23hM-vK^4e;&oG{bBvtD0$oE(~h+K zBoC9#xZ`v=kj>I15e;8i+RMrEx7jplQPP0rWUAaY;4rtM`Ut{sPj+;JS2Evl~$hPOL{Y`<^3 zcJNp#k=9->?JfFgQK?VwISW1PE2Ja1>Jk1v#)O6SN)8(%@=~-A1Xjkq+=O?r`FC=X zT@FMNxA?jXKVEMo(UQY?{qZJ6b2%ob!D7rknMfdsZkg<7#3ujISN}}`FaD4;HT>!l zBU5#n;#pCgU;yoxU7jMly<89D-a!0|7t~7^I*unGX;~65Yv(LueAUnT_0d;|($izD z@;O=+4YEtH{|PUoG@ZG~%!Q3SBI-Bb*GgASltlH@`_68CDm)yPd`0SXUXv8u=Qw=M zZ*)~qN*M)K*#q?v=|J0q2;$0DtRmdg3XTUw6jE!&_mIH4cb|iUud|2{4XG08?&&x4 z4rkL5T)fVU{*4Y=3}eVlzX9>2s>@IGegHQBAa(S`b4%nR1iIgMKDoDmQwvTWTmy8y zv^g>DNeDMh7)tP0A_t7|6qEQ`oG^*dPx>Qe;$*gA(bDh&(P`OeppNY6>GLc(&Md3- zMYaM);=_;*ZOL%!WG{*AshD*M^dR(X;BYW zyV?Rj7_D-()rB5YVz*dg^boF;2O`RQ{TqO4y7$3X=0aFSW%W@=8lUuypN_Z#?;@7Y zz{!jV@TGG;s?dr;l?8(+0gA|)JXzwQ>>Ec8GuxMhk165RG+NtHFfX=t(Q5=S1VV>- zk?QBP9xv3))z=(M{wV4O0CU)CK@~Kk|7`ZeJ85fDx(sLe^}uWiH<^z(hdG{XHICI6 z6U!_=-38l5MT`v+2se1U;Stqgz|qVJlsA&F`dBbWMk8gBqiT6}Mg}I2syQIJ89ASC zY_Q^?7I}dpUR0B8uy26+)4!!6Z>Q^`m1?d$aF+?zC0u z-X`vs5G!8Jtl{%Hm?2@7Cq#ovP5!5`!yt?cfj8xbH}3OZ%M(?Sg$E_0$%!Fp)l*1- zUD?_wR| z{kGwJt+A0O7&?q+h`qBr;woLXtx&-bwAtaG)GD|jB+P=spmjz6ggveix z3ONfTaE!adsbeR>C#LGW2mV52U?9>v#nxU_P*CV8V`TmE>PtbVk}V5YHYIAu(ZW$@ zne!>?_RGY%UKZ#Y4 zjwW4w5;dlK@G`50gkB4XS+nz+xjHqQA+Xhrqnzb5iaXgjq)L*kH`f}IxrgCbC+sMd z&k(Y(V0zJ)5j@W}jWz>Mqr$60fBA`-$Fc;VK%A~obOcN5GPuG$(ZK6q7IU6@i+Y;% zMu|9QOwy|8hB0DML`JUtQ(+c5`HXrGIf_;o)eW}_9}rK}c;?ZUSQ+8nO$m%_KRPj~ zFMTz2aj2&DzU1)UjT|~)IZO${e9dNIM-2M$eO7JTw~90*5J&Q5%oe*gDMI+X@rcyh z8uzC>^fE4Q@&gM^2^-H?v11jVdl`ks68l}imiXB)ERY|sv|4DetSpUAlSJE)!^Q_a z(aP_17MQGx6O~XbuhVuRL{?1yrO#45MNj89pbHjQK$z3HsdWY-_3PVfId`@c%9YNF z<^KpsF+vHK?|L?cAd2eR@c;3Ra%Sl^Z#uA{N43n9Dm475Y~tI2*TDdhcT8@`nD_}w znZhQm9nKe1I{+0U{nvn&gxvM)C@KXXQ*;Y!ly46dlx{set@QU>$8fI7AEqBh+~$RM zK%rI|k3QpHx{xbsWN9tjQS&xGc4Tt2yg^Q5e*+$zFAiTd_kG!k@$*@%awQX6LB5u& zW7gvGDB?>YL*AIVYG>Jxy-?Qn&L0jQ4jp2gRw-}M9=5Iz&>DLD_#nh`>z}_0J2~}@ z?$OL=sTyTg2>bj7c-)NFv3wF;Pp~k3W=ux1cRw--BqR87i~Y3*iG!Gx-C%|uzM1@%^)!_jJ>V_Kh$=O2=I8hYvOdg?*oSDF(&d; z=g;2&l$h3SDKo4#@v4%VMb`I0giDK${sUQ z8`*YKWv0YbD@%+@hHPKYc6&dGGc2Rq0w|JB2dMAKNTZs+d=^7)kYddo)>lDC%7o)F zKTv_HWiG#2f6n8npnWbC-Bm@Mty01n7c}xICK;wgvB3LQ*_4(hR#ZMdrspmD4`;}G z50u85*}@{EGNFyg!-|MyB++VjZ}=2hgIw&hkf|Soo|%4WpGwxtqO7o(C!?3ak*M-^ zTzjO!o`_r~V+EKms@znUT4jFW`(5Fd#}*3N>g*mjm_4XJNFK@C6@o|+N-D}QIn&`^ z>)eRjoXoyriFMh&k$JiV+;YM}lIyKw;u^)9fY!Z<#jA<%p#;>RsGz|C2{k$O3wWAM z^UkifX^QfzhH<(Jczp&sQ<-&s8gk91Xuj0*iaWMk1E&gmQx~D;n|w=p@>t8?gY%nP z@0Qj`a706l-o%$Q__rO@9|SYLZ~!E2%+b_9AiH*Pk0rlG}TsTkegyG*&|TL zUVlySvwLX5<{qg0C4SK@PKI8u+6;;AQn;WJMHdzof37Ki>xr=&GSVwwwVzM+UZD(8(nF`0Sc5hK*e-w%{t}+*6ExmgQ9y zHwgy;XjDv<&ilFM$9ytW6;|v!=0LBO1b(w zx<^nx;`ZaML<~HOKi1dpOFM&N8TRd}y#0Q@r-vAev@4A( z_ymHf7dd4DC5XL94%&@nU~<~dhW8)#F_Jxb;=D-De&A zFMF7z>L^%0kSI~3NzC`(fhB?x!fUyRStM%#g3f7Fsu5zz;~18HX<5>bJ@or z$I&>1Gr$!(Egkd0DncYYo}eI^O6fU2OirEam>tM)wVBF{G9K=kTx@&jHT)!tN|IO} z*+(8qILM=jnpQ4^G9L3dNeB!%a~#}WLKNc}=!;SxU{s`fAs>iZP4^y)s6Oudbo`wi zK-ev-K~FBiFNPA*JQG;pW&W$PhUWV9?z!B^y>JIUWj=Q&hLtj~YBcqHW>*I{sJYs@X1DCx96mkL=^VY7q9bNHAW zwRB5r%F=NX97j6AU`?HkxcCga!MejS`Zd5#{*G&wPn+zh2}=CYZ;`|ZCyc#Wd2dm1 z#m6f$mo-n#Blci5sH_U2>c}stxMKkjA0oZJ=RRpPEv$)DuN!e$oaeCen)}vj=8^jG$!7T`!q~exnPs;3HrRgOU#)f5su+X>ghFi7?Tn7*w-5~7hf={Q9 z-Ec`NoT8syr*qIrEInO*#lr&uf2Xg8TSxWMapcbrQV@&wxNdYnTry(E%igh4^`hr9 zyYAtT&lS;%)()#DN5$vH9Y=}Ei(aB-g?WZh%$^JfWn1a~oC_>tcyphGc@r;}ARw_? zBL0T4OR{{VLZ85t*Apu@B(?1c`oalyj7B)U?l(SRZg&{dBP*Jja3<-+C|YREb@%HS z4Ada0GNM@^d&mP&6Y(sI>D0)f2g}ZZbc4ssobf3)$w3OPnUcJm5MNdH@j@7EOj&1% zG*5$QoOoD76R#TF<#0cbnYg8verZo*R0IsW>9bswK~88mG}*uW^w)d#tDx7LB$|c< zJBoSUKeo1X3lb&p4DqWE<21C^q}{Y{G=<;bEOByw>$G(C_&f?j&LKf0?L`~W09*xD zM{u(NJsyBNh4wMkmb!s}wmz|5a7k>8&K|yP+%9}2UN9p%8e(ra7`jokC9n%f^oC0- z6hoCXr&1cF@l=UgGDsOSA5}Sf;>&69V87`p25^|`9|YgMSvpL0<_2T^AgF)0wqt|#? zKYvqttv33xYI&9AAO-O7th^%Fx5`0+D2bB3q(O_^ZA_SZ+@)ZFNERrY=D5dRk1XXw9%+%AIC^yny< zP7T?Fy)DobPx~_v3D59Tlc?;m52(sOf@aqCfqc|N$6wP&`LbzBsBX~TUHJ?6?l=#~ zT<%bQpv$&+gaP&JO?!+FhjxUj6Go;#i%H}$E_qos()4ck(B0rz@oyBd>T1|>g%5-R`@`%D z!eKX7X>*cgBJ}u;fkH|;cHORu%~GN69bazUv&qG>#rb*eyLA7J~J?3 zo^dbmShDF^)E2a_G;XDrrxE0l?wVY4J-C$1-sHd0SGOwM7x`!bjS z5xr%dfL*oWJWU@HXe{Uolqr{1u_;XMdGv+MG|9M`?y2PHmzyW)7{#_#N0(`|QSd&z zdC$?@g8jZNP6sp-)%1jph6q(J*3O9O1%*t_4#pRVG&q_WC;T^n1QeejjWLNlmlOvb z3jts*PDwJ4XYl1YqpllJe7X~oZSNH$wzFB3HAKYcCSfh7@&00@}}QPWd$fj zk#1-AJ(^$NEvg@SPkL{zeX_^YRQl9KdMS(K7eZT&4-qWR z{Q1BQ2F4wmuU*}q*h6*oj(ImkpIkU=D!B zDYF;Ohkk%9JOwB5^U%C>4$WVoei_*g49eHxSlR@K2SRgd+vS1Baf4#;K%6N*ud61E zz(Y+eh96ylbUaUB&@7TlBUtyq@a@4S1e0u%*kkFWU85%QHN<_GwJ1oA>&K??xRShq z+Vhr-IbnXvJ$U`&+LJJX``1gTaAv6{UqV=o)oJ58i%k4s2rpGT8xg!9Rjo>%3GaPZ zQXCi@F^3}UzzG;*A2ZF5^KBL7_f*$srmy-4CU`m2pyL~OHV1vwb`aRF;kg6w@EDq% z-wUKeoPSO|tNNvl3TD#J{!~MMdG=lv zVJph3>w`+8s$lSW$}xDs@tfs0ow#2l;evhrGMr}oePu>3IN>qERv~_xb(ZS!>%yEJ zCZTUeA5W}H*X&|VZNUMEF*sGF1@y?jmIXlpTvign%DeW%=2Al0MEY#sQv$(ah6e=_ z?XNf?r9c6ZK?@axW`r4E2j#|>X*QVj2>HS#au~_XC?1!Rl?4W;m562U85- ze@p;?vIz%~I4UKjgh6w|mhblm!hSLq0(LI7e;&CR(?rTV`+PCw62JkWJWcmyJ7gsq zD6ivOW0DT0MtLK55?-*&c3BR`pWdHdw!)!-e=N^@5JH$`B$uZKUK8GPgh&TmWncvD z&W$*8Ll+e|Zg%<20UP58Zo3#F0j;iVoCiS;1GTrV2n6`VfaNin1y>-|cdVkYy<|}t z1*Q7nQg6-vSaDl(h4d!=#@y*~I2hI#&4doBP%J+HA;#qe71|AR- zpuTZJ9^t=ypTfXVq3*0=2crJ~CKoMaijRDZj;cSK2Alz)zp(pc+CMlFTM+hU2|@*sz{zEA`~L#I@Upd$$xs| zbxk5Oxz&3woSYQS^6!OeQ;Lqbsh0ukl1tzB?}Y&{m6x-9pO@PKqb&j+7yv_^lWLxL zz=9GUbGff-485dKjwUAi_r#fqUEXW?#YNJpp!JVCC(>{vssNHbaqJe!g~%ZvKKOk! zL9JW8Pp3FXC~b*)>-Ubi3Q&nFXkTPwr>;YVqD+~4>wY`^Kw$tX2BhWhhy=9?PF6<~ zPP39#&Tm9r;DEGog%vf01$^LYBNdChh3ffnB&ERRJQyt*I)(SaJ$@q-KX75(MkTr2 zoqA*NC959Tccoj`T z04$dv5EET-Ktn3{$1#}~J@B@kF$|G}*kRati}B|ZB`$Ole3(Fj3u%mYq7E>Y)je{p zX|_bsS!Yz^k&P8VEnOH1^^|ooDXfW%w~2KT9DDBo@WD&f1^)NOP;l5IZZve^Y=*~R z20n1Zk@Oei0K)ob1aFzZ71lm8MG^zjrwD)&F1yYI`Q4WD;wRq(gB=?2nm00Yf+}Eu zsa!UI1Ge08`&i}>T`cuDoY--sW?IIi{{Xlobvjo>e;GIcZHYwj@Atqq%!hH+=v)5) zaxzc~bRL2G_{ygZTma>Ct~y~!kV;qk7${>+i@sWz|qAFi4z|VM$b-0dDZziZ^*Hra_?+#{lryNioU-4Mdt* zdn3ta@KFrn!lyRVw74OZCyBtA3-5rMCI}2UlhQGwIdUcgoZF+m0pPTt@=5lbSI*+V~c(0sXfg3j0sVA;W z@ia~`2&Gcv(-acYCzbJ7qAY^=BWS=^uya32IX$}wB>xvVg6_DiW41XU;$SD`U zJYpJ?1Wq(4))iFmG};0HtdjPfuJ}nv=^AYS5lu zJYxVSWF3>!skSR|j3R^22N^`how01$GsPQ2QuWQCNzfZkIfZvOlut86$}>IPMM6w<2Kkc^J%two{{TY>lm)2AxROMWamA~F_3qX*=p^d9BIlCm zCU8?CZ*%hRMEEi|3kA{4PLEe_j0IqWq2O}g`3@l`%@gTnJD0p`1WYgx?h4_%%Z2^S zXz6{UvCZB{Tgx*J!SWk0)MyQY5H!jC9T zmPQunA8a#HOWY8Buzf03^wRg zbPBPv{a_nlxtZmbTE%4f4O?EA_dRgT+WG|(FUCUECrO*!{wp4aY@HZ3h+WKm_|_AU zoBN-~i^CS$QEGN3yyGN5cveZ^pOYZy$qCW9uTRbn3Fwh8GwW$Z+y5T;qc|AeP5br%Q zOuXHO2hgyj`8W~760pfCHtMC>j?DutxkXx?O^LzH1>-|Tfw>ZDIO8P0&InL&3d7~D zVn_kjLGIuJTk(SRM@*T1?9L2?yakqG^1=@nouJ8#%^@W{R!7yx6E3N1k>EAPFheW{ zzxmE}s0UYIE8kh_B!}DXb(+O;h){qv8u>@IK@zbW4$KP!W`K3W?h0TmdmC3PFVWS^ z*VG0%p9YokV@ezAfa_UTNCtRSk7FBDQw2a$yFnhJ5zuwKEs$G~a|%$=54nqhNPQh2 zyTn;`p;aEiG0nJB*(I2VZd!HtawmwTrr=(L^~vmog@fg}^l`Q=HBE0ochjD23qqb# z+0#*oEJF9=j3kH_i`S#)D#+phELV21R`>-y9eX%E#G(9g#v}r%TPuqF`N$Gj*H^!u zVIGt_K5Q!6FT;NAA9*Wt7$t3LdxNI;*+X6`z;C4wJH!Q0@BmHpYE{J8?b z(dEJq7(*!?*`azQu8j2MGYYpY^pPRzjZ=`enuw9JnI?F#zzPsLtdafci&%=~z{(9c zw;RGsRBHh=V5|#(`NCjsf=|ncQz-&cT*@KHutL(zL(WC9qI-fvrG@n8B(xeB3+$ln zj*`g}gO%O>3>1_M7_^UQe=kos6crYQaE=ary2%aQ>jgy?Ks&;05!NxFbP?{mF(n5I zgqFNa;sHVt7(^-4q2g~z5|!E%{LW0C0NbH>7pthl6h|ye_zg~=nbk zM|=$t041J|{L|ARIh+H!MNZCP=idUASOR>q@>aOdej!VQ*x%naMN|@^d-pS$l^~U> zaw3Z;dFmCi8tIZk6lZ98{$p6DAudfk@9oA2Oo@dDv$i3GPvs8A`Tj7$ zf?5uyygx6gNy1XD10opfye^#GbA&;+%;QZF$BY5VJ@9O)$gC(eI0Qf*H^wpnod6uT z>!t>Wl$}=eAnTX7FxD511gvtVqa->Y#IynksebtJppeX|W~dnO=NtHeU=TX@>_TF1 z2APe5ik5wuu(T{jl|2&fWn?rPLKog}6^QLD=8`BFlw)}AAW<*`I`GNr?Ud)CuW~em zOVJyQfq%gi42?+yk7FfjLQWb((No(4OnU1phG)|P{A1IcBgRNGD@9==NG5v%{qc*Q z2uenysl{WHH5QYasZ|aodgL!42Tw!yoL~tSI!MFn8Lqou9AbAkT$TghA7Pg%w7R(H zM{I@XctD;8TrsPHHnbkNS!N!$7k&ClU_d_|7i-o72@yd+Y=hNVy(I-ru__{5H?Td4 zgC0d4%{{R^T8ov01EqBVcH3v+M=($>14u}Wa z01r3{l@thQ>d5JjwWU|i`Qke74s80Uk>u5vcs3O)EUfNuKv3Ho{rALfX4tibDYt5ejmm1i2L`R(}4cH}Feg5-=Y=Yw8xs#JLc(X?EmvC5ke%jdaTpr*0?}A-O9H z2bWwFcJG=9fbEj9LinziS}V32TvG`#!4FXIrm!TJig2-ry=$%-b~>tn^6KvB^7;NJsUi7i+w%m|J7eq?borv@@Wp^^sctdt~#gY=5#W?Q?9YqvG z9}Yl>BM#*nHZ^cPTzK*+7;Xe(L^|Jm1qUEN#H4q&CNct;U@hvnTm9e~J7iSr2u_aP z`LU$i1KcOla4|zH(b5wgSrr|!iSaMHj5TB&0!PZn!_ze~QvLCfL%*`U1-_kekR`rX z9#Kb(P#IguwpLLf@cM7loK~&7m2LOR(=ZF)6_x>q1HYV8Ap^XcYRFoGW4J1Ji~?;1 zFLJH1x4PrBz{r3%_W}O^bw-z}N~3)MmB^bFBoNTzt#-bEA$d?_r-V?ZqG=LI z{{SkYX=vKO(Tj@>ho!CCL>?;+t1 zfn`+RP2#afQ?uvz$KK|+dTsCTk|4ny&413h63Pt>mo*P;=k0|qr-|d|2uBy&uSflF zB9i!-1}I_NhrTP)i-d)I-`}^=F>PlIr?r#WJ-E&Zo_l4MUu-pX-7+T3_1~rxw(&AR zT-@ZPMGb_sc3FT-g$Oo=fG``r7cKtJpqZX;cnT~%m?ra~hls@WDm4Oxnv{sohDL-d zM2wQV)IaVH@b-pbQE;godgAssxsW!?r>X0e5`xNrYSGsnvchIPXC*9gA~~8Fdtj2X z2rxx&aZ}GRh&%#jnKc(A4=I|g_jVAT!^N`4f%b}eD?{G$ACW<+Qht3*0jaJG8Ccg@ z$n9A&;L_t3pk1eu@&e@|D0(Z5iHsQPCftbzh7>8033-2lTX%B%9tIq->mpZggYKQo z3v~q;$SZcZp*&>L8gGmQQY)>oViX;)V2NFO;oT~V2+BQW&6S_9S%-X`u5jPd?BL|03^deMy;UU5wI9WN)**X@%U7>zugST+latnx9?d%{zKf!u9u@oZuIMEhnfyrX&Z@M38m+dO4_& zC|3Pr^zg0EU<_kySh=sxHhT%3xxmeF(3j@!_ zERGVZaF9ZyYWhrLV4+N@Dz*c=8fRllcKq>c2+8&NrQp&^PEaBhQ9v*88EwV+;Lkuu6ew)onw+9Wy(m9AjlHu z5<)6*S8z7tk*}8wf%V8BTO4pXyb|*#wmF45{LkAKjT-LYlHmxOC$1CFWH^xL0AkIU zU^dB!yFgi{2f$)9tWit($o%7^H^gpFzdFO|kYu`jPF}B(g*g&bu;&~K?-gKzzkO>E z;)gnf`FagGa&RmpBSl?Dtzs>b88<{nsfbiqQ?WOwm(a*9%8Ju!SOmJK#!Lo0i(h6aoh;%45z-U? z0C2*hwKV{1dAn7vv;{O0jrzr~yo008{QOk1O?LThOn)0q7 zt%2o_rQiyHW`J;zL>2tjSlF;7G3Oits7iCfz=%wIsR)3RNt!lobbfKZT7E-GUCN%` z!dnWwsY&cYA06@`0p|b&^i6oil0sC_Kz{R%gxar1KD+h6R(jr4bi(y+^4t4hteQdv z^Q88~#n`|Se&=k^AQt-K!#)^6I{mT5;4b+bZgCA4n(>n-L^z~~w@-|psH_`|Q0<$9 z`e0a%<5n3kREL~mWemH7{n6>0Vid^&iLXqYFaa93_+rX)c%k!2{A9q$<3c3|u2GWc z!4K3OCpaVn(J>$E1vCtnsO|Ck;IoHX0S373;p;xEy%LBn7DLO^5u|slLeYHN-V6{y z6hkp0ub3E!U}Yyv{{SC+gtt9{qreLy^0G2isvh^3S3jeWa1*Gqp7jU5Y_v3lS6oto z5k+tq2Y`}!uZ&4eQTlkoj!LSh`HOvWP@7pD3`yL;=P4wJSE54uVh41#qREGwJzRSQ z)L9e@_Ky0|j8@1IA*mvNUu=mWAn-3oTVuc4KvD^VqRsWBhCVV={V4sH*r0(s!wvOy^|C~A4uMcW_}2)=F|=hFlrP@zJI>HIhm;c6!fIw5|~?y;qyNi9E$ zr!4Hm63QNZOghOyEKz>iz2pI%FGzamYJcMaLLEs8OkNY+#jymTjwPO?dpWc!#a>yd zOdv1YcrMtyGVqj_qaTcvI9N>#b)1l9tYF@=X~r3P0U0NQ5;K7}!H)5q2@k)8$FO(C za8R=zxdA+VBFLm<@f$I8GT(04p-aRpw3uewK5z%;=h@!#tj2bZbI`phyuCbuJ zLE1;yxL_b)b1-gjfiaD|V}DnH#{P0bfwHwPKkLRKPGojivKwfQitTZ#^({r;a47=S z(_xloI?~0|6Nu$YD>dGs!df-8J>cPx6_7}q)A1}(h%Id_*TL-=S&*1ZX?@DYCD9!e zk?wu5&;dzT0EwKCnE(!T`~LBaGU0-HVq9;cg%|43 zDx=_kYSf5;v=mJ7*T1^kR%TeZ5_q|<=MW(nqR1nBd7f~nsgY}?dOdJ8q#mi)*DD|! zMdcTM{{W^yiiEQrr@U7_F@g)=qWiy8T5GOoCCjOWgn?sh;g>??b9#{GFp{VWwlXtw z)I0wCVgTG|X$IT{A&rPSxD23nO!Y4wc)%ctDAUN4J;?TA3Cj^RFwx^%!(S;T;1?=c zC)+1!NXZz2RL4)8hfPIun7$?U#cw8DhtdMVIvz225#-6SA9Da#OaY_j9M%&8DHBu8 z1JS&ndZG+Lj8Kh{5x1wtLm+U{Q0?o4lvy3H#H7L+7!QaavSOxWX#-wP$IcpIk~T&5 z9_JENU>j49QcqmhtimQ|pJ>BZyc8NQCK#EXeSAGQ-+agoB*8D6gswlRVY zjH@ZBxXpLR?up~w2Ty?81B&9v6q4}XAp`i2!Z#Xj4oYBtVSO# z&M|@^?2_P?vcNY{etF5jiB@5oylfd0b?@pJvV|s48xE036J9Y10@YtQa!}zjdQKKK z=->rajNKML-A=Gh5K*3EvP`l71Iv%1d>3F9+B_HCR9dbK_v8k*cX_! z=c`R~lB1Q3==^o-cmOgQAGcV@Y7EbFbl?(U=^%sMkEyXTo0s#3YDA0ggS*dcHW9LE z*L-?~GE;~cg%=6<6x;zX#uY#az|ck7OBvY>WV+rVEBMKH)B|g$Wru7~WlKq1{BC2u zFwmJvl9uCbaEUKW0fjS=tZ$>y{{S4ZV38^t;^Qol#JVK&HU9uk6rlhCrn5am0w4u* z2_uFdH~|m^Jk3S(0{;M5#3?MLv+0T&sOgDs%VG}WzI)zS^#gUZ2L$5KfJCvcT%CXs zbW-?*?~^20q<|^b&toh`ML?7vPnNP!NJ*U1fY*(fRZJ6zZ1-mAI7GNWL3~UTfM*2J z0S?C!R@CIfj{D-9j5oY6zH6pfRtWbQ8WM3_YY2I)5V|m9yjI-dB6-Es$sEy*Riu5K zc3vE0AF2GY7-XbPY{v^Gz!=5}5el7k&O;Rrl4Mg0DOb`ngid!(R~a8d1Ev1}Z%mlM zNn&9hs9WO=5tPuFwduuG*IW%bV^!_caV(Ny5`MI_UJ4vTg7( zAp`Ic?qlpt;Yf(~>R|A65J^C5T%>ivf^-^EPj*-4<9IO|N+k&Qs!v_UNZA}#7xsGd zl;%*73VOZV#!%bMpeDM9wk(&>Q6&kcfcl!6i7*Jy0cxjnonpWSOM%`bc#KeiHyiw9 z&gOX3V**?KjJPA!QBNmmefwq1QQ88Y6KTX&D`!z4l$ShpdusupB%^mR#tcT6jBQK1 zz%J*YxgH1G2FOI9V~GwuF_t?GgnsKcHCb_+GxT$iO7WAFuY4IXj<|u4dgG|pPfXjK z8o*;6C=}P<7}WPJ>cMcGR6 zQbZCX_j_YZ7|1Nl8eP5(!-dd68I+Bz?8-tW3jwr^%o>RDz=i=y7VObqIJ!z%63Gv^ z$drQ%s%z6x-Hy1W#DPQ=;7L5kTyjQ9xwtcD_!#}K;~kSPK)`XAwA4>Ot}B4aq30RO zN(@_C_Wa^MS};Lh-Yaub4Xd+k$y?yTxD=QzjZ4LR^?sHTnU+1mN*wkp`F8^~*Ae8IlL6KN$lDgsGBiZ?rt%=%JBR z$FAY?=M|t(cnUM)ohO_tDvX55jUrIq?-=Vr1yK(Gp3%-;*%bMW&O3I&-?iMye+S4qwx<##{j#_^2nDCRjG7TGy#D}8kJo6^)<`g~f(<+0>T)SUcoIdk zuAX-u79f5UTzJS4Agxy3M36J)A(CFzjHz}%4!xceiN zE)Oul6g_P9!(aphrk>mT*~tdL?Hn#3B?cZO_RZok z1lf^}@)e0=B%?v<@$xa61w+UJe(@c$V8xZF03*w+4#px4y?d+QZ603w+dw{pqriWxTv zA<+^xptE&c6SU$H3Pc><*M!vCX;Kn}jK>^xjB4SRom(r!1K%!tRbcc*fH2E}MFG`( z83S%%CP|3dXKjJPV1bo`WH2b=G6evopxBz~eD}$Mf^LM9;u+1Pc)@cdbm(PhDdOOBzzkJvKKFciy!xp16goK_peZM+ip%Yw2;Y+=-4 zmhxhIPDEgngEV3KWv7a(`#p2HhI&gNl)^7SpT;y-rd^$hrrd!D4E7(4Pk&4ubJyzs z0ExnJgU$>jJ6pc^VkFX~eZOoNYDq*?!Rm!PV;+n`R1hQA?cto5z^oDI3r_E-$z}y~ z0$KYmaAL%>BN02_d%?`2KVfv9@%GJr!EvZMT^%)%c9t16!zbGo{{Y$^It3cYQ5>*d ziiln;<-!A)q~ljY+FY2}B)RtOh(X<-O$PObXGVjFO|3-~>#kb@3epob&-3e(V6rN; z!BeYWOcRa;^i&NV*sLgn;Rdm^A{qm)PWYWepe*m6+W7B`61hQhcLhDMAd9Dh3VQuO zDVGT%d}E2UYGzlN!~p`LqvItTe2*An0HX;8n?iT3;s|U|E5-x3qKO5HXhkQy;?su) z$QBflH?H_+WgNpp4pYa6C>M*a1kyiE-JX zRDg(SVs!9xhUJf#OoXIKIP_@A+xZb9R0PQgPoB2u1~SYinFmP@*l{S5=7moXh4h>{ z_D(Qwo|o&0uf*u0q1A!MOeED416>osp7{b^f-{R)dX#eu-A^&B3nC*3M@>iBjam(X z5*`nhBLZD=3JLS~#Q+#bDep4D01+dm=jS4c5+|-EWWJY>scd>Mjpaxh z%8V6w)DTIXL^!v+l}-uWtVjrehc7oAXTikvE}XciNC_do#Tm=!W9rDC-Q$p;kXtVvmAXW0iw2}lShlTJyGF&yFTMgc(wbi(&_#kM!G114DDJXS0S zieW4%zMk5~i9nPQ**<@qk?mfjhi2v`5^!8ZAxjRmez z*m=pZ`Wm;V-xvcnM;to(dR765s(HDC6WV>UWOXRN9SY+tgi^BJ_w9t`0U$hG_5Jrm zu3ECJ^~66VB8uSBCx$%cHB0^0T-1qH_m0+UF7HJ8NykM}@h*KiS z4FvK-lI5-aWPk|ipx!Hd4ph6Kg9DZ@lfH}@PnSG-H(ZituqHW{X zxsYUlUvUKtoR(tbgp$8JsXMXXt~&&c8EBxTle6uLa#2xaB3_tSp{h@ifSuhj^3)tM zy-I3Yz|Tl2FF+U7ZOr9Smt6+Ov2p2+aUdq853ZB;aiB_#5<6>?(=J-i8jx4Dj<_do zO5Hz@$V#&sy6F>mmbDrKAg=y3d2(QY3P>g$te=XqPO>AMnXG^_@rqh9CvHHP!HiN9 zg}4jT05Tp7ffByh>2G|Z0Q1f^YZyCd_p84KE#PAIF{+V*fk?S!^c-|{#07wzCsOGc z4CM)S$uskgTgAJ@kEnwsWGM;GBG`J*s2ww5BmxbBaLT_oZV{azFe3S2i0yGXCQfT$ z0X(D9NWn}Ic`5P*UvEIUNDT$6!pVabTH0p4)5aQAh^Hc9nCpHg0NyCLt9giV+KPr{ z!Xus|{o{xboq>z_$v91$h{Kf$^qgCJXEs#ZZ`V8@D^$^KX%n)CE zpbI*f&hFTd;S8O)n~f(+$8iEOn^HD=xvl8Ou~@`ot=DXD4}4KBN!7X3a-*CY)=LmL zFkTWdInD0#s}y*~D?)DOqC8^Gs-xW;P6l7w`Kh`GV>cA(8h zk|Rrs;GIZ%>zpL|f>X<<%=X2+xaLv=yCeY<+k}jCYAOI$w=rw30_p{_NhTTNZ>}>^ zpvxFa4##W_Tmot1pWb@ZEFe^HzLxGXNo8T-yj-Bz98D2|MzBD^d;8%bhSF{Ad}FFn z4BT-O86=eSmK5)NarBHq2~qEjL8nJfn22dNI)`pvFgHpan(O_>PlA#60i(ls@84&t zL1V2OY{P4Nkp#UXrQOaPQ*>hCFi)W@BEk4j61~h&)(wV9!HKDZdd_G8q_7&RsF%Iq z5p*spfSHK$VifI)P(pNJo+O#zV5cJyODA9%DNBuH%#{=Fv(G!gLMbpoDqAuQwWiK6 z0~lBeeS#aRnlbCfaM7OUV&2QdCl{C!K~$0~NvS!QE?6Z5GE*eO+1zEFF)c8++h_5t zAY3NxwfT$?)1!Ky5s;)sP)LNg+mjU`Fo>Ra3q9@SGKfrOA%wfL;~cK$avBS6S7Q8pe^&eo|9Nnu@Y8L zL%DUxj=0E1xa43E+}t68xu8K3z@eC^zOF6sD5DU991O7bMtXxG1t|hx9xV&Ph$Hp<xt(Wpfe?2Mhh>d4=WTTx}s#7)>Cp*-Qj`15_NGHF)9oJ z)FVul<2uu_0Dkqs8W5_R+trD8gdln*{NxxGjgOvl%S-r>i9GD*EdB>1l_Q2Ed#@#{ zHeovQNhOxF%Y~RJ344*FnhbW9P_(H|W5xNv14skX2PGZZX}oDl<&?D{2SRu5nF)9W zB%pEv6qCPPtg2{0D8#lRCdM!rgqQ=fObao@f)vX`09b*Gj)GtFgABF1s4J%MPlnq> zQjZAvGO?M&66Aj6((+gcfGUuP;$cqn)WBSX8A%~Y@+O$`#tn*8P0i1!$(m{C97Yt) z)y`9y?TS(XQk6{0SG{pN$g0T}#htuPZ?hcRkrRnnZa0J&bAoN6Ps4!Z^0fS^|fnY0SYYZC<)KJmlq?EaEA=3oHO&RSWhAyvo zGgjycOO)?@iai>dhsm%f$;mzmu9#-I=LkXrT&ivK(UH;<32(<*#F8k=a8!Gtj^8e_ ztRo#jWXcA@T1p}a81R^3#R`Zb4yNV2wu`k1JB05rGkEY|;Ihhx?>JwRjo`Q@sO;nO z=CKtOO+a-0>78e2Yx(`@fl0!W_8)$5(GrtlepqB7SrakeUNL5MHB{@*r`0+XsW7Jf zE%e2T2|{vDXO-Y1;i^NVnRuP=2F55A6-zTWR^W&fSUNUH*Nm6~UJ9i~A?2yw4S{1* z#z;9_7>YN`6)A|0w=D=;bZZW#@RFt_1M1_DC>oYFMT+(FfC)rOA}UgLk@vy-ilw)O zv0h{dygW#R0}d6`VD7MXT_bZG_Uj10Jesy{68iSaUqZ655}j1eq`}N73|c5P&ie7A zBquXKAqv40zQV4t;@CU-NnHHP3^I$|-IHMUp;>l2X*2qS|4HFK=hM3a-QAGFE~8c0sst-?76ISMG! zARI$1*pACJfmm}H^Nh1ucDX#WelW!O>6JRiwy@@aL0M)1Cr0GROzU7yB$gi1;Y)bb zDuI$TYH;3J2nn@>*P{wKB++a+lD(z$$)g;Ke8w3ixK^eQ*L+s-i@ulWGxL-r++xl? z`0ML=0aMr?d=c%5tZ!-L@skP|ma2%+^Qhp(uPGBGJdv^v!kyv=fGsf#^%8ky?~|Q{ zAX157L+Kuufy{9-z|#$?HDL~NV~DL|XyF2scSK|);{;5?O+%pIOfXrnPOX==639V- z3Au^mc@la8PiL=Rwc>ceKQ$o^b)#w`XwEfDk$4q7`TzVfVd5s` zF|aT?Iq|O%kwC%Oab`3>81Y1hpnoL9h+~j3zpZmu*JrUm^Ug69B0w3Kn0yuKghtkO zuuo+~d-lnKQUIVGjvJ?LaU;c=XlVI9Z~>x?8Yp$O^)d|>Y9UKsMNY36Gg5-c5{#-n z+TJC9qEB%WLr?+-YRG{LN(l|SCH9D9mnm=P3|kmpn5ETnf+Gc8Ef5$ALYiJF#tRdUtAWHLM^rT z$fB5|M4>xk6*^!7y|Q64v4#S1A1t|Aa6>yY zhyY#*pv|OXO0YCBh+^@iNXr8eNu#zM@MQH!Jybn%QEz;gMnbMge zdQUxH_b*BzT&U6G`NSy70!*mDd!MEh-G;UTvSY@mTnbR~Oug{}5)#Z!>;2;`5j^z3 zn)Cq38w5RXj6(8SNwMDXVKXwlJ7H2aH>b`ZkX^F+edD_r6(EGtoSwMLg23d}iTVx! zKmaSX|gSZnPsmB}A@ zh_i1@)RKgO!K+u`?`^=E3EAJPkqW-;QTIg zq!R_Zsrx)}k@isuMWH5DP`b%P?#$XW8EA~XnV*8!G*2~NACk7fh)q&-59OtWMRNFJk=tvLq;CxA8x zCsnER#wU5ICV^CvRTIv#aU>eU-o=`G_C^gN=SswZ!(G~(St5&yLQB|Sg%Rj1;7THh zH=GhBKDaWHU!0lL^uZuft}z$}CL(9q%hm6ckmpw11cc%OBy*R@hCmHM=>$lG)k!%N zknBOoI7^d)cNwxJd63l)QzZ5Ck4F9sXaH0>kUt02z?iDwz$dZWE#?L3jW)1oczQB= zV8M(54H#R-oFQ6p?#XqG9ZYx0i-$HZ$%@*(nP=m`_3h+(_V67agC2~c2$=2rShF;_ z%M&>~891&nPU8h@9O4hQ1RP*w1D;_6)(5ZFb0qQ9sa_0~KmrJ~B;4-N)K+R34njtO zQrAgi(;&iAZZ?Uj*xwjEGQ)5HK|=f`0Iq-tF4q{V zy-Cr*AR-LZ5h8UlQ`xQII7DD3QX;a1d@cri=!q?dSd=c|dSt?S3uO6!eQ>h{2T=g_ z1ODY}B{lEAj3dhNQDsMnE7!&oR9VDXzf6?OlX@Pvx4->^UA!Q<*W@Fk$6c>SFCCO8pS$ z=#H2WWYkUyyJvPX`X+HqoD{*yyqL(H7ms~?AvSD4|O(apo1JSvx z8CW^YL#^@q*CApiO*Q`jFr2ViM>XfKT$Tt4htGb$d~?bM#$Whk5R^haM2}D1eP*u} zusJ(+^*h};>#%JGq<%7)Dq0Qog7Hv5ThKZ2 zpPnGP=rsp7gNm#%uf4_U9^ssPIH7ChmRAQ*>jp%mq0na1qBzawX#O%JX1;Ps;G7aw zTF##n_r-us&0z^6UAfJ=<0-{d)L^F}36}-Co&Ny6UMegQx*fapeHz4@jRACJ4)ku! z)j1nR7O_SSGN6&$XMoA|wuml+fx+tV3_Ft}pgajB^f^apP7L639^>>fFvliw!wpyd zCo_>e6nqow^g98^!g=Zb@fLzi!uv-08fzA^y3Su2{{X~ff9yWwL63n?Bbz6Vm+3iN zK937%!D1wr1!PG;H|vRLhXZ)PrA@XyhB6JwC?NL0R;|ksC?!Jc?SYHg!azV$dWX1R zxZDC@J#mtenSh$}lx;aeV+cbb7Kt^ikQsW5UfEzosbPNj;EUwJ^3P^P5Q4RbayHHc z#1(wx-XE2K3P#>+`{M}!LIp9&Tgsg8aVN~;oRC#t*vK@bhH86nwo*FO^Wr6@Fu`4-pt4!HFY_J+PsM0rcoSTo3|3@#KRFk1io- z07utl{L)~R$RU_6&~AG<1R_L^L1+GAII);1{P)9HBOg5c!s8F8(hitWUr6vH2J7hda>a~_YYXVOa^`VA{&!<2WJ+Q}_;DeJf7&ba zMQ9Da$G$q(0SKEP>#qxGQR^}!=rXgaQg2CTU- z`7vrslP{MM16XJ}j+6fYfwmw~chC1t`p!jQvWxKic+ISFi`o9etN_wEgTePPrt(7) zE$%PD_rWR@LHZqge_C^fDpA^Y0bdwufGl_I*S8umv_NGbAgzT_-WG@qBoGy%h#J9E z1tS6a2L<@IZoRqFk(_fvj>EDddH$*2F^>b4>=NJ+0G2z2l#Mr`C=?5{#7?aM13U?s zh=_&A82O@p(sF)>d`>(L6S717{{S->HP}VZ*^nNhL)pj!qa%G%FjGc_CySHQ9!fSW zo(22PERmpu_=SI3ZvpBzGw&Xlgy^4BK*z2V5Z91)Hof0mJ!gA}N$wxkE61^lGwi+o zjiLi70R?CXrm(a?WdQ+OAPc{tULDLqpJDC&P;ydxEx|Y=Dwm>SLrHT$Kq1I|8zNFU zm7b)S4nog$pVoWDzLT?lp14vGwi*MKhua!LG{a(Wl6&X8Tj@JD>FfP&CNOKbnvc66 zJw%VOkPlW)`Yd3gjRd|bUrc!{P%wBG?-;U1l2PIn{bbZs7<7uqBTEuC+1O7^V7Im} zcLxHq;EewOS+5B*l?e7;*zTY?0V=!+C5L5W5*k+>$Ke=6hSkSm`A!?C4oFCkDi~nX zSl5qZ5F^-o{{U4S1di))`Xs#bsq{o~j~O-yqI-@m@M>CuPena(yd@)vTj)!O;H-98 z{b#&e=^8id>4hO0VWfCTeet9tY&Nee2ex~~zLBGTzMt11L3Pjf4SL2+V4}S~@5hcpyf39#XEytoz?BL)#nEECc0n|s(Fz_u6N1#ybe_RnY zE`y?JJmAomB3}+I8FC@;VkT-G2SCtx{{T8ngMx+^jC#MrAYxd!oTQaaYAo>Kf}U8T zM2AYiivU1VK_kHYWTQeSpvUzSAmE{e;~RX01sJSofdwp@80W?!66B@ga1ca>hnUAA z5C})PjV`rd1};OKuniL5^r7hqz>B0hbmt-5oJ>nQ3{Bwx!jP;93Ra^Mo(9rMAxWDv z{%ep)csx0}zyyV0o!&mYwknwkBz^Kty1F?m<;+eK_>%zd1!D&(LOLU_=p(7ZA|1?? z%2P6II80>@xd&6P5>SlBr&*0-wnP9*xxBC#KKSH7m1sRNc^2L5Ik-76Jsc*v5b;i_ z&Buhn_s0c@+(U5%<2FPhLO;-!tbi^B$=^Ny0C0zS%o^g2A|_(-5mpTkF^bwCaF25Z zP=Y{owOP1Om>$^8NQ6j7`k%M!fk-8O;|s6Y?CN1M$~*8r*s*fVH*f^2@tY#W_4&{hK?G~)OCMJ z<>;6W14}WHj5UOkl(fG7xZMb$6d-hAUl{IAc(+HILx)iLHbAmx_VDy`CYzUgnBFo! z_E4o>U#G%wO$2)*(WsxXj)X!8GsrTF?fnnecfcB>oo!)YaB zJ6cf*SROG#DMxDa{RAY0O^BHTh#rx*=_0&ftRT}w2z~u<90k7SPM^j#`Eq%Xy;440 zcEy(iOYYH-yY(9dyG~Et90o;)t$$O4cc3_!V-kqL^JZ!r#Ri1a77TVOJ7Mz*yo7?G z_{}pKs7z77oN<)(n9Rhp{Z0+ufZ}0{?-04OF+AaeAVMBa9p8LGU@wSfCVR3-jh6$t zMVSqUL#7EP|f>jvinCf91h)0n$C5MS| z)ePgQ2zNTpd-{@zvfac+a`Scc=`LEYIkmmDkIkliGF>5CdvOng$3h&Zc_x{WcWwTF zb1w-8BM;E+Bep*|$YE+JG$Y02_>hS&IQ(K3;{-7;W?5=NPjVD@%g6&&w=R!P_@@hJ&>!@1A1~*;K9d{*PKo=J+$>usaaxsUZYhk<&ai zV@RrAy5jUoqz7{3$<>=+9jfhm=ld8wm@?ZAX!?M&Ag2aU8kd*9{{XzyB0$y~V87n- zg)N7`0>)USp!on8#6T3%TLiz}zreSwe6B}L?(5I7#^FK1b|)Q(JAY*cWfe%!_kSGZ zk5)l2utC5G;#a$s^sKadK!=r;^sF#@$ftpVJrFZ1H1MK(k8>p4uDBZ$mHcu2iC5nx z#6yskIrB2|e5p(g))O@Wa{u&^N@F zKnKK;lz>)OB7MW@_0R!jau3)(xEjJspi|;l{{R7g{HC$?84WkPzaHZWiGc!bZ3j|L z{{YzyV8L)Q1J(TThz|ltmE_?F?mZJBfrJ(w;<4m17(GBC?js%t03L*~1Ixe@%&%3% z>`JOe!@K$C`xY<0L5P Date: Tue, 22 Dec 2020 17:36:18 -0500 Subject: [PATCH 050/101] close #436 --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9833375d..1d23024f 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,7 +26,7 @@ Favorites Discover Comments - Notifications + Activity Highlight: %s Check for updates at startup Download posts to username folders From 11a180d8f3d196450e61bea489fa563911cfdfca Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 17:53:15 -0500 Subject: [PATCH 051/101] all-contributors --- .all-contributorsrc | 27 +++++++++++++++++++++++++++ README.md | 19 +++++++++++-------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 1bc26b73..0354eb31 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -61,6 +61,15 @@ "translation" ] }, + { + "login": "CrazyMarvin", + "name": "CrazyMarvin", + "avatar_url": "https://avatars3.githubusercontent.com/u/15004217?v=4", + "profile": "https://github.com/CrazyMarvin", + "contributions": [ + "financial" + ] + }, { "login": "KevinNThomas", "name": "Kevin Thomas", @@ -112,6 +121,15 @@ "translation" ] }, + { + "login": "cizordj", + "name": "Cézar Augusto", + "avatar_url": "https://avatars2.githubusercontent.com/u/32869222?v=4", + "profile": "https://github.com/cizordj", + "contributions": [ + "translation" + ] + }, { "login": "farzadx", "name": "farzadx", @@ -148,6 +166,15 @@ "translation" ] }, + { + "login": "initdebugs", + "name": "Initdebugs", + "avatar_url": "https://avatars0.githubusercontent.com/u/75781464?v=4", + "profile": "https://github.com/initdebugs", + "contributions": [ + "translation" + ] + }, { "login": "kernoeb", "name": "kernoeb", diff --git a/README.md b/README.md index 3e0e5552..4f9b1493 100755 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE) [![GitHub stars](https://img.shields.io/github/stars/austinhuang0131/instagrabber.svg?style=social&label=Star)](https://GitHub.com/austinhuang0131/barinsta/stargazers/) -[![All Contributors](https://img.shields.io/badge/all_contributors-27-orange.svg)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-30-orange.svg)](#contributors) We're previously known as InstaGrabber. @@ -53,33 +53,36 @@ Prominent contributors are listed here in the [all-contributors](https://allcont
Anderson Mesquita

💻 🐛
AWAiS

💻
Stefan Najdovski

🎨 🌍 -
Kevin Thomas

💵 +
CrazyMarvin

💵 +
Kevin Thomas

💵
Shadowspear123

📝 🐛 🤔 💬
Airikr

🤔 💬
ALIN

🐛 🤔
Akrai

🤔 🌍 -
farzadx

🌍 -
Fatih Aydın

🌍 +
Cézar Augusto

🌍 +
farzadx

🌍 +
Fatih Aydın

🌍
fouze555

🌍
Galang23

🌍 +
Initdebugs

🌍
kernoeb

🌍 + +
Ten_Lego

🌍
MoaufmKlo

🌍
nalinalini

🌍 - -
peterge1998

🌍
PierreM0

🌍
RAMAR-RAR

🌍 + +
rohang02

🌍
retiolus

🌍
Ricardo

🐛 🌍 - -
rikishi0071

🌍
Still Hsu

🌍
wagnim

🌍 From 0ec9e02e2a244e92ea974e70c077f99f512c4919 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 18:03:23 -0500 Subject: [PATCH 052/101] apparently no caption id doesn't mean no caption --- .../java/awais/instagrabber/fragments/PostViewV2Fragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index 0a8dc7b2..6c5600e5 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -751,7 +751,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment { if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) return; bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }); - if (TextUtils.isEmpty(feedModel.getCaptionId())) + if (TextUtils.isEmpty(feedModel.getCaptionId()) || TextUtils.isEmpty(feedModel.getPostCaption())) binding.translateTitle.setVisibility(View.GONE); else binding.translateTitle.setOnClickListener(v -> { mediaService.translate(feedModel.getCaptionId(), "1", new ServiceCallback() { From e371f405a0cc7b67396092411171404f9403cec5 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Tue, 22 Dec 2020 22:06:57 -0500 Subject: [PATCH 053/101] New Crowdin updates (#435) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Indonesian) * New translations strings.xml (Persian) * New translations strings.xml (Hindi) * New translations strings.xml (Odia) * New translations strings.xml (Vietnamese) * New translations strings.xml (Catalan) * New translations strings.xml (Russian) * New translations strings.xml (Dutch) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Spanish) * New translations strings.xml (Czech) * New translations strings.xml (German) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Macedonian) * New translations strings.xml (Polish) * New translations strings.xml (Turkish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Kannada) * New translations strings.xml (Spanish) * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Indonesian) * New translations strings.xml (Persian) * New translations strings.xml (Hindi) * New translations strings.xml (Odia) * New translations strings.xml (Vietnamese) * New translations strings.xml (Catalan) * New translations strings.xml (Russian) * New translations strings.xml (Dutch) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Spanish) * New translations strings.xml (Czech) * New translations strings.xml (German) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Macedonian) * New translations strings.xml (Polish) * New translations strings.xml (Turkish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Kannada) * Update source file strings.xml * New translations strings.xml (Portuguese, Brazilian) * New translations strings.xml (Indonesian) * New translations strings.xml (Persian) * New translations strings.xml (Hindi) * New translations strings.xml (Vietnamese) * New translations strings.xml (Catalan) * New translations strings.xml (Russian) * New translations strings.xml (Dutch) * New translations strings.xml (French) * New translations strings.xml (Italian) * New translations strings.xml (Spanish) * New translations strings.xml (German) * New translations strings.xml (Chinese Traditional) * New translations strings.xml (Macedonian) * New translations strings.xml (Polish) * New translations strings.xml (Turkish) * New translations strings.xml (Chinese Simplified) * New translations strings.xml (Polish) * New translations strings.xml (Chinese Traditional) --- app/src/main/res/values-ca/strings.xml | 8 ++++---- app/src/main/res/values-cs/strings.xml | 8 ++++---- app/src/main/res/values-de/strings.xml | 8 ++++---- app/src/main/res/values-es/strings.xml | 10 +++++----- app/src/main/res/values-fa/strings.xml | 8 ++++---- app/src/main/res/values-fr/strings.xml | 8 ++++---- app/src/main/res/values-hi/strings.xml | 8 ++++---- app/src/main/res/values-in/strings.xml | 8 ++++---- app/src/main/res/values-it/strings.xml | 8 ++++---- app/src/main/res/values-kn/strings.xml | 8 ++++---- app/src/main/res/values-mk/strings.xml | 8 ++++---- app/src/main/res/values-nl/strings.xml | 8 ++++---- app/src/main/res/values-or/strings.xml | 8 ++++---- app/src/main/res/values-pl/strings.xml | 18 +++++++++--------- app/src/main/res/values-pt/strings.xml | 8 ++++---- app/src/main/res/values-ru/strings.xml | 8 ++++---- app/src/main/res/values-tr/strings.xml | 8 ++++---- app/src/main/res/values-vi/strings.xml | 8 ++++---- app/src/main/res/values-zh-rCN/strings.xml | 8 ++++---- app/src/main/res/values-zh-rTW/strings.xml | 6 +++--- 20 files changed, 85 insertions(+), 85 deletions(-) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index c15d09ff..684583b7 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -23,7 +23,7 @@ Preferits Descobrir Comentaris - Notificacions + Activitat Destaca: %s Cerca actualitzacions a l\'inici Descarrega les publicacions a carpetes de nom d\'usuari @@ -111,9 +111,9 @@ Deixar de restringir Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Mapa Exportar Importar diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 03ea8184..02108ed8 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -23,7 +23,7 @@ Oblíbené Objevit Komentáře - Upozornění + Activity Zvýraznit: %s Zkontrolovat aktualizace při spuštění Stáhnout příspěvky do složek s uživatelským jménem @@ -117,9 +117,9 @@ Unrestrict Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Map Export Import diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index dce72b45..d5949d4c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,7 +23,7 @@ Favoriten Entdecken Kommentare - Benachrichtigungen + Aktivität Hervorheben: %s Beim Start auf Aktualisierungen prüfen Beiträge in Benutzernamen-Ordner herunterladen @@ -111,9 +111,9 @@ Nicht mehr einschränken Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Karte Exportieren Importieren diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f75cb722..ed5b6289 100755 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -23,7 +23,7 @@ Favoritos Explorar Comentarios - Notificaciones + Actividad Resaltar: %s Buscar actualizaciones al inicio Descargar publicaciones en carpetas por nombre de usuario @@ -47,7 +47,7 @@ %s publicaciones
- %s Follower + %s seguidor %s seguidores %s seguidos @@ -111,9 +111,9 @@ Desrestringir Copiar biografía Traducir biografía - Siguiéndose mutuamente - Seguido por ti - Siguiéndote + Mutuo + Siguiendo + Seguidor Mapa Exportar Importar diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 6d6ca256..bdeb0901 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -23,7 +23,7 @@ علاقه مندی ها کاوش دیدگاه‌ها - آگهداد + فعالیت درخشندگی: %s بررسی بروزرسانی هنگام آغاز برنامه بارگیری پست ها در پوشه های به نام کاربر @@ -112,9 +112,9 @@ حذف محدودیت Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower نقشه صادر کردن وارد کردن diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index fb57dbbf..44f0fe1b 100755 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -23,7 +23,7 @@ Favoris Découvrir Commentaires - Notifications + Activité Temps forts: %s Rechercher les mises à jours au démarrage Télécharger les messages dans les dossiers des noms d\'utilisateurs @@ -111,9 +111,9 @@ Retirer des restrictions Copier la bio Traduire la bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Carte Exporter Importer diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index b8eb49e8..90159184 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -23,7 +23,7 @@ पसंदीदा खोजिए टिप्पणियाँ - सूचनाएँ + कार्यकलाप विशेषताएँ: %s खुलने पर अपडेट के लिए जाँच करें पोस्ट को ब्यबहारकारी के नाम पर किये फोल्डरस में रखें @@ -112,9 +112,9 @@ प्रतिबंध न लगाए Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower नक्शा निर्यात करें आयात करें diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index a2377e31..42a35496 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -23,7 +23,7 @@ Favorit Temukan Komentar - Pemberitahuan + Aktivitas Sorotan: %s Cek pembaruan saat memulai Unduh kiriman ke folder nama pengguna @@ -108,9 +108,9 @@ Hilangkan Batasan Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Peta Ekspor Impor diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 75e70a49..5a9ac571 100755 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -23,7 +23,7 @@ Preferiti Scopri Commenti - Notifiche + Attività In Evidenza: %s Verifica per aggiornamenti all\'avvio Scarica i post nelle cartelle del nome utente @@ -111,9 +111,9 @@ Rimuovi limitazione Copia bio Traduci bio - Si seguono a vicenda - Seguito da te - Ti segue + Mutual + Following + Follower Mappa Esporta Importa diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index b102c23d..36bae749 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -23,7 +23,7 @@ Favorites Discover Comments - Notifications + Activity Highlight: %s Check for updates at startup Download posts to username folders @@ -111,9 +111,9 @@ Unrestrict Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Map Export Import diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index a2b71cf2..d684a4c8 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -23,7 +23,7 @@ Омилени Откриј Коментари - Нотификации + Активности Важни Приказни: %s Провери за надоградба (ажурирање) при старт на апликацијата. Превземи постови во фолдерот со кориснички имиња @@ -111,9 +111,9 @@ Одограничи Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Мапа Експорт Импорт diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 020f38ec..0f3237f0 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -23,7 +23,7 @@ Favorieten Ontdekken Opmerkingen - Meldingen + Activiteit Hoogtepunt: %s Controleer op updates bij het opstarten Download berichten naar gebruikersnaam mappen @@ -111,9 +111,9 @@ De-restrict Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Kaart Exporteer Importeer diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index a313ff73..cfec7d5c 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -23,7 +23,7 @@ ପସନ୍ଦିତ ଖୋଜିବା ଟିପ୍ପଣୀ - ସୂଚନା + Activity ବିଶେଷତା: %s ଖୋଲିବା ସମୟରେ ଅପଡେଟ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ ଡାଉନଲୋଡ ପୋଷ୍ଟକୁ ବ୍ୟବହାରକାରୀଙ୍କ ନାମରେ ହୋଇଥିବା ସ୍ଥାନ ରେ ରଖ @@ -111,9 +111,9 @@ Unrestrict Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Map Export Import diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index cd55c037..222967be 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -23,7 +23,7 @@ Ulubione Odkrywaj Komentarze - Powiadomienia + Aktywność Wyróżnione: %s Sprawdź aktualizacje przy starcie Pobierz posty do folderów o nazwie użytkownika @@ -78,11 +78,11 @@ %d responses averaging %s %d responses averaging %s
- Your answer: %s + Twoja odpowiedź: %s Odpowiedz na relację Odpowiedź… Quiz - Slider + Suwak Już odpowiedziałeś! Wzmianki To konto jest prywatne @@ -115,11 +115,11 @@ Odblokuj Ogranicz Nieograniczone - Copy bio - Translate bio - Following each other - Followed by you - Following you + Skopiuj bio + Przetłumacz bio + Mutual + Following + Follower Mapa Eksportuj Importuj @@ -319,7 +319,7 @@ Pokaż widok siatki Wyłączenie animacji Poczekaj aż bieżące zadanie zostanie ukończone! - Depending on user counts, this can take a while to load. Please be patient. + W zależności od liczby użytkowników, może to chwilę potrwać. Prosimy o cierpliwość. Nie znaleziono posta! Nie znaleziono aplikacji, która otwiera adresy URL diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index d73b5cc8..e7b7eaae 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -23,7 +23,7 @@ Favoritos Descobrir Comentários - Notificações + Atividade Destaque: %s Verificar se há atualizações ao iniciar Baixar publicações para pastas com o nome de usuário @@ -111,9 +111,9 @@ Deixar de restringir Copiar bio Traduzir bio - Seguindo um ao outro - Seguido por você - Segue você + Mútuo + Seguindo + Seguidor Mapa Exportar Importar diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 73cf5724..5443852c 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -23,7 +23,7 @@ Избранное Подборка Комментарии - Уведомления + Активность События: %s Проверять наличие обновлений при запуске Скачать публикации в папки с именем пользователя @@ -117,9 +117,9 @@ Снять ограничение Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Карта Экспорт Импорт diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 758a4afa..dd1be3f2 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -23,7 +23,7 @@ Favoriler Keşfet Yorumlar - Bildirimler + Hareketler Öne çıkarılanlar: %s Güncellemeleri başlangıçta kontrol et İndirmeleri kullanıcı adından oluşan bir alt klasörün içine yap @@ -111,9 +111,9 @@ Kısıtlamayı Kaldır Copy bio Translate bio - Karşılıklı takip ediliyor - Takip ediliyor - Seni takip ediyor + Mutual + Following + Follower Harita Dışa aktar İçe aktar diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 74f92306..d1571b12 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -23,7 +23,7 @@ Yêu thích Khám phá Bình luận - Thông báo + Hoạt động Highlight: %s Kiểm tra cập nhật khi khởi động Tải bài viết xuống theo thư mục tên người dùng trong Downloads @@ -108,9 +108,9 @@ Bỏ giới hạn Copy bio Translate bio - Following each other - Followed by you - Following you + Mutual + Following + Follower Bản đồ Xuất Nhập diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 826baa67..3751700a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -23,7 +23,7 @@ 最爱 发现 留言 - 通知 + 动态 精彩:%s 启动时检查更新 下载帖子到用户名文件夹 @@ -108,9 +108,9 @@ 放开 复制简介 翻译简介 - 互相关注 - 您已关注 - 关注了您 + 相互关注 + 已关注 + 粉丝 地图 导出 导入 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index f6f9043a..32ed2ef3 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -23,7 +23,7 @@ 收藏 探索 評論 - 通知 + 動態 標記: %s 啟動時檢查更新 將貼文下載到用戶名資料夾 @@ -109,8 +109,8 @@ Copy bio Translate bio 正彼此追蹤 - 您已追蹤 - 關注了你 + 追蹤中 + 追蹤者 地圖 匯出 匯入 From 30fcf687ebfb10c5e3c14cc8a72692b6c0cdba47 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Wed, 23 Dec 2020 08:03:43 -0500 Subject: [PATCH 054/101] close #437 --- app/src/main/java/awais/instagrabber/utils/Constants.java | 4 ++-- app/src/main/res/values/themes.xml | 4 ++-- fastlane/metadata/android/en-US/changelogs/55.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 73120ddd..3f6a2f25 100644 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -56,9 +56,9 @@ public final class Constants { // spoof public static final String USER_AGENT = "Mozilla/5.0 (Linux; Android 8.1.0; motorola one Build/OPKS28.63-18-3; wv) " + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36 " + - "Instagram 166.1.0.42.245 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 256099205)"; + "Instagram 169.1.0.29.135 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 262886998)"; public static final String I_USER_AGENT = - "Instagram 166.1.0.42.245 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 256099205)"; + "Instagram 169.1.0.29.135 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 262886998)"; public static final String A_USER_AGENT = "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me"; // see https://github.com/dilame/instagram-private-api/blob/master/src/core/constants.ts public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index e1c4087a..7a8118e7 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -120,8 +120,8 @@