mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-12-23 13:26:59 +00:00
Merge branch 'bottombar_redesign' into bottombar_redesign
This commit is contained in:
commit
71e1b9c03c
@ -42,6 +42,24 @@
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Zopieux",
|
||||
"name": "Alexandre Macabies",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/81353?v=4",
|
||||
"profile": "https://github.com/Zopieux",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "MeLlamoPablo",
|
||||
"name": "Pablo Rodríguez",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/11708035?v=4",
|
||||
"profile": "https://github.com/MeLlamoPablo",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AwaisKing",
|
||||
"name": "AWAiS",
|
||||
@ -55,7 +73,7 @@
|
||||
"login": "snajdovski",
|
||||
"name": "Stefan Najdovski",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/42580385?v=4",
|
||||
"profile": "https://stefannajdovski.com/",
|
||||
"profile": "https://snajdovski.github.io",
|
||||
"contributions": [
|
||||
"design",
|
||||
"translation"
|
||||
@ -91,16 +109,6 @@
|
||||
"question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "alin-1",
|
||||
"name": "ALIN",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/13281020?v=4",
|
||||
"profile": "https://alin.atwebpages.com/",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "RickyM7",
|
||||
"name": "Ricardo",
|
||||
@ -131,6 +139,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "avtkal",
|
||||
"name": "avtkal",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/63205014?v=4",
|
||||
"profile": "https://github.com/avtkal",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cizordj",
|
||||
"name": "Cézar Augusto",
|
||||
@ -140,6 +157,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dimitrist19",
|
||||
"name": "Dimitris T",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/56406468?v=4",
|
||||
"profile": "https://github.com/dimitrist19",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "farzadx",
|
||||
"name": "farzadx",
|
||||
@ -194,6 +220,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "GenosseFlosse",
|
||||
"name": "GenosseFlosse",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/59205524?v=4",
|
||||
"profile": "https://github.com/GenosseFlosse",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kernoeb",
|
||||
"name": "kernoeb",
|
||||
@ -275,6 +310,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sandboiii",
|
||||
"name": "Alexey Peschany",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/17468894?v=4",
|
||||
"profile": "https://gitlab.com/sandboiii",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Still34",
|
||||
"name": "Still Hsu",
|
||||
@ -302,6 +346,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wokija",
|
||||
"name": "wokija",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/14982166?v=4",
|
||||
"profile": "https://github.com/wokija",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ysakamoto",
|
||||
"name": "ysakamoto",
|
||||
@ -310,6 +363,15 @@
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ZDVokoun",
|
||||
"name": "ZDVokoun",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/76393152?v=4",
|
||||
"profile": "https://github.com/ZDVokoun",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 6,
|
||||
|
11
.github/ISSUE_TEMPLATE/questions.md
vendored
11
.github/ISSUE_TEMPLATE/questions.md
vendored
@ -1,19 +1,16 @@
|
||||
---
|
||||
name: General questions & feedback
|
||||
about: These should be submitted to either one of our chatrooms, or r/barinsta on reddit.
|
||||
about: These should be submitted to either one of our chatrooms, the discussions, or r/barinsta on reddit.
|
||||
title: "[Q]"
|
||||
labels: question
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
STOP!!!
|
||||
STOP!!! STOP!!! STOP!!!
|
||||
|
||||
General questions & feedback should be submitted to
|
||||
* one of our chatrooms (see README.md), or
|
||||
* the GitHub discussions section, or
|
||||
* r/barinsta on reddit.
|
||||
|
||||
STOP!!!
|
||||
|
||||
-->
|
||||
STOP!!! STOP!!! STOP!!!
|
||||
|
@ -36,5 +36,10 @@
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="http://maven.geotoolkit.org/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://www.jitpack.io" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
47
README.md
47
README.md
@ -1,4 +1,4 @@
|
||||
**THERE ARE CURRENTLY NO OFFICIAL GOOGLE PLAY RELEASES. PLEASE REPORT ANY OCCURRENCES TO US.**
|
||||
### THERE ARE CURRENTLY NO OFFICIAL GOOGLE PLAY RELEASES. PLEASE REPORT ANY OCCURRENCES TO US.
|
||||
|
||||
<img src="./app/src/main/ic_launcher-round.png" alt="Barinsta logo" align="right" width="20%"/>
|
||||
|
||||
@ -9,10 +9,10 @@
|
||||
[![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-BADGE:START - Do not remove or modify this section -->
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-32-orange.svg)](#contributors)
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-39-orange.svg)](#contributors)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
We're previously known as InstaGrabber.
|
||||
Instagram client; previously known as InstaGrabber.
|
||||
|
||||
For documentation, visit [Barinsta.AustinHuang.me](https://barinsta.austinhuang.me).
|
||||
|
||||
@ -25,6 +25,8 @@ For documentation, visit [Barinsta.AustinHuang.me](https://barinsta.austinhuang.
|
||||
|
||||
Version status: ![F-Droid](https://img.shields.io/f-droid/v/me.austinhuang.instagrabber.svg) vs. ![GitHub](https://img.shields.io/github/release/austinhuang0131/barinsta.svg?logo=github)
|
||||
|
||||
## Screenshots
|
||||
|
||||
<a href="https://github.com/austinhuang0131/instagrabber/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg"><img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg" alt="Profile" width="15%"/></a>
|
||||
<a href="https://github.com/austinhuang0131/instagrabber/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg"><img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg" alt="Post" width="15%"/></a>
|
||||
<a href="https://github.com/austinhuang0131/instagrabber/blob/master/fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg"><img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg" alt="Comments" width="15%"/></a>
|
||||
@ -41,7 +43,7 @@ To speed up development, we need more hands on deck. If you are proficient in Ja
|
||||
* Use [GitHub issues](https://github.com/austinhuang0131/instagrabber/issues) when possible.
|
||||
* Email: [Barinsta@AustinHuang.me](mailto:barinsta@austinhuang.me?body=Please%20note%20that%20your%20email%20address%20and%20the%20entire%20content%20will%20be%20published%20onto%20GitHub%20issues.%20If%20you%20do%20not%20wish%20to%20do%20that%2C%20use%20other%20contact%20methods%20instead.) (Synced to GitHub issues)
|
||||
* Reddit: [![r/Barinsta](https://img.shields.io/reddit/subreddit-subscribers/Barinsta?style=social)](https://reddit.com/r/barinsta)
|
||||
* Chat (Bridged to each other): [![Matrix](https://img.shields.io/badge/Matrix-%23Barinsta:matrix.org-000000?logo=matrix)](https://matrix.to/#/#barinsta:matrix.org) [![Telegram](https://img.shields.io/badge/Telegram-@Grabber__App-2CA5E0?logo=telegram)](https://t.me/grabber_app) [![Discord](https://img.shields.io/badge/Discord-YtEDzN2-7289da?logo=discord&logoColor=white)](https://discord.gg/YtEDzN2) [![Gitter](https://img.shields.io/badge/Gitter-InstaGrabber/General-ed1965?logo=gitter)](https://gitter.im/instagrabber/general)
|
||||
* Chat (Bridged to each other): [![Matrix](https://img.shields.io/badge/Matrix-%23Barinsta:matrix.org-000000?logo=matrix)](https://matrix.to/#/#barinsta:matrix.org) [![Telegram](https://img.shields.io/badge/Telegram-@Barinsta__App-2CA5E0?logo=telegram)](https://t.me/barinsta_app) [![Discord](https://img.shields.io/badge/Discord-YtEDzN2-7289da?logo=discord&logoColor=white)](https://discord.gg/YtEDzN2)
|
||||
|
||||
## Contributors
|
||||
|
||||
@ -55,45 +57,54 @@ Prominent contributors are listed here in the [all-contributors](https://allcont
|
||||
<td align="center"><a href="https://austinhuang.me"><img src="https://avatars1.githubusercontent.com/u/16656689?s=100" width="100px;" alt=""/><br /><sub><b>Austin Huang</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/commits?author=austinhuang0131" title="Code">💻</a> <a href="https://github.com/austinhuang0131/barinsta/commits?author=austinhuang0131" title="Documentation">📖</a> <a href="#question-austinhuang0131" title="Answering Questions">💬</a> <a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a> <a href="#ideas-austinhuang0131" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/ammargitham"><img src="https://avatars0.githubusercontent.com/u/8017365?s=100" width="100px;" alt=""/><br /><sub><b>Ammar Githam</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/commits?author=ammargitham" title="Code">💻</a> <a href="#design-ammargitham" title="Design">🎨</a> <a href="#ideas-ammargitham" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-ammargitham" title="Maintenance">🚧</a> <a href="#question-ammargitham" title="Answering Questions">💬</a></td>
|
||||
<td align="center"><a href="https://github.com/andersonvom"><img src="https://avatars3.githubusercontent.com/u/69922?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anderson Mesquita</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/commits?author=andersonvom" title="Code">💻</a> <a href="https://github.com/austinhuang0131/barinsta/issues?q=author%3Aandersonvom" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/Zopieux"><img src="https://avatars.githubusercontent.com/u/81353?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandre Macabies</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/commits?author=Zopieux" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/MeLlamoPablo"><img src="https://avatars.githubusercontent.com/u/11708035?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pablo Rodríguez</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/commits?author=MeLlamoPablo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://rerolledgeek.blogspot.com/"><img src="https://avatars3.githubusercontent.com/u/5278488?s=100" width="100px;" alt=""/><br /><sub><b>AWAiS</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/commits?author=AwaisKing" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://stefannajdovski.com/"><img src="https://avatars2.githubusercontent.com/u/42580385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Najdovski</b></sub></a><br /><a href="#design-snajdovski" title="Design">🎨</a> <a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/CrazyMarvin"><img src="https://avatars3.githubusercontent.com/u/15004217?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CrazyMarvin</b></sub></a><br /><a href="#financial-CrazyMarvin" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://snajdovski.github.io"><img src="https://avatars2.githubusercontent.com/u/42580385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Najdovski</b></sub></a><br /><a href="#design-snajdovski" title="Design">🎨</a> <a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/CrazyMarvin"><img src="https://avatars3.githubusercontent.com/u/15004217?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CrazyMarvin</b></sub></a><br /><a href="#financial-CrazyMarvin" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="http://kevinthomas.dev"><img src="https://avatars2.githubusercontent.com/u/15370181?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Thomas</b></sub></a><br /><a href="#financial-KevinNThomas" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/Shadowspear123"><img src="https://avatars1.githubusercontent.com/u/50462281?s=100" width="100px;" alt=""/><br /><sub><b>Shadowspear123</b></sub></a><br /><a href="#blog-Shadowspear123" title="Blogposts">📝</a> <a href="https://github.com/austinhuang0131/barinsta/issues?q=author%3AShadowspear123" title="Bug reports">🐛</a> <a href="#ideas-Shadowspear123" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-Shadowspear123" title="Answering Questions">💬</a></td>
|
||||
<td align="center"><a href="https://alin.atwebpages.com/"><img src="https://avatars2.githubusercontent.com/u/13281020?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ALIN</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/issues?q=author%3Aalin-1" title="Bug reports">🐛</a> <a href="#ideas-alin-1" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/RickyM7"><img src="https://avatars3.githubusercontent.com/u/24703825?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ricardo</b></sub></a><br /><a href="https://github.com/austinhuang0131/barinsta/issues?q=author%3ARickyM7" title="Bug reports">🐛</a> <a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://airikr.me/"><img src="https://avatars0.githubusercontent.com/u/53869451?s=100" width="100px;" alt=""/><br /><sub><b>Airikr</b></sub></a><br /><a href="#ideas-e-edgren" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-e-edgren" title="Answering Questions">💬</a></td>
|
||||
<td align="center"><a href="https://github.com/Akrai"><img src="https://avatars1.githubusercontent.com/u/5624597?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akrai</b></sub></a><br /><a href="#ideas-Akrai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Akrai"><img src="https://avatars1.githubusercontent.com/u/5624597?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akrai</b></sub></a><br /><a href="#ideas-Akrai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/avtkal"><img src="https://avatars.githubusercontent.com/u/63205014?v=4?s=100" width="100px;" alt=""/><br /><sub><b>avtkal</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/cizordj"><img src="https://avatars2.githubusercontent.com/u/32869222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cézar Augusto</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/dimitrist19"><img src="https://avatars.githubusercontent.com/u/56406468?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dimitris T</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/farzadx"><img src="https://avatars2.githubusercontent.com/u/70059397?v=4?s=100" width="100px;" alt=""/><br /><sub><b>farzadx</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/faydin"><img src="https://avatars2.githubusercontent.com/u/22706676?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fatih Aydın</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/fouze555"><img src="https://avatars3.githubusercontent.com/u/71935341?v=4?s=100" width="100px;" alt=""/><br /><sub><b>fouze555</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/Galang23"><img src="https://avatars3.githubusercontent.com/u/13700948?s=100" width="100px;" alt=""/><br /><sub><b>Galang23</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/initdebugs"><img src="https://avatars0.githubusercontent.com/u/75781464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Initdebugs</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://janek.xyz/"><img src="https://avatars3.githubusercontent.com/u/8365659?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jakub Janek</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/GenosseFlosse"><img src="https://avatars.githubusercontent.com/u/59205524?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GenosseFlosse</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://becauseofprog.fr/"><img src="https://avatars3.githubusercontent.com/u/24623168?s=100" width="100px;" alt=""/><br /><sub><b>kernoeb</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://janek.xyz/"><img src="https://avatars3.githubusercontent.com/u/8365659?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jakub Janek</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://becauseofprog.fr/"><img src="https://avatars3.githubusercontent.com/u/24623168?s=100" width="100px;" alt=""/><br /><sub><b>kernoeb</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/MoaufmKlo"><img src="https://avatars1.githubusercontent.com/u/45636897?s=100" width="100px;" alt=""/><br /><sub><b>MoaufmKlo</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/nalinalini"><img src="https://avatars0.githubusercontent.com/u/65640431?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nalinalini</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/peterge1998"><img src="https://avatars2.githubusercontent.com/u/47355238?s=100" width="100px;" alt=""/><br /><sub><b>peterge1998</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/PierreM0"><img src="https://avatars3.githubusercontent.com/u/71077853?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PierreM0</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/RAMAR-RAR"><img src="https://avatars3.githubusercontent.com/u/47423745?s=100" width="100px;" alt=""/><br /><sub><b>RAMAR-RAR</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/rohang02"><img src="https://avatars3.githubusercontent.com/u/47921164?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rohang02</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/retiolus"><img src="https://avatars1.githubusercontent.com/u/65604466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>retiolus</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/rikishi0071"><img src="https://avatars3.githubusercontent.com/u/18183855?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rikishi0071</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://stillu.cc/"><img src="https://avatars2.githubusercontent.com/u/5843208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Still Hsu</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/Lego8486"><img src="https://avatars1.githubusercontent.com/u/47414485?s=100" width="100px;" alt=""/><br /><sub><b>Ten_Lego</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/retiolus"><img src="https://avatars1.githubusercontent.com/u/65604466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>retiolus</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/rikishi0071"><img src="https://avatars3.githubusercontent.com/u/18183855?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rikishi0071</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://gitlab.com/sandboiii"><img src="https://avatars.githubusercontent.com/u/17468894?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexey Peschany</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://stillu.cc/"><img src="https://avatars2.githubusercontent.com/u/5843208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Still Hsu</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/Lego8486"><img src="https://avatars1.githubusercontent.com/u/47414485?s=100" width="100px;" alt=""/><br /><sub><b>Ten_Lego</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/wagnim"><img src="https://avatars0.githubusercontent.com/u/30241419?s=100" width="100px;" alt=""/><br /><sub><b>wagnim</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/wokija"><img src="https://avatars.githubusercontent.com/u/14982166?v=4?s=100" width="100px;" alt=""/><br /><sub><b>wokija</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/ysakamoto"><img src="https://avatars3.githubusercontent.com/u/1331642?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ysakamoto</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/ZDVokoun"><img src="https://avatars.githubusercontent.com/u/76393152?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ZDVokoun</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -103,7 +114,7 @@ Prominent contributors are listed here in the [all-contributors](https://allcont
|
||||
|
||||
## License
|
||||
|
||||
This app's predecessor, InstaGrabber, is originally made by [@AwaisKing](https://github.com/AwaisKing) on [GitLab](https://gitlab.com/AwaisKing/instagrabber).
|
||||
This app's predecessor, InstaGrabber, was originally made by [@AwaisKing](https://github.com/AwaisKing) on [GitLab](https://gitlab.com/AwaisKing/instagrabber).
|
||||
|
||||
Barinsta
|
||||
Copyright (C) 2020-2021 Austin Huang <im@austinhuang.me>
|
||||
@ -122,7 +133,7 @@ This app's predecessor, InstaGrabber, is originally made by [@AwaisKing](https:/
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Logo by [Stefan Najdovski](https://stefannajdovski.com/). Used under license.
|
||||
Logo by [Stefan Najdovski](https://snajdovski.github.io/). Used under license.
|
||||
|
||||
[![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/austinhuang0131/instagrabber)](https://snyk.io/test/github/austinhuang0131/barinsta)
|
||||
[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/austinhuang0131/instagrabber)](https://lgtm.com/projects/g/austinhuang0131/barinsta)
|
||||
|
@ -10,8 +10,8 @@ android {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
|
||||
versionCode 57
|
||||
versionName '19.0.5'
|
||||
versionCode 60
|
||||
versionName '19.1.0'
|
||||
|
||||
multiDexEnabled true
|
||||
|
||||
@ -56,13 +56,13 @@ configurations.all {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
def appcompat_version = "1.2.0"
|
||||
def nav_version = '2.3.2'
|
||||
def exoplayer_version = '2.12.0'
|
||||
def nav_version = '2.3.4'
|
||||
def exoplayer_version = '2.13.2'
|
||||
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha04'
|
||||
implementation 'com.google.android.material:material:1.4.0-alpha01'
|
||||
|
||||
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
|
||||
implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version"
|
||||
@ -70,24 +70,36 @@ dependencies {
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$appcompat_version"
|
||||
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-beta01"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-beta02"
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
implementation "androidx.navigation:navigation-fragment:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui:$nav_version"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||
implementation "androidx.preference:preference:1.1.1"
|
||||
implementation "androidx.work:work-runtime:2.4.0"
|
||||
implementation "androidx.work:work-runtime:2.5.0"
|
||||
implementation 'androidx.palette:palette:1.0.0'
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
|
||||
implementation 'com.google.guava:guava:27.0.1-android'
|
||||
implementation 'com.google.guava:guava:27.1-jre'
|
||||
|
||||
// Room
|
||||
def room_version = "2.2.5"
|
||||
def room_version = "2.2.6"
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
implementation "androidx.room:room-guava:$room_version"
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
|
||||
// CameraX
|
||||
def camerax_version = "1.1.0-alpha02"
|
||||
implementation "androidx.camera:camera-camera2:$camerax_version"
|
||||
implementation "androidx.camera:camera-lifecycle:$camerax_version"
|
||||
implementation "androidx.camera:camera-view:1.0.0-alpha22"
|
||||
|
||||
// EmojiCompat
|
||||
def emoji_compat_version = "1.1.0"
|
||||
implementation "androidx.emoji:emoji:$emoji_compat_version"
|
||||
implementation "androidx.emoji:emoji-appcompat:$emoji_compat_version"
|
||||
|
||||
implementation 'me.austinhuang:AutoLinkTextViewV2:-SNAPSHOT'
|
||||
|
||||
implementation 'com.facebook.fresco:fresco:2.3.0'
|
||||
@ -99,8 +111,11 @@ dependencies {
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
|
||||
implementation 'org.apache.commons:commons-imaging:1.0-alpha2'
|
||||
implementation 'com.github.ammargitham:uCrop:2.3-native-beta-2'
|
||||
implementation 'com.github.ammargitham:android-gpuimage:2.1.1-beta4'
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
|
||||
}
|
||||
|
5
app/proguard-rules.pro
vendored
5
app/proguard-rules.pro
vendored
@ -23,6 +23,7 @@
|
||||
#noinspection ShrinkerUnresolvedReference
|
||||
#-keep class !com.google.android.exoplayer2.**, ** { *; }
|
||||
|
||||
#-keep class !awais.instagrabber.** { *; }
|
||||
-dontobfuscate
|
||||
|
||||
-dontobfuscate
|
||||
# prevent shrinking retrofit response entities
|
||||
-keep class awais.instagrabber.repositories.responses.** { *; }
|
161
app/schemas/awais.instagrabber.db.AppDatabase/5.json
Normal file
161
app/schemas/awais.instagrabber.db.AppDatabase/5.json
Normal file
@ -0,0 +1,161 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 5,
|
||||
"identityHash": "0b38e12b76bb081ec837191c5ef5b54e",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "accounts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uid` TEXT, `username` TEXT, `cookie` TEXT, `full_name` TEXT, `profile_pic` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uid",
|
||||
"columnName": "uid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "username",
|
||||
"columnName": "username",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "cookie",
|
||||
"columnName": "cookie",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "fullName",
|
||||
"columnName": "full_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "profilePic",
|
||||
"columnName": "profile_pic",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "favorites",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query_text` TEXT, `type` TEXT, `display_name` TEXT, `pic_url` TEXT, `date_added` INTEGER)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "query",
|
||||
"columnName": "query_text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "displayName",
|
||||
"columnName": "display_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "picUrl",
|
||||
"columnName": "pic_url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "dateAdded",
|
||||
"columnName": "date_added",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "dm_last_notified",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thread_id` TEXT, `last_notified_msg_ts` INTEGER, `last_notified_at` INTEGER)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "threadId",
|
||||
"columnName": "thread_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastNotifiedMsgTs",
|
||||
"columnName": "last_notified_msg_ts",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastNotifiedAt",
|
||||
"columnName": "last_notified_at",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_dm_last_notified_thread_id",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"thread_id"
|
||||
],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_dm_last_notified_thread_id` ON `${TABLE_NAME}` (`thread_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0b38e12b76bb081ec837191c5ef5b54e')"
|
||||
]
|
||||
}
|
||||
}
|
@ -6,6 +6,13 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<!--<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />-->
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.any"
|
||||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:name=".InstaGrabberApplication"
|
||||
@ -15,13 +22,13 @@
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.Light.White"
|
||||
android:theme="@style/AppTheme.Launcher"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=".Main"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@ -30,8 +37,8 @@
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<!--<action android:name="android.intent.action.SEARCH" />-->
|
||||
<!--<action android:name="android.intent.action.WEB_SEARCH" />-->
|
||||
<!-- <action android:name="android.intent.action.SEARCH" /> -->
|
||||
<!-- <action android:name="android.intent.action.WEB_SEARCH" /> -->
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
@ -114,6 +121,15 @@
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.CameraActivity"
|
||||
android:label="Camera"
|
||||
android:parentActivityName=".activities.MainActivity"
|
||||
android:theme="@style/AppTheme.Light.White">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
@ -131,5 +147,27 @@
|
||||
<service
|
||||
android:name=".services.DeleteImageIntentService"
|
||||
android:exported="false" />
|
||||
<service
|
||||
android:name=".services.DMSyncService"
|
||||
android:exported="false" />
|
||||
|
||||
<receiver
|
||||
android:name=".services.DMSyncAlarmReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
<!--<receiver android:name=".services.BootCompletedReceiver" >-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.BOOT_COMPLETED" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!--</receiver>-->
|
||||
|
||||
<uses-library
|
||||
android:name="org.apache.http.legacy"
|
||||
android:required="false" />
|
||||
|
||||
<meta-data
|
||||
android:name="fontProviderRequests"
|
||||
android:value="Noto Color Emoji Compat" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -3,6 +3,7 @@ package awais.instagrabber;
|
||||
import android.app.Application;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
@ -15,13 +16,16 @@ import java.util.UUID;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.LocaleUtils;
|
||||
import awais.instagrabber.utils.SettingsHelper;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awaisomereport.CrashReporter;
|
||||
import awaisomereport.LogCollector;
|
||||
//import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.CookieUtils.NET_COOKIE_MANAGER;
|
||||
import static awais.instagrabber.utils.Utils.applicationHandler;
|
||||
import static awais.instagrabber.utils.Utils.cacheDir;
|
||||
import static awais.instagrabber.utils.Utils.clipboardManager;
|
||||
import static awais.instagrabber.utils.Utils.datetimeParser;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class InstaGrabberApplication extends Application {
|
||||
@ -52,13 +56,21 @@ public final class InstaGrabberApplication extends Application {
|
||||
}
|
||||
|
||||
if (!BuildConfig.DEBUG) CrashReporter.get(this).start();
|
||||
logCollector = new LogCollector(this);
|
||||
// logCollector = new LogCollector(this);
|
||||
|
||||
CookieHandler.setDefault(NET_COOKIE_MANAGER);
|
||||
|
||||
if (settingsHelper == null)
|
||||
settingsHelper = new SettingsHelper(this);
|
||||
|
||||
if (applicationHandler == null) {
|
||||
applicationHandler = new Handler(getApplicationContext().getMainLooper());
|
||||
}
|
||||
|
||||
if (cacheDir == null) {
|
||||
cacheDir = getCacheDir().getAbsolutePath();
|
||||
}
|
||||
|
||||
LocaleUtils.setLocale(getBaseContext());
|
||||
|
||||
if (clipboardManager == null)
|
||||
@ -70,6 +82,8 @@ public final class InstaGrabberApplication extends Application {
|
||||
settingsHelper.getString(Constants.CUSTOM_DATE_TIME_FORMAT) :
|
||||
settingsHelper.getString(Constants.DATE_TIME_FORMAT), LocaleUtils.getCurrentLocale());
|
||||
|
||||
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
|
||||
if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) {
|
||||
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,276 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.camera.core.CameraInfoUnavailableException;
|
||||
import androidx.camera.core.CameraSelector;
|
||||
import androidx.camera.core.ImageCapture;
|
||||
import androidx.camera.core.ImageCaptureException;
|
||||
import androidx.camera.core.Preview;
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import awais.instagrabber.databinding.ActivityCameraBinding;
|
||||
import awais.instagrabber.utils.DirectoryUtils;
|
||||
import awais.instagrabber.utils.PermissionUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class CameraActivity extends BaseLanguageActivity {
|
||||
private static final String TAG = CameraActivity.class.getSimpleName();
|
||||
private static final int CAMERA_REQUEST_CODE = 100;
|
||||
private static final String FILE_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS";
|
||||
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(FILE_FORMAT, Locale.US);
|
||||
|
||||
private ActivityCameraBinding binding;
|
||||
private ImageCapture imageCapture;
|
||||
private File outputDirectory;
|
||||
private ExecutorService cameraExecutor;
|
||||
private int displayId = -1;
|
||||
|
||||
private final DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener() {
|
||||
@Override
|
||||
public void onDisplayAdded(final int displayId) {}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(final int displayId) {}
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(final int displayId) {
|
||||
if (displayId == CameraActivity.this.displayId) {
|
||||
imageCapture.setTargetRotation(binding.getRoot().getDisplay().getRotation());
|
||||
}
|
||||
}
|
||||
};
|
||||
private DisplayManager displayManager;
|
||||
private ProcessCameraProvider cameraProvider;
|
||||
private int lensFacing;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityCameraBinding.inflate(LayoutInflater.from(getBaseContext()));
|
||||
setContentView(binding.getRoot());
|
||||
Utils.transparentStatusBar(this, true, false);
|
||||
displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
|
||||
outputDirectory = DirectoryUtils.getOutputMediaDirectory(this, "Camera");
|
||||
cameraExecutor = Executors.newSingleThreadExecutor();
|
||||
displayManager.registerDisplayListener(displayListener, null);
|
||||
binding.viewFinder.post(() -> {
|
||||
displayId = binding.viewFinder.getDisplay().getDisplayId();
|
||||
updateUi();
|
||||
checkPermissionsAndSetupCamera();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// Make sure that all permissions are still present, since the
|
||||
// user could have removed them while the app was in paused state.
|
||||
if (!PermissionUtils.hasCameraPerms(this)) {
|
||||
PermissionUtils.requestCameraPerms(this, CAMERA_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
// Redraw the camera UI controls
|
||||
updateUi();
|
||||
|
||||
// Enable or disable switching between cameras
|
||||
updateCameraSwitchButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Utils.transparentStatusBar(this, false, false);
|
||||
cameraExecutor.shutdown();
|
||||
displayManager.unregisterDisplayListener(displayListener);
|
||||
}
|
||||
|
||||
private void updateUi() {
|
||||
binding.cameraCaptureButton.setOnClickListener(v -> takePhoto());
|
||||
// Disable the button until the camera is set up
|
||||
binding.switchCamera.setEnabled(false);
|
||||
// Listener for button used to switch cameras. Only called if the button is enabled
|
||||
binding.switchCamera.setOnClickListener(v -> {
|
||||
lensFacing = CameraSelector.LENS_FACING_FRONT == lensFacing ? CameraSelector.LENS_FACING_BACK
|
||||
: CameraSelector.LENS_FACING_FRONT;
|
||||
// Re-bind use cases to update selected camera
|
||||
bindCameraUseCases();
|
||||
});
|
||||
binding.close.setOnClickListener(v -> {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
private void checkPermissionsAndSetupCamera() {
|
||||
if (PermissionUtils.hasCameraPerms(this)) {
|
||||
setupCamera();
|
||||
return;
|
||||
}
|
||||
PermissionUtils.requestCameraPerms(this, CAMERA_REQUEST_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
|
||||
if (requestCode == CAMERA_REQUEST_CODE) {
|
||||
if (PermissionUtils.hasCameraPerms(this)) {
|
||||
setupCamera();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupCamera() {
|
||||
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
|
||||
cameraProviderFuture.addListener(() -> {
|
||||
try {
|
||||
cameraProvider = cameraProviderFuture.get();
|
||||
// Select lensFacing depending on the available cameras
|
||||
lensFacing = -1;
|
||||
if (hasBackCamera()) {
|
||||
lensFacing = CameraSelector.LENS_FACING_BACK;
|
||||
} else if (hasFrontCamera()) {
|
||||
lensFacing = CameraSelector.LENS_FACING_FRONT;
|
||||
}
|
||||
if (lensFacing == -1) {
|
||||
throw new IllegalStateException("Back and front camera are unavailable");
|
||||
}
|
||||
// Enable or disable switching between cameras
|
||||
updateCameraSwitchButton();
|
||||
// Build and bind the camera use cases
|
||||
bindCameraUseCases();
|
||||
} catch (ExecutionException | InterruptedException | CameraInfoUnavailableException e) {
|
||||
Log.e(TAG, "setupCamera: ", e);
|
||||
}
|
||||
|
||||
}, ContextCompat.getMainExecutor(this));
|
||||
}
|
||||
|
||||
private void bindCameraUseCases() {
|
||||
final int rotation = binding.viewFinder.getDisplay().getRotation();
|
||||
|
||||
// CameraSelector
|
||||
final CameraSelector cameraSelector = new CameraSelector.Builder()
|
||||
.requireLensFacing(lensFacing)
|
||||
.build();
|
||||
|
||||
// Preview
|
||||
final Preview preview = new Preview.Builder()
|
||||
// Set initial target rotation
|
||||
.setTargetRotation(rotation)
|
||||
.build();
|
||||
|
||||
// ImageCapture
|
||||
imageCapture = new ImageCapture.Builder()
|
||||
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
||||
// Set initial target rotation, we will have to call this again if rotation changes
|
||||
// during the lifecycle of this use case
|
||||
.setTargetRotation(rotation)
|
||||
.build();
|
||||
|
||||
cameraProvider.unbindAll();
|
||||
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);
|
||||
|
||||
preview.setSurfaceProvider(binding.viewFinder.getSurfaceProvider());
|
||||
}
|
||||
|
||||
private void takePhoto() {
|
||||
if (imageCapture == null) return;
|
||||
final File photoFile = new File(outputDirectory, SIMPLE_DATE_FORMAT.format(System.currentTimeMillis()) + ".jpg");
|
||||
final ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();
|
||||
imageCapture.takePicture(
|
||||
outputFileOptions,
|
||||
cameraExecutor,
|
||||
new ImageCapture.OnImageSavedCallback() {
|
||||
@Override
|
||||
public void onImageSaved(@NonNull final ImageCapture.OutputFileResults outputFileResults) {
|
||||
final Uri uri = Uri.fromFile(photoFile);
|
||||
//noinspection UnstableApiUsage
|
||||
final String mimeType = MimeTypeMap.getSingleton()
|
||||
.getMimeTypeFromExtension(Files.getFileExtension(photoFile.getName()));
|
||||
MediaScannerConnection.scanFile(
|
||||
CameraActivity.this,
|
||||
new String[]{photoFile.getAbsolutePath()},
|
||||
new String[]{mimeType},
|
||||
(path, uri1) -> {
|
||||
Log.d(TAG, "onImageSaved: scan complete");
|
||||
final Intent intent = new Intent();
|
||||
intent.setData(uri1);
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
});
|
||||
Log.d(TAG, "onImageSaved: " + uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull final ImageCaptureException exception) {
|
||||
Log.e(TAG, "onError: ", exception);
|
||||
}
|
||||
}
|
||||
);
|
||||
// We can only change the foreground Drawable using API level 23+ API
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// // Display flash animation to indicate that photo was captured
|
||||
// final ConstraintLayout container = binding.getRoot();
|
||||
// container.postDelayed(() -> {
|
||||
// container.setForeground(new ColorDrawable(Color.WHITE));
|
||||
// container.postDelayed(() -> container.setForeground(null), 50);
|
||||
// }, 100);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabled or disabled a button to switch cameras depending on the available cameras
|
||||
*/
|
||||
private void updateCameraSwitchButton() {
|
||||
try {
|
||||
binding.switchCamera.setEnabled(hasBackCamera() && hasFrontCamera());
|
||||
} catch (CameraInfoUnavailableException e) {
|
||||
binding.switchCamera.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the device has an available back camera. False otherwise
|
||||
*/
|
||||
private boolean hasBackCamera() throws CameraInfoUnavailableException {
|
||||
if (cameraProvider == null) return false;
|
||||
return cameraProvider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the device has an available front camera. False otherwise
|
||||
*/
|
||||
private boolean hasFrontCamera() throws CameraInfoUnavailableException {
|
||||
if (cameraProvider == null) {
|
||||
return false;
|
||||
}
|
||||
return cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA);
|
||||
}
|
||||
}
|
@ -22,9 +22,9 @@ import androidx.core.content.ContextCompat;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.asyncs.PostFetcher;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.IntentModel;
|
||||
import awais.instagrabber.models.enums.IntentModelType;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
@ -123,7 +123,7 @@ public final class DirectDownload extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
final String text = model.getText();
|
||||
new PostFetcher(text, new FetchListener<FeedModel>() {
|
||||
new PostFetcher(text, new FetchListener<Media>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
if (notificationManager == null) return;
|
||||
@ -138,7 +138,7 @@ public final class DirectDownload extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final FeedModel result) {
|
||||
public void onResult(final Media result) {
|
||||
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
|
||||
if (result == null) {
|
||||
finish();
|
||||
|
@ -1,5 +1,6 @@
|
||||
package awais.instagrabber.activities;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@ -20,19 +21,26 @@ import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.provider.FontRequest;
|
||||
import androidx.emoji.text.EmojiCompat;
|
||||
import androidx.emoji.text.FontRequestEmojiCompatConfig;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDestination;
|
||||
@ -40,6 +48,7 @@ import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
||||
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -53,19 +62,27 @@ import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.SuggestionsAdapter;
|
||||
import awais.instagrabber.asyncs.PostFetcher;
|
||||
import awais.instagrabber.asyncs.SuggestionsFetcher;
|
||||
import awais.instagrabber.customviews.emoji.EmojiVariantManager;
|
||||
import awais.instagrabber.databinding.ActivityMainBinding;
|
||||
import awais.instagrabber.fragments.PostViewV2Fragment;
|
||||
import awais.instagrabber.fragments.directmessages.DirectMessageInboxFragmentDirections;
|
||||
import awais.instagrabber.fragments.main.FeedFragment;
|
||||
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.IntentModel;
|
||||
import awais.instagrabber.models.SuggestionModel;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
import awais.instagrabber.services.ActivityCheckerService;
|
||||
import awais.instagrabber.services.DMSyncAlarmReceiver;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.FlavorTown;
|
||||
import awais.instagrabber.utils.IntentUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.emoji.EmojiParser;
|
||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||
|
||||
import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -93,6 +110,8 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
private int firstFragmentGraphIndex;
|
||||
private boolean isActivityCheckerServiceBound = false;
|
||||
private boolean isBackStackEmpty = false;
|
||||
private boolean isLoggedIn;
|
||||
private HideBottomViewOnScrollBehavior<BottomNavigationView> behavior;
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
@ -122,10 +141,20 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
CookieUtils.setupCookies(cookie);
|
||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != 0;
|
||||
if (settingsHelper.getBoolean(Constants.FLAG_SECURE))
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
setContentView(binding.getRoot());
|
||||
final Toolbar toolbar = binding.toolbar;
|
||||
setSupportActionBar(toolbar);
|
||||
createNotificationChannels();
|
||||
try {
|
||||
final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) binding.bottomNavView.getLayoutParams();
|
||||
//noinspection unchecked
|
||||
behavior = (HideBottomViewOnScrollBehavior<BottomNavigationView>) layoutParams.getBehavior();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onCreate: ", e);
|
||||
}
|
||||
if (savedInstanceState == null) {
|
||||
setupBottomNavigationBar(true);
|
||||
}
|
||||
@ -133,12 +162,27 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
final boolean checkUpdates = settingsHelper.getBoolean(Constants.CHECK_UPDATES);
|
||||
if (checkUpdates) FlavorTown.updateCheck(this);
|
||||
FlavorTown.changelogCheck(this);
|
||||
new ViewModelProvider(this).get(AppStateViewModel.class); // Just initiate the App state here
|
||||
final Intent intent = getIntent();
|
||||
handleIntent(intent);
|
||||
if (!TextUtils.isEmpty(cookie) && settingsHelper.getBoolean(Constants.CHECK_ACTIVITY)) {
|
||||
bindActivityCheckerService();
|
||||
}
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
||||
// Initialise the internal map
|
||||
AppExecutors.getInstance().tasksThread().execute(() -> {
|
||||
EmojiParser.setup(this);
|
||||
EmojiVariantManager.getInstance();
|
||||
});
|
||||
initEmojiCompat();
|
||||
// initDmService();
|
||||
}
|
||||
|
||||
private void initDmService() {
|
||||
if (!isLoggedIn) return;
|
||||
final boolean enabled = settingsHelper.getBoolean(PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH);
|
||||
if (!enabled) return;
|
||||
DMSyncAlarmReceiver.setAlarm(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -206,7 +250,17 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (isTaskRoot() && isBackStackEmpty) {
|
||||
int currentNavControllerBackStack = 2;
|
||||
if (currentNavControllerLiveData != null) {
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (navController != null) {
|
||||
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
||||
if (backStack != null) {
|
||||
currentNavControllerBackStack = backStack.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isTaskRoot() && isBackStackEmpty && currentNavControllerBackStack == 2) {
|
||||
finishAfterTransition();
|
||||
return;
|
||||
}
|
||||
@ -227,15 +281,22 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
}
|
||||
|
||||
private void createNotificationChannels() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.DOWNLOAD_CHANNEL_ID,
|
||||
Constants.DOWNLOAD_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.ACTIVITY_CHANNEL_ID,
|
||||
Constants.ACTIVITY_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.DOWNLOAD_CHANNEL_ID,
|
||||
Constants.DOWNLOAD_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.ACTIVITY_CHANNEL_ID,
|
||||
Constants.ACTIVITY_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
notificationManager.createNotificationChannel(new NotificationChannel(Constants.DM_UNREAD_CHANNEL_ID,
|
||||
Constants.DM_UNREAD_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT));
|
||||
final NotificationChannel silentNotificationChannel = new NotificationChannel(Constants.SILENT_NOTIFICATIONS_CHANNEL_ID,
|
||||
Constants.SILENT_NOTIFICATIONS_CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_LOW);
|
||||
silentNotificationChannel.setSound(null, null);
|
||||
notificationManager.createNotificationChannel(silentNotificationChannel);
|
||||
}
|
||||
|
||||
private void setupSuggestions() {
|
||||
@ -372,8 +433,6 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
|
||||
private void setupBottomNavigationBar(final boolean setDefaultFromSettings) {
|
||||
int main_nav_ids = R.array.main_nav_ids;
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
final boolean isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) != null;
|
||||
if (!isLoggedIn) {
|
||||
main_nav_ids = R.array.logged_out_main_nav_ids;
|
||||
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
||||
@ -449,12 +508,28 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
if (navController == null) return;
|
||||
NavigationUI.setupWithNavController(toolbar, navController);
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
if (destination.getId() == R.id.directMessagesThreadFragment && arguments != null) {
|
||||
// Set the thread title earlier for better ux
|
||||
final String title = arguments.getString("title");
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null && !TextUtils.isEmpty(title)) {
|
||||
actionBar.setTitle(title);
|
||||
}
|
||||
}
|
||||
// below is a hack to check if we are at the end of the current stack, to setup the search view
|
||||
binding.appBarLayout.setExpanded(true, true);
|
||||
final int destinationId = destination.getId();
|
||||
@SuppressLint("RestrictedApi") final Deque<NavBackStackEntry> backStack = navController.getBackStack();
|
||||
setupMenu(backStack.size(), destinationId);
|
||||
binding.bottomNavView.setVisibility(SHOW_BOTTOM_VIEW_DESTINATIONS.contains(destinationId) ? View.VISIBLE : View.GONE);
|
||||
final boolean contains = SHOW_BOTTOM_VIEW_DESTINATIONS.contains(destinationId);
|
||||
binding.bottomNavView.setVisibility(contains ? View.VISIBLE : View.GONE);
|
||||
if (contains && behavior != null) {
|
||||
behavior.slideUp(binding.bottomNavView);
|
||||
}
|
||||
|
||||
// explicitly hide keyboard when we navigate
|
||||
final View view = getCurrentFocus();
|
||||
Utils.hideKeyboard(view);
|
||||
});
|
||||
}
|
||||
|
||||
@ -491,6 +566,10 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
showActivityView();
|
||||
return;
|
||||
}
|
||||
if (Constants.ACTION_SHOW_DM_THREAD.equals(action)) {
|
||||
showThread(intent);
|
||||
return;
|
||||
}
|
||||
if (Intent.ACTION_SEND.equals(action) && type != null) {
|
||||
if (type.equals("text/plain")) {
|
||||
handleUrl(intent.getStringExtra(Intent.EXTRA_TEXT));
|
||||
@ -504,6 +583,58 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
}
|
||||
}
|
||||
|
||||
private void showThread(@NonNull final Intent intent) {
|
||||
final String threadId = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_ID);
|
||||
final String threadTitle = intent.getStringExtra(Constants.DM_THREAD_ACTION_EXTRA_THREAD_TITLE);
|
||||
navigateToThread(threadId, threadTitle);
|
||||
}
|
||||
|
||||
public void navigateToThread(final String threadId, final String threadTitle) {
|
||||
if (threadId == null || threadTitle == null) return;
|
||||
currentNavControllerLiveData.observe(this, new Observer<NavController>() {
|
||||
@Override
|
||||
public void onChanged(final NavController navController) {
|
||||
if (navController == null) return;
|
||||
if (navController.getGraph().getId() != R.id.direct_messages_nav_graph) return;
|
||||
try {
|
||||
final NavDestination currentDestination = navController.getCurrentDestination();
|
||||
if (currentDestination != null && currentDestination.getId() == R.id.directMessagesInboxFragment) {
|
||||
// if we are already on the inbox page, navigate to the thread
|
||||
// need handler.post() to wait for the fragment manager to be ready to navigate
|
||||
new Handler().post(() -> {
|
||||
final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections
|
||||
.actionInboxToThread(threadId, threadTitle);
|
||||
navController.navigate(action);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// add a destination change listener to navigate to thread once we are on the inbox page
|
||||
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
|
||||
@Override
|
||||
public void onDestinationChanged(@NonNull final NavController controller,
|
||||
@NonNull final NavDestination destination,
|
||||
@Nullable final Bundle arguments) {
|
||||
if (destination.getId() == R.id.directMessagesInboxFragment) {
|
||||
final DirectMessageInboxFragmentDirections.ActionInboxToThread action = DirectMessageInboxFragmentDirections
|
||||
.actionInboxToThread(threadId, threadTitle);
|
||||
controller.navigate(action);
|
||||
controller.removeOnDestinationChangedListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
// pop back stack until we reach the inbox page
|
||||
navController.popBackStack(R.id.directMessagesInboxFragment, false);
|
||||
} finally {
|
||||
currentNavControllerLiveData.removeObserver(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
final int selectedItemId = binding.bottomNavView.getSelectedItemId();
|
||||
if (selectedItemId != R.navigation.direct_messages_nav_graph) {
|
||||
setBottomNavSelectedItem(R.navigation.direct_messages_nav_graph);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUrl(final String url) {
|
||||
if (url == null) return;
|
||||
// Log.d(TAG, url);
|
||||
@ -583,7 +714,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (navController == null) return;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("hashtag", "#" + hashtag);
|
||||
bundle.putString("hashtag", hashtag);
|
||||
navController.navigate(R.id.action_global_hashTagFragment, bundle);
|
||||
}
|
||||
|
||||
@ -591,7 +722,9 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
if (currentNavControllerLiveData == null) return;
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (navController == null) return;
|
||||
navController.navigate(R.id.action_global_notificationsViewerFragment);
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("type", "notif");
|
||||
navController.navigate(R.id.action_global_notificationsViewerFragment, bundle);
|
||||
}
|
||||
|
||||
private void bindActivityCheckerService() {
|
||||
@ -637,4 +770,44 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
public CollapsingToolbarLayout getCollapsingToolbarView() {
|
||||
return binding.collapsingToolbarLayout;
|
||||
}
|
||||
|
||||
public AppBarLayout getAppbarLayout() {
|
||||
return binding.appBarLayout;
|
||||
}
|
||||
|
||||
public void removeLayoutTransition() {
|
||||
binding.getRoot().setLayoutTransition(null);
|
||||
}
|
||||
|
||||
public void setLayoutTransition() {
|
||||
binding.getRoot().setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
private void initEmojiCompat() {
|
||||
// Use a downloadable font for EmojiCompat
|
||||
final FontRequest fontRequest = new FontRequest(
|
||||
"com.google.android.gms.fonts",
|
||||
"com.google.android.gms",
|
||||
"Noto Color Emoji Compat",
|
||||
R.array.com_google_android_gms_fonts_certs);
|
||||
final EmojiCompat.Config config = new FontRequestEmojiCompatConfig(getApplicationContext(), fontRequest);
|
||||
config.setReplaceAll(true)
|
||||
// .setUseEmojiAsDefaultStyle(true)
|
||||
.registerInitCallback(new EmojiCompat.InitCallback() {
|
||||
@Override
|
||||
public void onInitialized() {
|
||||
Log.i(TAG, "EmojiCompat initialized");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(@Nullable Throwable throwable) {
|
||||
Log.e(TAG, "EmojiCompat initialization failed", throwable);
|
||||
}
|
||||
});
|
||||
EmojiCompat.init(config);
|
||||
}
|
||||
|
||||
public Toolbar getToolbar() {
|
||||
return binding.toolbar;
|
||||
}
|
||||
}
|
@ -0,0 +1,407 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.AdapterListUpdateCallback;
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig;
|
||||
import androidx.recyclerview.widget.AsyncListDiffer;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemActionLogViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemAnimatedMediaViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemDefaultViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemLikeViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemLinkViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemMediaShareViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemMediaViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemPlaceholderViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemProfileViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemRavenMediaViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemReelShareViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemStoryShareViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemTextViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemVideoCallEventViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemVoiceMediaViewHolder;
|
||||
import awais.instagrabber.customviews.emoji.Emoji;
|
||||
import awais.instagrabber.databinding.LayoutDmActionLogBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmAnimatedMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmHeaderBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLikeBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLinkBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaShareBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmProfileBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmReelShareBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmStoryShareBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmVoiceMediaBinding;
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.DateUtils;
|
||||
|
||||
public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
private static final String TAG = DirectItemsAdapter.class.getSimpleName();
|
||||
|
||||
private List<DirectItem> items;
|
||||
private DirectThread thread;
|
||||
private DirectItemViewHolder selectedViewHolder;
|
||||
|
||||
private final User currentUser;
|
||||
private final DirectItemCallback callback;
|
||||
private final AsyncListDiffer<DirectItemOrHeader> differ;
|
||||
private final DirectItemInternalLongClickListener longClickListener;
|
||||
|
||||
private static final DiffUtil.ItemCallback<DirectItemOrHeader> diffCallback = new DiffUtil.ItemCallback<DirectItemOrHeader>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final DirectItemOrHeader oldItem, @NonNull final DirectItemOrHeader newItem) {
|
||||
final boolean bothHeaders = oldItem.isHeader() && newItem.isHeader();
|
||||
final boolean bothItems = !oldItem.isHeader() && !newItem.isHeader();
|
||||
boolean areSameType = bothHeaders || bothItems;
|
||||
if (!areSameType) return false;
|
||||
if (bothHeaders) {
|
||||
return oldItem.date.equals(newItem.date);
|
||||
}
|
||||
if (oldItem.item != null && newItem.item != null) {
|
||||
String oldClientContext = oldItem.item.getClientContext();
|
||||
if (oldClientContext == null) {
|
||||
oldClientContext = oldItem.item.getItemId();
|
||||
}
|
||||
String newClientContext = newItem.item.getClientContext();
|
||||
if (newClientContext == null) {
|
||||
newClientContext = newItem.item.getItemId();
|
||||
}
|
||||
return oldClientContext.equals(newClientContext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final DirectItemOrHeader oldItem, @NonNull final DirectItemOrHeader newItem) {
|
||||
final boolean bothHeaders = oldItem.isHeader() && newItem.isHeader();
|
||||
final boolean bothItems = !oldItem.isHeader() && !newItem.isHeader();
|
||||
boolean areSameType = bothHeaders || bothItems;
|
||||
if (!areSameType) return false;
|
||||
if (bothHeaders) {
|
||||
return oldItem.date.equals(newItem.date);
|
||||
}
|
||||
final boolean timestampEqual = oldItem.item.getTimestamp() == newItem.item.getTimestamp();
|
||||
final boolean bothPending = oldItem.item.isPending() == newItem.item.isPending();
|
||||
final boolean reactionSame = Objects.equals(oldItem.item.getReactions(), newItem.item.getReactions());
|
||||
return timestampEqual && bothPending && reactionSame;
|
||||
}
|
||||
};
|
||||
|
||||
public DirectItemsAdapter(@NonNull final User currentUser,
|
||||
@NonNull final DirectThread thread,
|
||||
@NonNull final DirectItemCallback callback,
|
||||
@NonNull final DirectItemLongClickListener itemLongClickListener) {
|
||||
this.currentUser = currentUser;
|
||||
this.thread = thread;
|
||||
this.callback = callback;
|
||||
differ = new AsyncListDiffer<>(new AdapterListUpdateCallback(this),
|
||||
new AsyncDifferConfig.Builder<>(diffCallback).build());
|
||||
longClickListener = (position, viewHolder) -> {
|
||||
if (selectedViewHolder != null) {
|
||||
selectedViewHolder.setSelected(false);
|
||||
}
|
||||
selectedViewHolder = viewHolder;
|
||||
viewHolder.setSelected(true);
|
||||
itemLongClickListener.onLongClick(position);
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
if (type == -1) {
|
||||
// header
|
||||
return new HeaderViewHolder(LayoutDmHeaderBinding.inflate(layoutInflater, parent, false));
|
||||
}
|
||||
final LayoutDmBaseBinding baseBinding = LayoutDmBaseBinding.inflate(layoutInflater, parent, false);
|
||||
final DirectItemType directItemType = DirectItemType.valueOf(type);
|
||||
final DirectItemViewHolder itemViewHolder = getItemViewHolder(layoutInflater, baseBinding, directItemType);
|
||||
itemViewHolder.setLongClickListener(longClickListener);
|
||||
return itemViewHolder;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private DirectItemViewHolder getItemViewHolder(final LayoutInflater layoutInflater,
|
||||
final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final DirectItemType directItemType) {
|
||||
switch (directItemType) {
|
||||
case TEXT: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemTextViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case LIKE: {
|
||||
final LayoutDmLikeBinding binding = LayoutDmLikeBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemLikeViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case LINK: {
|
||||
final LayoutDmLinkBinding binding = LayoutDmLinkBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemLinkViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case ACTION_LOG: {
|
||||
final LayoutDmActionLogBinding binding = LayoutDmActionLogBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemActionLogViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case VIDEO_CALL_EVENT: {
|
||||
final LayoutDmActionLogBinding binding = LayoutDmActionLogBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemVideoCallEventViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case PLACEHOLDER: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemPlaceholderViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case ANIMATED_MEDIA: {
|
||||
final LayoutDmAnimatedMediaBinding binding = LayoutDmAnimatedMediaBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemAnimatedMediaViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case VOICE_MEDIA: {
|
||||
final LayoutDmVoiceMediaBinding binding = LayoutDmVoiceMediaBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemVoiceMediaViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case LOCATION:
|
||||
case PROFILE: {
|
||||
final LayoutDmProfileBinding binding = LayoutDmProfileBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemProfileViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case MEDIA: {
|
||||
final LayoutDmMediaBinding binding = LayoutDmMediaBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemMediaViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case CLIP:
|
||||
case FELIX_SHARE:
|
||||
case MEDIA_SHARE: {
|
||||
final LayoutDmMediaShareBinding binding = LayoutDmMediaShareBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemMediaShareViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case STORY_SHARE: {
|
||||
final LayoutDmStoryShareBinding binding = LayoutDmStoryShareBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemStoryShareViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case REEL_SHARE: {
|
||||
final LayoutDmReelShareBinding binding = LayoutDmReelShareBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemReelShareViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
case RAVEN_MEDIA: {
|
||||
final LayoutDmRavenMediaBinding binding = LayoutDmRavenMediaBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemRavenMediaViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
default: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, baseBinding.message, false);
|
||||
return new DirectItemDefaultViewHolder(baseBinding, binding, currentUser, thread, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
|
||||
final DirectItemOrHeader itemOrHeader = getItem(position);
|
||||
if (itemOrHeader.isHeader()) {
|
||||
((HeaderViewHolder) holder).bind(itemOrHeader.date);
|
||||
return;
|
||||
}
|
||||
if (thread == null) return;
|
||||
((DirectItemViewHolder) holder).bind(position, itemOrHeader.item);
|
||||
}
|
||||
|
||||
protected DirectItemOrHeader getItem(int position) {
|
||||
return differ.getCurrentList().get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return differ.getCurrentList().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
final DirectItemOrHeader itemOrHeader = getItem(position);
|
||||
if (itemOrHeader.isHeader()) {
|
||||
return -1;
|
||||
}
|
||||
return itemOrHeader.item.getItemType().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
final DirectItemOrHeader itemOrHeader = getItem(position);
|
||||
if (itemOrHeader.isHeader()) {
|
||||
return itemOrHeader.date.hashCode();
|
||||
}
|
||||
if (itemOrHeader.item.getClientContext() == null) {
|
||||
return itemOrHeader.item.getItemId().hashCode();
|
||||
}
|
||||
return itemOrHeader.item.getClientContext().hashCode();
|
||||
}
|
||||
|
||||
public void setThread(final DirectThread thread) {
|
||||
if (thread == null) return;
|
||||
this.thread = thread;
|
||||
// notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void submitList(@Nullable final List<DirectItem> list) {
|
||||
if (list == null) {
|
||||
differ.submitList(null);
|
||||
return;
|
||||
}
|
||||
differ.submitList(sectionAndSort(list));
|
||||
this.items = list;
|
||||
}
|
||||
|
||||
public void submitList(@Nullable final List<DirectItem> list, @Nullable final Runnable commitCallback) {
|
||||
if (list == null) {
|
||||
differ.submitList(null, commitCallback);
|
||||
return;
|
||||
}
|
||||
differ.submitList(sectionAndSort(list), commitCallback);
|
||||
this.items = list;
|
||||
}
|
||||
|
||||
private List<DirectItemOrHeader> sectionAndSort(final List<DirectItem> list) {
|
||||
final List<DirectItemOrHeader> itemOrHeaders = new ArrayList<>();
|
||||
Date prevSectionDate = null;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
final DirectItem item = list.get(i);
|
||||
if (item == null) continue;
|
||||
final DirectItemOrHeader prev = itemOrHeaders.isEmpty() ? null : itemOrHeaders.get(itemOrHeaders.size() - 1);
|
||||
if (prev != null && prev.item != null && DateUtils.isSameDay(prev.item.getDate(), item.getDate())) {
|
||||
// just add item
|
||||
final DirectItemOrHeader itemOrHeader = new DirectItemOrHeader();
|
||||
itemOrHeader.item = item;
|
||||
itemOrHeaders.add(itemOrHeader);
|
||||
if (i == list.size() - 1) {
|
||||
// add header
|
||||
final DirectItemOrHeader itemOrHeader2 = new DirectItemOrHeader();
|
||||
itemOrHeader2.date = prevSectionDate;
|
||||
itemOrHeaders.add(itemOrHeader2);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (prevSectionDate != null) {
|
||||
// add header
|
||||
final DirectItemOrHeader itemOrHeader = new DirectItemOrHeader();
|
||||
itemOrHeader.date = prevSectionDate;
|
||||
itemOrHeaders.add(itemOrHeader);
|
||||
}
|
||||
// Add item
|
||||
final DirectItemOrHeader itemOrHeader = new DirectItemOrHeader();
|
||||
itemOrHeader.item = item;
|
||||
itemOrHeaders.add(itemOrHeader);
|
||||
prevSectionDate = DateUtils.dateAtZeroHours(item.getDate());
|
||||
}
|
||||
return itemOrHeaders;
|
||||
}
|
||||
|
||||
public List<DirectItemOrHeader> getList() {
|
||||
return differ.getCurrentList();
|
||||
}
|
||||
|
||||
public List<DirectItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull final RecyclerView.ViewHolder holder) {
|
||||
if (holder instanceof DirectItemViewHolder) {
|
||||
((DirectItemViewHolder) holder).cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull final RecyclerView.ViewHolder holder) {
|
||||
if (holder instanceof DirectItemViewHolder) {
|
||||
((DirectItemViewHolder) holder).cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public DirectThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
public static class DirectItemOrHeader {
|
||||
Date date;
|
||||
public DirectItem item;
|
||||
|
||||
public boolean isHeader() {
|
||||
return date != null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DirectItemOrHeader{" +
|
||||
"date=" + date +
|
||||
", item=" + (item != null ? item.getItemType() : null) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class HeaderViewHolder extends RecyclerView.ViewHolder {
|
||||
private final LayoutDmHeaderBinding binding;
|
||||
|
||||
public HeaderViewHolder(@NonNull final LayoutDmHeaderBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final Date date) {
|
||||
if (date == null) {
|
||||
binding.header.setText("");
|
||||
return;
|
||||
}
|
||||
binding.header.setText(DateFormat.getDateFormat(itemView.getContext()).format(date));
|
||||
}
|
||||
}
|
||||
|
||||
public interface DirectItemCallback {
|
||||
void onHashtagClick(String hashtag);
|
||||
|
||||
void onMentionClick(String mention);
|
||||
|
||||
void onLocationClick(long locationId);
|
||||
|
||||
void onURLClick(String url);
|
||||
|
||||
void onEmailClick(String email);
|
||||
|
||||
void onMediaClick(Media media);
|
||||
|
||||
void onStoryClick(DirectItemStoryShare storyShare);
|
||||
|
||||
void onReaction(DirectItem item, Emoji emoji);
|
||||
|
||||
void onReactionClick(DirectItem item, int position);
|
||||
|
||||
void onOptionSelect(DirectItem item, @IdRes int itemId);
|
||||
}
|
||||
|
||||
public interface DirectItemInternalLongClickListener {
|
||||
void onLongClick(int position, DirectItemViewHolder viewHolder);
|
||||
}
|
||||
|
||||
public interface DirectItemLongClickListener {
|
||||
void onLongClick(int position);
|
||||
}
|
||||
}
|
@ -4,51 +4,72 @@ import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.DirectMessageInboxItemViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
import awais.instagrabber.models.direct_messages.InboxThreadModel;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class DirectMessageInboxAdapter extends ListAdapter<InboxThreadModel, DirectMessageInboxItemViewHolder> {
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectInboxItemViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
|
||||
public final class DirectMessageInboxAdapter extends ListAdapter<DirectThread, DirectInboxItemViewHolder> {
|
||||
private final OnItemClickListener onClickListener;
|
||||
|
||||
private static final DiffUtil.ItemCallback<InboxThreadModel> diffCallback = new DiffUtil.ItemCallback<InboxThreadModel>() {
|
||||
private static final DiffUtil.ItemCallback<DirectThread> diffCallback = new DiffUtil.ItemCallback<DirectThread>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final InboxThreadModel oldItem, @NonNull final InboxThreadModel newItem) {
|
||||
public boolean areItemsTheSame(@NonNull final DirectThread oldItem, @NonNull final DirectThread newItem) {
|
||||
return oldItem.getThreadId().equals(newItem.getThreadId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final InboxThreadModel oldItem, @NonNull final InboxThreadModel newItem) {
|
||||
return oldItem.equals(newItem);
|
||||
public boolean areContentsTheSame(@NonNull final DirectThread oldThread,
|
||||
@NonNull final DirectThread newThread) {
|
||||
final boolean titleEqual = oldThread.getThreadTitle().equals(newThread.getThreadTitle());
|
||||
if (!titleEqual) return false;
|
||||
final boolean lastSeenAtEqual = Objects.equals(oldThread.getLastSeenAt(), newThread.getLastSeenAt());
|
||||
if (!lastSeenAtEqual) return false;
|
||||
final List<DirectItem> oldItems = oldThread.getItems();
|
||||
final List<DirectItem> newItems = newThread.getItems();
|
||||
if (oldItems == null || newItems == null) return false;
|
||||
if (oldItems.size() != newItems.size()) return false;
|
||||
final DirectItem oldItemFirst = oldThread.getFirstDirectItem();
|
||||
final DirectItem newItemFirst = newThread.getFirstDirectItem();
|
||||
if (oldItemFirst == null || newItemFirst == null) return false;
|
||||
final boolean idsEqual = oldItemFirst.getItemId().equals(newItemFirst.getItemId());
|
||||
if (!idsEqual) return false;
|
||||
return oldItemFirst.getTimestamp() == newItemFirst.getTimestamp();
|
||||
}
|
||||
};
|
||||
|
||||
public DirectMessageInboxAdapter(final OnItemClickListener onClickListener) {
|
||||
super(diffCallback);
|
||||
super(new AsyncDifferConfig.Builder<>(diffCallback).build());
|
||||
this.onClickListener = onClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DirectMessageInboxItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) {
|
||||
public DirectInboxItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final LayoutDmInboxItemBinding binding = LayoutDmInboxItemBinding.inflate(layoutInflater, parent, false);
|
||||
return new DirectMessageInboxItemViewHolder(binding);
|
||||
return new DirectInboxItemViewHolder(binding, onClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final DirectMessageInboxItemViewHolder holder, final int position) {
|
||||
final InboxThreadModel threadModel = getItem(position);
|
||||
if (onClickListener != null) {
|
||||
holder.itemView.setOnClickListener((v) -> onClickListener.onItemClick(threadModel));
|
||||
}
|
||||
holder.bind(threadModel);
|
||||
public void onBindViewHolder(@NonNull final DirectInboxItemViewHolder holder, final int position) {
|
||||
final DirectThread thread = getItem(position);
|
||||
holder.bind(thread);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
return getItem(position).getThreadId().hashCode();
|
||||
}
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(final InboxThreadModel inboxThreadModel);
|
||||
void onItemClick(final DirectThread thread);
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageActionLogViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageAnimatedMediaViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageDefaultViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageItemViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageLinkViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageMediaShareViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageMediaViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessagePlaceholderViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageProfileViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageRavenMediaViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageReelShareViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageStoryShareViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageTextViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageVideoCallEventViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectMessageVoiceMediaViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmAnimatedMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLinkBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaShareBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmProfileBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmStoryShareBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmVoiceMediaBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
|
||||
public final class DirectMessageItemsAdapter extends ListAdapter<DirectItemModel, DirectMessageItemViewHolder> {
|
||||
private final List<ProfileModel> users;
|
||||
private final List<ProfileModel> leftUsers;
|
||||
private final View.OnClickListener onClickListener;
|
||||
private final MentionClickListener mentionClickListener;
|
||||
|
||||
private static final DiffUtil.ItemCallback<DirectItemModel> diffCallback = new DiffUtil.ItemCallback<DirectItemModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final DirectItemModel oldItem, @NonNull final DirectItemModel newItem) {
|
||||
return oldItem.getItemId().equals(newItem.getItemId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final DirectItemModel oldItem, @NonNull final DirectItemModel newItem) {
|
||||
return oldItem.getItemId().equals(newItem.getItemId());
|
||||
}
|
||||
};
|
||||
|
||||
public DirectMessageItemsAdapter(final List<ProfileModel> users,
|
||||
final List<ProfileModel> leftUsers,
|
||||
final View.OnClickListener onClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
super(diffCallback);
|
||||
this.users = users;
|
||||
this.leftUsers = leftUsers;
|
||||
this.onClickListener = onClickListener;
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DirectMessageItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int type) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final DirectItemType directItemType = DirectItemType.valueOf(type);
|
||||
final LayoutDmBaseBinding baseBinding = LayoutDmBaseBinding.inflate(layoutInflater, parent, false);
|
||||
final ViewGroup itemViewParent = baseBinding.messageCard;
|
||||
switch (directItemType) {
|
||||
case LIKE:
|
||||
case TEXT: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageTextViewHolder(baseBinding, binding, onClickListener, mentionClickListener);
|
||||
}
|
||||
case PLACEHOLDER: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessagePlaceholderViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case ACTION_LOG: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageActionLogViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case LINK: {
|
||||
final LayoutDmLinkBinding binding = LayoutDmLinkBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageLinkViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case MEDIA: {
|
||||
final LayoutDmMediaBinding binding = LayoutDmMediaBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageMediaViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case PROFILE: {
|
||||
final LayoutDmProfileBinding binding = LayoutDmProfileBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageProfileViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case REEL_SHARE: {
|
||||
final LayoutDmRavenMediaBinding binding = LayoutDmRavenMediaBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageReelShareViewHolder(baseBinding, binding, onClickListener, mentionClickListener);
|
||||
}
|
||||
case MEDIA_SHARE:
|
||||
case FELIX_SHARE:
|
||||
case CLIP: {
|
||||
final LayoutDmMediaShareBinding binding = LayoutDmMediaShareBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageMediaShareViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case RAVEN_MEDIA: {
|
||||
final LayoutDmRavenMediaBinding binding = LayoutDmRavenMediaBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageRavenMediaViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case STORY_SHARE: {
|
||||
final LayoutDmStoryShareBinding binding = LayoutDmStoryShareBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageStoryShareViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case VOICE_MEDIA: {
|
||||
final LayoutDmVoiceMediaBinding binding = LayoutDmVoiceMediaBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageVoiceMediaViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case ANIMATED_MEDIA: {
|
||||
final LayoutDmAnimatedMediaBinding binding = LayoutDmAnimatedMediaBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageAnimatedMediaViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
case VIDEO_CALL_EVENT: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageVideoCallEventViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
default: {
|
||||
final LayoutDmTextBinding binding = LayoutDmTextBinding.inflate(layoutInflater, itemViewParent, false);
|
||||
return new DirectMessageDefaultViewHolder(baseBinding, binding, onClickListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final DirectMessageItemViewHolder holder, final int position) {
|
||||
final DirectItemModel directItemModel = getItem(position);
|
||||
holder.bind(directItemModel, users, leftUsers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
return getItem(position).getItemType().getId();
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
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 DirectMessageMembersAdapter extends RecyclerView.Adapter<FollowsViewHolder> {
|
||||
private final ProfileModel[] profileModels;
|
||||
private final List<Long> admins;
|
||||
private final View.OnClickListener onClickListener;
|
||||
|
||||
public DirectMessageMembersAdapter(final ProfileModel[] profileModels,
|
||||
final List<Long> admins,
|
||||
final View.OnClickListener onClickListener) {
|
||||
this.profileModels = profileModels;
|
||||
this.admins = admins;
|
||||
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[position];
|
||||
holder.bind(model, admins, onClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return profileModels.length;
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectPendingUserViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmPendingUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadParticipantRequestsResponse;
|
||||
|
||||
public final class DirectPendingUsersAdapter extends ListAdapter<DirectPendingUsersAdapter.PendingUser, DirectPendingUserViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<PendingUser> DIFF_CALLBACK = new DiffUtil.ItemCallback<PendingUser>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final PendingUser oldItem, @NonNull final PendingUser newItem) {
|
||||
return oldItem.user.getPk() == newItem.user.getPk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final PendingUser oldItem, @NonNull final PendingUser newItem) {
|
||||
return Objects.equals(oldItem.user.getUsername(), newItem.user.getUsername()) &&
|
||||
Objects.equals(oldItem.user.getFullName(), newItem.user.getFullName()) &&
|
||||
Objects.equals(oldItem.requester, newItem.requester);
|
||||
}
|
||||
};
|
||||
|
||||
private final PendingUserCallback callback;
|
||||
|
||||
public DirectPendingUsersAdapter(final PendingUserCallback callback) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.callback = callback;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
public void submitPendingRequests(final DirectThreadParticipantRequestsResponse requests) {
|
||||
if (requests == null || requests.getUsers() == null) {
|
||||
submitList(Collections.emptyList());
|
||||
return;
|
||||
}
|
||||
submitList(parse(requests));
|
||||
}
|
||||
|
||||
private List<PendingUser> parse(final DirectThreadParticipantRequestsResponse requests) {
|
||||
final List<User> users = requests.getUsers();
|
||||
final Map<Long, String> requesterUsernames = requests.getRequesterUsernames();
|
||||
return users.stream()
|
||||
.map(user -> new PendingUser(user, requesterUsernames.get(user.getPk())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DirectPendingUserViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final LayoutDmPendingUserItemBinding binding = LayoutDmPendingUserItemBinding.inflate(layoutInflater, parent, false);
|
||||
return new DirectPendingUserViewHolder(binding, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final DirectPendingUserViewHolder holder, final int position) {
|
||||
final PendingUser pendingUser = getItem(position);
|
||||
holder.bind(position, pendingUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
final PendingUser item = getItem(position);
|
||||
return item.user.getPk();
|
||||
}
|
||||
|
||||
public static class PendingUser {
|
||||
private final User user;
|
||||
private final String requester;
|
||||
|
||||
private boolean inProgress;
|
||||
|
||||
public PendingUser(final User user, final String requester) {
|
||||
this.user = user;
|
||||
this.requester = requester;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getRequester() {
|
||||
return requester;
|
||||
}
|
||||
|
||||
public boolean isInProgress() {
|
||||
return inProgress;
|
||||
}
|
||||
|
||||
public PendingUser setInProgress(final boolean inProgress) {
|
||||
this.inProgress = inProgress;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public interface PendingUserCallback {
|
||||
void onClick(int position, PendingUser pendingUser);
|
||||
|
||||
void onApprove(int position, PendingUser pendingUser);
|
||||
|
||||
void onDeny(int position, PendingUser pendingUser);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectReactionViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
||||
|
||||
public final class DirectReactionsAdapter extends ListAdapter<DirectItemEmojiReaction, DirectReactionViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<DirectItemEmojiReaction> DIFF_CALLBACK = new DiffUtil.ItemCallback<DirectItemEmojiReaction>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final DirectItemEmojiReaction oldItem, @NonNull final DirectItemEmojiReaction newItem) {
|
||||
return oldItem.getSenderId() == newItem.getSenderId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final DirectItemEmojiReaction oldItem, @NonNull final DirectItemEmojiReaction newItem) {
|
||||
return oldItem.getEmoji().equals(newItem.getEmoji());
|
||||
}
|
||||
};
|
||||
|
||||
private final long viewerId;
|
||||
private final List<User> users;
|
||||
private final String itemId;
|
||||
private final OnReactionClickListener onReactionClickListener;
|
||||
|
||||
public DirectReactionsAdapter(final long viewerId,
|
||||
final List<User> users,
|
||||
final String itemId,
|
||||
final OnReactionClickListener onReactionClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.viewerId = viewerId;
|
||||
this.users = users;
|
||||
this.itemId = itemId;
|
||||
this.onReactionClickListener = onReactionClickListener;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DirectReactionViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final LayoutDmUserItemBinding binding = LayoutDmUserItemBinding.inflate(layoutInflater, parent, false);
|
||||
return new DirectReactionViewHolder(binding, viewerId, itemId, onReactionClickListener);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final DirectReactionViewHolder holder, final int position) {
|
||||
final DirectItemEmojiReaction reaction = getItem(position);
|
||||
if (reaction == null) return;
|
||||
holder.bind(reaction, getUser(reaction.getSenderId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
return getItem(position).getSenderId();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private User getUser(final long pk) {
|
||||
return users.stream()
|
||||
.filter(user -> user.getPk() == pk)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public interface OnReactionClickListener {
|
||||
void onReactionClick(String itemId, DirectItemEmojiReaction reaction);
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectUserViewHolder;
|
||||
import awais.instagrabber.databinding.ItemFavSectionHeaderBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public final class DirectUsersAdapter extends ListAdapter<DirectUsersAdapter.DirectUserOrHeader, RecyclerView.ViewHolder> {
|
||||
|
||||
private static final int VIEW_TYPE_HEADER = 0;
|
||||
private static final int VIEW_TYPE_USER = 1;
|
||||
private static final DiffUtil.ItemCallback<DirectUserOrHeader> DIFF_CALLBACK = new DiffUtil.ItemCallback<DirectUserOrHeader>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final DirectUserOrHeader oldItem, @NonNull final DirectUserOrHeader newItem) {
|
||||
final boolean bothHeaders = oldItem.isHeader() && newItem.isHeader();
|
||||
final boolean bothItems = !oldItem.isHeader() && !newItem.isHeader();
|
||||
boolean areSameType = bothHeaders || bothItems;
|
||||
if (!areSameType) return false;
|
||||
if (bothHeaders) {
|
||||
return oldItem.headerTitle == newItem.headerTitle;
|
||||
}
|
||||
if (oldItem.user != null && newItem.user != null) {
|
||||
return oldItem.user.getPk() == newItem.user.getPk();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final DirectUserOrHeader oldItem, @NonNull final DirectUserOrHeader newItem) {
|
||||
final boolean bothHeaders = oldItem.isHeader() && newItem.isHeader();
|
||||
final boolean bothItems = !oldItem.isHeader() && !newItem.isHeader();
|
||||
boolean areSameType = bothHeaders || bothItems;
|
||||
if (!areSameType) return false;
|
||||
if (bothHeaders) {
|
||||
return oldItem.headerTitle == newItem.headerTitle;
|
||||
}
|
||||
if (oldItem.user != null && newItem.user != null) {
|
||||
return oldItem.user.getUsername().equals(newItem.user.getUsername()) &&
|
||||
oldItem.user.getFullName().equals(newItem.user.getFullName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private final long inviterId;
|
||||
private final OnDirectUserClickListener onClickListener;
|
||||
private final OnDirectUserLongClickListener onLongClickListener;
|
||||
private List<Long> adminUserIds;
|
||||
|
||||
public DirectUsersAdapter(final long inviterId,
|
||||
final OnDirectUserClickListener onClickListener,
|
||||
final OnDirectUserLongClickListener onLongClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.inviterId = inviterId;
|
||||
this.onClickListener = onClickListener;
|
||||
this.onLongClickListener = onLongClickListener;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
public void submitUsers(final List<User> users, final List<User> leftUsers) {
|
||||
if (users == null && leftUsers == null) return;
|
||||
final List<DirectUserOrHeader> userOrHeaders = combineLists(users, leftUsers);
|
||||
submitList(userOrHeaders);
|
||||
}
|
||||
|
||||
private List<DirectUserOrHeader> combineLists(final List<User> users, final List<User> leftUsers) {
|
||||
final ImmutableList.Builder<DirectUserOrHeader> listBuilder = ImmutableList.builder();
|
||||
if (users != null && !users.isEmpty()) {
|
||||
listBuilder.add(new DirectUserOrHeader(R.string.members));
|
||||
users.stream()
|
||||
.map(DirectUserOrHeader::new)
|
||||
.forEach(listBuilder::add);
|
||||
}
|
||||
if (leftUsers != null && !leftUsers.isEmpty()) {
|
||||
listBuilder.add(new DirectUserOrHeader(R.string.dms_left_users));
|
||||
leftUsers.stream()
|
||||
.map(DirectUserOrHeader::new)
|
||||
.forEach(listBuilder::add);
|
||||
}
|
||||
return listBuilder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_USER:
|
||||
final LayoutDmUserItemBinding binding = LayoutDmUserItemBinding.inflate(layoutInflater, parent, false);
|
||||
return new DirectUserViewHolder(binding, onClickListener, onLongClickListener);
|
||||
case VIEW_TYPE_HEADER:
|
||||
default:
|
||||
final ItemFavSectionHeaderBinding headerBinding = ItemFavSectionHeaderBinding.inflate(layoutInflater, parent, false);
|
||||
return new HeaderViewHolder(headerBinding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
|
||||
if (holder instanceof HeaderViewHolder) {
|
||||
((HeaderViewHolder) holder).bind(getItem(position).headerTitle);
|
||||
return;
|
||||
}
|
||||
if (holder instanceof DirectUserViewHolder) {
|
||||
final User user = getItem(position).user;
|
||||
((DirectUserViewHolder) holder).bind(position,
|
||||
user,
|
||||
user != null && adminUserIds != null && adminUserIds.contains(user.getPk()),
|
||||
user != null && user.getPk() == inviterId,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
final DirectUserOrHeader item = getItem(position);
|
||||
return item.isHeader() ? VIEW_TYPE_HEADER : VIEW_TYPE_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
final DirectUserOrHeader item = getItem(position);
|
||||
return item.isHeader() ? item.headerTitle : item.user.getPk();
|
||||
}
|
||||
|
||||
public void setAdminUserIds(final List<Long> adminUserIds) {
|
||||
this.adminUserIds = adminUserIds;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public static class DirectUserOrHeader {
|
||||
int headerTitle;
|
||||
User user;
|
||||
|
||||
public DirectUserOrHeader(final int headerTitle) {
|
||||
this.headerTitle = headerTitle;
|
||||
}
|
||||
|
||||
public DirectUserOrHeader(final User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
boolean isHeader() {
|
||||
return headerTitle > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HeaderViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ItemFavSectionHeaderBinding binding;
|
||||
|
||||
public HeaderViewHolder(@NonNull final ItemFavSectionHeaderBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(@StringRes final int headerTitle) {
|
||||
binding.getRoot().setText(headerTitle);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnDirectUserClickListener {
|
||||
void onClick(int position, User user, boolean selected);
|
||||
}
|
||||
|
||||
public interface OnDirectUserLongClickListener {
|
||||
boolean onLongClick(int position, User user);
|
||||
}
|
||||
}
|
@ -10,7 +10,8 @@ import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.TopicClusterViewHolder;
|
||||
import awais.instagrabber.databinding.ItemDiscoverTopicBinding;
|
||||
import awais.instagrabber.models.TopicCluster;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicCluster;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class DiscoverTopicsAdapter extends ListAdapter<TopicCluster, TopicClusterViewHolder> {
|
||||
private static final DiffUtil.ItemCallback<TopicCluster> DIFF_CALLBACK = new DiffUtil.ItemCallback<TopicCluster>() {
|
||||
@ -21,7 +22,8 @@ public class DiscoverTopicsAdapter extends ListAdapter<TopicCluster, TopicCluste
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final TopicCluster oldItem, @NonNull final TopicCluster newItem) {
|
||||
return oldItem.getCoverMedia().getDisplayUrl().equals(newItem.getCoverMedia().getDisplayUrl())
|
||||
final String oldThumbUrl = ResponseBodyUtils.getThumbUrl(oldItem.getCoverMedia());
|
||||
return oldThumbUrl != null && oldThumbUrl.equals(ResponseBodyUtils.getThumbUrl(newItem.getCoverMedia()))
|
||||
&& oldItem.getTitle().equals(newItem.getTitle());
|
||||
}
|
||||
};
|
||||
@ -38,7 +40,7 @@ public class DiscoverTopicsAdapter extends ListAdapter<TopicCluster, TopicCluste
|
||||
public TopicClusterViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemDiscoverTopicBinding binding = ItemDiscoverTopicBinding.inflate(layoutInflater, parent, false);
|
||||
return new TopicClusterViewHolder(binding, onTopicClickListener);
|
||||
return new TopicClusterViewHolder(binding, onTopicClickListener, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.FeedGridItemViewHolder;
|
||||
@ -22,43 +23,45 @@ import awais.instagrabber.databinding.ItemFeedGridBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedPhotoBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedSliderBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedVideoBinding;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.repositories.responses.Caption;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.ViewHolder> {
|
||||
public final class FeedAdapterV2 extends ListAdapter<Media, RecyclerView.ViewHolder> {
|
||||
private static final String TAG = "FeedAdapterV2";
|
||||
|
||||
private final FeedItemCallback feedItemCallback;
|
||||
private final SelectionModeCallback selectionModeCallback;
|
||||
private final Set<Integer> selectedPositions = new HashSet<>();
|
||||
private final Set<FeedModel> selectedFeedModels = new HashSet<>();
|
||||
private final Set<Media> selectedFeedModels = new HashSet<>();
|
||||
|
||||
private PostsLayoutPreferences layoutPreferences;
|
||||
private boolean selectionModeActive = false;
|
||||
|
||||
|
||||
private static final DiffUtil.ItemCallback<FeedModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<FeedModel>() {
|
||||
private static final DiffUtil.ItemCallback<Media> DIFF_CALLBACK = new DiffUtil.ItemCallback<Media>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
public boolean areItemsTheSame(@NonNull final Media oldItem, @NonNull final Media newItem) {
|
||||
return Objects.equals(oldItem.getPk(), newItem.getPk());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final FeedModel oldItem, @NonNull final FeedModel newItem) {
|
||||
boolean result = oldItem.getPostId().equals(newItem.getPostId());
|
||||
if (TextUtils.isEmpty(oldItem.getPostCaption())) {
|
||||
return result ? TextUtils.isEmpty(newItem.getPostCaption()) : false;
|
||||
}
|
||||
else {
|
||||
return result ? oldItem.getPostCaption().equals(newItem.getPostCaption()) : false;
|
||||
}
|
||||
public boolean areContentsTheSame(@NonNull final Media oldItem, @NonNull final Media newItem) {
|
||||
final Caption oldItemCaption = oldItem.getCaption();
|
||||
final Caption newItemCaption = newItem.getCaption();
|
||||
return Objects.equals(oldItem.getPk(), newItem.getPk())
|
||||
&& Objects.equals(getCaptionText(oldItemCaption), getCaptionText(newItemCaption));
|
||||
}
|
||||
|
||||
private String getCaptionText(final Caption caption) {
|
||||
if (caption == null) return null;
|
||||
return caption.getText();
|
||||
}
|
||||
};
|
||||
private final AdapterSelectionCallback adapterSelectionCallback = new AdapterSelectionCallback() {
|
||||
@Override
|
||||
public boolean onPostLongClick(final int position, final FeedModel feedModel) {
|
||||
public boolean onPostLongClick(final int position, final Media feedModel) {
|
||||
if (!selectionModeActive) {
|
||||
selectionModeActive = true;
|
||||
notifyDataSetChanged();
|
||||
@ -76,7 +79,7 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostClick(final int position, final FeedModel feedModel) {
|
||||
public void onPostClick(final int position, final Media feedModel) {
|
||||
if (!selectionModeActive) return;
|
||||
if (selectedPositions.contains(position)) {
|
||||
selectedPositions.remove(position);
|
||||
@ -147,7 +150,7 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, final int position) {
|
||||
final FeedModel feedModel = getItem(position);
|
||||
final Media feedModel = getItem(position);
|
||||
if (feedModel == null) return;
|
||||
switch (layoutPreferences.getType()) {
|
||||
case LINEAR:
|
||||
@ -168,7 +171,7 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
return getItem(position).getItemType().getId();
|
||||
return getItem(position).getMediaType().getId();
|
||||
}
|
||||
|
||||
public void setLayoutPreferences(@NonNull final PostsLayoutPreferences layoutPreferences) {
|
||||
@ -205,43 +208,43 @@ public final class FeedAdapterV2 extends ListAdapter<FeedModel, RecyclerView.Vie
|
||||
// }
|
||||
|
||||
public interface FeedItemCallback {
|
||||
void onPostClick(final FeedModel feedModel,
|
||||
void onPostClick(final Media feedModel,
|
||||
final View profilePicView,
|
||||
final View mainPostImage);
|
||||
|
||||
void onProfilePicClick(final FeedModel feedModel,
|
||||
void onProfilePicClick(final Media feedModel,
|
||||
final View profilePicView);
|
||||
|
||||
void onNameClick(final FeedModel feedModel,
|
||||
void onNameClick(final Media feedModel,
|
||||
final View profilePicView);
|
||||
|
||||
void onLocationClick(final FeedModel feedModel);
|
||||
void onLocationClick(final Media feedModel);
|
||||
|
||||
void onMentionClick(final String mention);
|
||||
|
||||
void onHashtagClick(final String hashtag);
|
||||
|
||||
void onCommentsClick(final FeedModel feedModel);
|
||||
void onCommentsClick(final Media feedModel);
|
||||
|
||||
void onDownloadClick(final FeedModel feedModel, final int childPosition);
|
||||
void onDownloadClick(final Media feedModel, final int childPosition);
|
||||
|
||||
void onEmailClick(final String emailId);
|
||||
|
||||
void onURLClick(final String url);
|
||||
|
||||
void onSliderClick(FeedModel feedModel, int position);
|
||||
void onSliderClick(Media feedModel, int position);
|
||||
}
|
||||
|
||||
public interface AdapterSelectionCallback {
|
||||
boolean onPostLongClick(final int position, FeedModel feedModel);
|
||||
boolean onPostLongClick(final int position, Media feedModel);
|
||||
|
||||
void onPostClick(final int position, FeedModel feedModel);
|
||||
void onPostClick(final int position, Media feedModel);
|
||||
}
|
||||
|
||||
public interface SelectionModeCallback {
|
||||
void onSelectionStart();
|
||||
|
||||
void onSelectionChange(final Set<FeedModel> selectedFeedModels);
|
||||
void onSelectionChange(final Set<Media> selectedFeedModels);
|
||||
|
||||
void onSelectionEnd();
|
||||
}
|
||||
|
@ -2,20 +2,21 @@ package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
|
||||
public class FeedItemCallbackAdapter implements FeedAdapterV2.FeedItemCallback {
|
||||
@Override
|
||||
public void onPostClick(final FeedModel feedModel, final View profilePicView, final View mainPostImage) {}
|
||||
public void onPostClick(final Media media, final View profilePicView, final View mainPostImage) {}
|
||||
|
||||
@Override
|
||||
public void onProfilePicClick(final FeedModel feedModel, final View profilePicView) {}
|
||||
public void onProfilePicClick(final Media media, final View profilePicView) {}
|
||||
|
||||
@Override
|
||||
public void onNameClick(final FeedModel feedModel, final View profilePicView) {}
|
||||
public void onNameClick(final Media media, final View profilePicView) {}
|
||||
|
||||
@Override
|
||||
public void onLocationClick(final FeedModel feedModel) {}
|
||||
public void onLocationClick(final Media media) {}
|
||||
|
||||
@Override
|
||||
public void onMentionClick(final String mention) {}
|
||||
@ -24,10 +25,10 @@ public class FeedItemCallbackAdapter implements FeedAdapterV2.FeedItemCallback {
|
||||
public void onHashtagClick(final String hashtag) {}
|
||||
|
||||
@Override
|
||||
public void onCommentsClick(final FeedModel feedModel) {}
|
||||
public void onCommentsClick(final Media media) {}
|
||||
|
||||
@Override
|
||||
public void onDownloadClick(final FeedModel feedModel, final int childPosition) {}
|
||||
public void onDownloadClick(final Media media, final int childPosition) {}
|
||||
|
||||
@Override
|
||||
public void onEmailClick(final String emailId) {}
|
||||
@ -36,5 +37,5 @@ public class FeedItemCallbackAdapter implements FeedAdapterV2.FeedItemCallback {
|
||||
public void onURLClick(final String url) {}
|
||||
|
||||
@Override
|
||||
public void onSliderClick(final FeedModel feedModel, final int position) {}
|
||||
public void onSliderClick(final Media media, final int position) {}
|
||||
}
|
||||
|
@ -2,23 +2,46 @@ package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.StoryListViewHolder;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.models.FeedStoryModel;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public final class FeedStoriesListAdapter extends ListAdapter<FeedStoryModel, StoryListViewHolder> {
|
||||
public final class FeedStoriesListAdapter extends ListAdapter<FeedStoryModel, StoryListViewHolder> implements Filterable {
|
||||
private final OnFeedStoryClickListener listener;
|
||||
private List<FeedStoryModel> list;
|
||||
|
||||
private final Filter filter = new Filter() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected FilterResults performFiltering(final CharSequence filter) {
|
||||
final boolean isFilterEmpty = TextUtils.isEmpty(filter);
|
||||
final String query = isFilterEmpty ? null : filter.toString().toLowerCase();
|
||||
|
||||
for (FeedStoryModel item : list) {
|
||||
if (isFilterEmpty) item.setShown(true);
|
||||
else item.setShown(item.getProfileModel().getUsername().toLowerCase().contains(query));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(final CharSequence constraint, final FilterResults results) {
|
||||
submitList(list);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
|
||||
private static final DiffUtil.ItemCallback<FeedStoryModel> diffCallback = new DiffUtil.ItemCallback<FeedStoryModel>() {
|
||||
@Override
|
||||
@ -37,6 +60,17 @@ public final class FeedStoriesListAdapter extends ListAdapter<FeedStoryModel, St
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitList(final List<FeedStoryModel> list) {
|
||||
super.submitList(list.stream().filter(i -> i.isShown()).collect(Collectors.toList()));
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StoryListViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
|
@ -0,0 +1,94 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.FilterViewHolder;
|
||||
import awais.instagrabber.databinding.ItemFilterBinding;
|
||||
import awais.instagrabber.fragments.imageedit.filters.filters.Filter;
|
||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
||||
|
||||
public class FiltersAdapter extends ListAdapter<Filter<?>, FilterViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<Filter<?>> DIFF_CALLBACK = new DiffUtil.ItemCallback<Filter<?>>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final Filter<?> oldItem, @NonNull final Filter<?> newItem) {
|
||||
return oldItem.getType().equals(newItem.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final Filter<?> oldItem, @NonNull final Filter<?> newItem) {
|
||||
return oldItem.getType().equals(newItem.getType());
|
||||
}
|
||||
};
|
||||
|
||||
private final Bitmap bitmap;
|
||||
private final OnFilterClickListener onFilterClickListener;
|
||||
private final Collection<GPUImageFilter> filters;
|
||||
private final String originalKey;
|
||||
private int selectedPosition = 0;
|
||||
|
||||
public FiltersAdapter(final Collection<GPUImageFilter> filters,
|
||||
final String originalKey,
|
||||
final Bitmap bitmap,
|
||||
final OnFilterClickListener onFilterClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.filters = filters;
|
||||
this.originalKey = originalKey;
|
||||
this.bitmap = bitmap;
|
||||
this.onFilterClickListener = onFilterClickListener;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FilterViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemFilterBinding binding = ItemFilterBinding.inflate(layoutInflater, parent, false);
|
||||
return new FilterViewHolder(binding, filters, onFilterClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final FilterViewHolder holder, final int position) {
|
||||
holder.bind(position, originalKey, bitmap, getItem(position), selectedPosition == position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
return getItem(position).getLabel();
|
||||
}
|
||||
|
||||
public void setSelected(final int position) {
|
||||
final int prev = this.selectedPosition;
|
||||
this.selectedPosition = position;
|
||||
notifyItemChanged(position);
|
||||
notifyItemChanged(prev);
|
||||
}
|
||||
|
||||
public void setSelectedFilter(final GPUImageFilter instance) {
|
||||
final List<Filter<?>> currentList = getCurrentList();
|
||||
int index = -1;
|
||||
for (int i = 0; i < currentList.size(); i++) {
|
||||
final Filter<?> filter = currentList.get(i);
|
||||
final GPUImageFilter filterInstance = filter.getInstance();
|
||||
if (filterInstance.getClass() == instance.getClass()) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index < 0) return;
|
||||
setSelected(index);
|
||||
}
|
||||
|
||||
public interface OnFilterClickListener {
|
||||
void onClick(int position, Filter<?> filter);
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
|
||||
import com.facebook.drawee.controller.BaseControllerListener;
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.imagepipeline.common.ResizeOptions;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.databinding.ItemMediaBinding;
|
||||
import awais.instagrabber.repositories.responses.giphy.GiphyGif;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class GifItemsAdapter extends ListAdapter<GiphyGif, GifItemsAdapter.GifViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<GiphyGif> diffCallback = new DiffUtil.ItemCallback<GiphyGif>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final GiphyGif oldItem, @NonNull final GiphyGif newItem) {
|
||||
return Objects.equals(oldItem.getId(), newItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final GiphyGif oldItem, @NonNull final GiphyGif newItem) {
|
||||
return Objects.equals(oldItem.getId(), newItem.getId());
|
||||
}
|
||||
};
|
||||
|
||||
private final OnItemClickListener onItemClickListener;
|
||||
|
||||
public GifItemsAdapter(final OnItemClickListener onItemClickListener) {
|
||||
super(diffCallback);
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GifViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemMediaBinding binding = ItemMediaBinding.inflate(layoutInflater, parent, false);
|
||||
return new GifViewHolder(binding, onItemClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final GifViewHolder holder, final int position) {
|
||||
holder.bind(getItem(position));
|
||||
}
|
||||
|
||||
public static class GifViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = GifViewHolder.class.getSimpleName();
|
||||
private static final int size = Utils.displayMetrics.widthPixels / 3;
|
||||
|
||||
private final ItemMediaBinding binding;
|
||||
private final OnItemClickListener onItemClickListener;
|
||||
|
||||
public GifViewHolder(@NonNull final ItemMediaBinding binding,
|
||||
final OnItemClickListener onItemClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
binding.duration.setVisibility(View.GONE);
|
||||
final GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(itemView.getResources());
|
||||
builder.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER);
|
||||
binding.item.setHierarchy(builder.build());
|
||||
}
|
||||
|
||||
public void bind(final GiphyGif item) {
|
||||
if (onItemClickListener != null) {
|
||||
itemView.setOnClickListener(v -> onItemClickListener.onItemClick(item));
|
||||
}
|
||||
final BaseControllerListener<ImageInfo> controllerListener = new BaseControllerListener<ImageInfo>() {
|
||||
@Override
|
||||
public void onFailure(final String id, final Throwable throwable) {
|
||||
Log.e(TAG, "onFailure: ", throwable);
|
||||
}
|
||||
};
|
||||
final ImageRequest request = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(item.getImages().getFixedHeight().getWebp()))
|
||||
.setResizeOptions(ResizeOptions.forDimensions(size, size))
|
||||
.build();
|
||||
final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(request)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setControllerListener(controllerListener);
|
||||
binding.item.setController(builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(GiphyGif giphyGif);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.dialogs.KeywordsFilterDialogViewHolder;
|
||||
|
||||
public class KeywordsFilterAdapter extends RecyclerView.Adapter<KeywordsFilterDialogViewHolder> {
|
||||
|
||||
private final Context context;
|
||||
private final ArrayList<String> items;
|
||||
|
||||
public KeywordsFilterAdapter(Context context, ArrayList<String> items){
|
||||
this.context = context;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public KeywordsFilterDialogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
final View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_keyword, parent, false);
|
||||
return new KeywordsFilterDialogViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull KeywordsFilterDialogViewHolder holder, int position) {
|
||||
holder.bind(items, position, context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -12,13 +11,13 @@ import java.util.List;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.FollowsViewHolder;
|
||||
import awais.instagrabber.databinding.ItemFollowBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public final class LikesAdapter extends RecyclerView.Adapter<FollowsViewHolder> {
|
||||
private final List<ProfileModel> profileModels;
|
||||
private final List<User> profileModels;
|
||||
private final View.OnClickListener onClickListener;
|
||||
|
||||
public LikesAdapter(final List<ProfileModel> profileModels,
|
||||
public LikesAdapter(final List<User> profileModels,
|
||||
final View.OnClickListener onClickListener) {
|
||||
this.profileModels = profileModels;
|
||||
this.onClickListener = onClickListener;
|
||||
@ -34,7 +33,7 @@ public final class LikesAdapter extends RecyclerView.Adapter<FollowsViewHolder>
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final FollowsViewHolder holder, final int position) {
|
||||
final ProfileModel model = profileModels.get(position);
|
||||
final User model = profileModels.get(position);
|
||||
holder.bind(model, null, onClickListener);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,111 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
|
||||
import com.facebook.drawee.controller.BaseControllerListener;
|
||||
import com.facebook.imagepipeline.common.ResizeOptions;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import awais.instagrabber.databinding.ItemMediaBinding;
|
||||
import awais.instagrabber.utils.MediaController.MediaEntry;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class MediaItemsAdapter extends ListAdapter<MediaEntry, MediaItemsAdapter.MediaItemViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<MediaEntry> diffCallback = new DiffUtil.ItemCallback<MediaEntry>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final MediaEntry oldItem, @NonNull final MediaEntry newItem) {
|
||||
return oldItem.imageId == newItem.imageId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final MediaEntry oldItem, @NonNull final MediaEntry newItem) {
|
||||
return oldItem.imageId == newItem.imageId;
|
||||
}
|
||||
};
|
||||
|
||||
private final OnItemClickListener onItemClickListener;
|
||||
|
||||
public MediaItemsAdapter(final OnItemClickListener onItemClickListener) {
|
||||
super(diffCallback);
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MediaItemViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemMediaBinding binding = ItemMediaBinding.inflate(layoutInflater, parent, false);
|
||||
return new MediaItemViewHolder(binding, onItemClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final MediaItemViewHolder holder, final int position) {
|
||||
holder.bind(getItem(position));
|
||||
}
|
||||
|
||||
public static class MediaItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = MediaItemViewHolder.class.getSimpleName();
|
||||
private static final int size = Utils.displayMetrics.widthPixels / 3;
|
||||
|
||||
private final ItemMediaBinding binding;
|
||||
private final OnItemClickListener onItemClickListener;
|
||||
|
||||
public MediaItemViewHolder(@NonNull final ItemMediaBinding binding,
|
||||
final OnItemClickListener onItemClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
public void bind(final MediaEntry item) {
|
||||
final Uri uri = Uri.fromFile(new File(item.path));
|
||||
if (onItemClickListener != null) {
|
||||
itemView.setOnClickListener(v -> onItemClickListener.onItemClick(item));
|
||||
}
|
||||
final BaseControllerListener<ImageInfo> controllerListener = new BaseControllerListener<ImageInfo>() {
|
||||
@Override
|
||||
public void onFailure(final String id, final Throwable throwable) {
|
||||
Log.e(TAG, "onFailure: ", throwable);
|
||||
}
|
||||
};
|
||||
final ImageRequest request = ImageRequestBuilder
|
||||
.newBuilderWithSource(uri)
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(false)
|
||||
.setResizeOptions(ResizeOptions.forDimensions(size, size))
|
||||
.build();
|
||||
final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(request)
|
||||
.setControllerListener(controllerListener);
|
||||
binding.item.setController(builder.build());
|
||||
if (item.isVideo && item.duration >= 0) {
|
||||
final String timeString = TextUtils.millisToTimeString(item.duration);
|
||||
binding.duration.setVisibility(View.VISIBLE);
|
||||
binding.duration.setText(timeString);
|
||||
} else {
|
||||
binding.duration.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(MediaEntry entry);
|
||||
}
|
||||
}
|
@ -11,34 +11,31 @@ import androidx.recyclerview.widget.ListAdapter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.NotificationViewHolder;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.NotificationModel;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
|
||||
public final class NotificationsAdapter extends ListAdapter<NotificationModel, NotificationViewHolder> {
|
||||
public final class NotificationsAdapter extends ListAdapter<Notification, NotificationViewHolder> {
|
||||
private final OnNotificationClickListener notificationClickListener;
|
||||
private final MentionClickListener mentionClickListener;
|
||||
|
||||
private static final DiffUtil.ItemCallback<NotificationModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<NotificationModel>() {
|
||||
private static final DiffUtil.ItemCallback<Notification> DIFF_CALLBACK = new DiffUtil.ItemCallback<Notification>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final NotificationModel oldItem, @NonNull final NotificationModel newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
public boolean areItemsTheSame(@NonNull final Notification oldItem, @NonNull final Notification newItem) {
|
||||
return oldItem.getPk().equals(newItem.getPk());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final NotificationModel oldItem, @NonNull final NotificationModel newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
public boolean areContentsTheSame(@NonNull final Notification oldItem, @NonNull final Notification newItem) {
|
||||
return oldItem.getPk().equals(newItem.getPk());
|
||||
}
|
||||
};
|
||||
|
||||
public NotificationsAdapter(final OnNotificationClickListener notificationClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
public NotificationsAdapter(final OnNotificationClickListener notificationClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.notificationClickListener = notificationClickListener;
|
||||
this.mentionClickListener = mentionClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -51,12 +48,12 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final NotificationViewHolder holder, final int position) {
|
||||
final NotificationModel notificationModel = getItem(position);
|
||||
holder.bind(notificationModel, notificationClickListener);
|
||||
final Notification Notification = getItem(position);
|
||||
holder.bind(Notification, notificationClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitList(@Nullable final List<NotificationModel> list, @Nullable final Runnable commitCallback) {
|
||||
public void submitList(@Nullable final List<Notification> list, @Nullable final Runnable commitCallback) {
|
||||
if (list == null) {
|
||||
super.submitList(null, commitCallback);
|
||||
return;
|
||||
@ -65,7 +62,7 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitList(@Nullable final List<NotificationModel> list) {
|
||||
public void submitList(@Nullable final List<Notification> list) {
|
||||
if (list == null) {
|
||||
super.submitList(null);
|
||||
return;
|
||||
@ -73,8 +70,10 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
|
||||
super.submitList(sort(list));
|
||||
}
|
||||
|
||||
private List<NotificationModel> sort(final List<NotificationModel> list) {
|
||||
final List<NotificationModel> listCopy = new ArrayList<>(list);
|
||||
private List<Notification> sort(final List<Notification> list) {
|
||||
final List<Notification> listCopy = new ArrayList<>(list).stream()
|
||||
.filter(i -> i.getType() != null)
|
||||
.collect(Collectors.toList());
|
||||
Collections.sort(listCopy, (o1, o2) -> {
|
||||
// keep requests at top
|
||||
if (o1.getType() == o2.getType()
|
||||
@ -83,16 +82,16 @@ public final class NotificationsAdapter extends ListAdapter<NotificationModel, N
|
||||
else if (o1.getType() == NotificationType.REQUEST) return -1;
|
||||
else if (o2.getType() == NotificationType.REQUEST) return 1;
|
||||
// timestamp
|
||||
return o1.getTimestamp() > o2.getTimestamp() ? -1 : (o1.getTimestamp() == o2.getTimestamp() ? 0 : 1);
|
||||
return Double.compare(o2.getArgs().getTimestamp(), o1.getArgs().getTimestamp());
|
||||
});
|
||||
return listCopy;
|
||||
}
|
||||
|
||||
public interface OnNotificationClickListener {
|
||||
void onNotificationClick(final NotificationModel model);
|
||||
void onNotificationClick(final Notification model);
|
||||
|
||||
void onProfileClick(final String username);
|
||||
|
||||
void onPreviewClick(final NotificationModel model);
|
||||
void onPreviewClick(final Notification model);
|
||||
}
|
||||
}
|
@ -1,206 +0,0 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
import awais.instagrabber.customviews.drawee.ZoomableDraweeView;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class PostViewerChildAdapter extends ListAdapter<ViewerPostModel, PostViewerChildAdapter.ChildViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<ViewerPostModel> diffCallback = new DiffUtil.ItemCallback<ViewerPostModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final ViewerPostModel oldItem, @NonNull final ViewerPostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId()) && oldItem.getShortCode().equals(newItem.getShortCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final ViewerPostModel oldItem, @NonNull final ViewerPostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId()) && oldItem.getShortCode().equals(newItem.getShortCode());
|
||||
}
|
||||
};
|
||||
|
||||
public PostViewerChildAdapter() {
|
||||
super(diffCallback);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ChildViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
// final AppCompatTextView textView = new AppCompatTextView(parent.getContext());
|
||||
// textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
// return new ChildViewHolder(textView);
|
||||
final MediaItemType mediaItemType = MediaItemType.valueOf(viewType);
|
||||
if (mediaItemType == null) return getPlaceholder(parent);
|
||||
switch (mediaItemType) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
return getImageViewHolder(parent);
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
return getVideoViewHolder(parent);
|
||||
default:
|
||||
return getPlaceholder(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private ChildViewHolder getImageViewHolder(final ViewGroup parent) {
|
||||
final ZoomableDraweeView view = new ZoomableDraweeView(parent.getContext());
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
return new ChildViewHolder(view);
|
||||
}
|
||||
|
||||
private ChildViewHolder getVideoViewHolder(final ViewGroup parent) {
|
||||
final PlayerView view = new PlayerView(parent.getContext());
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
return new ChildViewHolder(view);
|
||||
}
|
||||
|
||||
private ChildViewHolder getPlaceholder(final ViewGroup parent) {
|
||||
final AppCompatTextView textView = new AppCompatTextView(parent.getContext());
|
||||
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
textView.setGravity(Gravity.CENTER);
|
||||
textView.setText("Placeholder");
|
||||
return new ChildViewHolder(textView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final ChildViewHolder holder, final int position) {
|
||||
holder.bind(getItem(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
final ViewerPostModel item = getItem(position);
|
||||
return item.getItemType().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(@NonNull final ChildViewHolder holder) {
|
||||
if (holder.itemView instanceof PlayerView) {
|
||||
final Player player = ((PlayerView) holder.itemView).getPlayer();
|
||||
if (player != null) {
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull final ChildViewHolder holder) {
|
||||
if (holder.itemView instanceof PlayerView) {
|
||||
final Player player = ((PlayerView) holder.itemView).getPlayer();
|
||||
if (player != null) {
|
||||
player.release();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (holder.itemView instanceof ZoomableDraweeView) {
|
||||
((ZoomableDraweeView) holder.itemView).setController(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ChildViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ChildViewHolder(@NonNull final View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public void bind(final ViewerPostModel item) {
|
||||
final MediaItemType mediaItemType = item.getItemType();
|
||||
switch (mediaItemType) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
bindImage(item);
|
||||
break;
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
bindVideo(item);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private void bindImage(final ViewerPostModel item) {
|
||||
final ZoomableDraweeView imageView = (ZoomableDraweeView) itemView;
|
||||
imageView.setController(null);
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(item.getDisplayUrl()))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
final DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(requestBuilder)
|
||||
.setOldController(imageView.getController())
|
||||
// .setControllerListener(new BaseControllerListener<ImageInfo>() {
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(final String id, final Throwable throwable) {
|
||||
// // viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFinalImageSet(final String id, final ImageInfo imageInfo, final Animatable animatable) {
|
||||
// // viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
// })
|
||||
.build();
|
||||
imageView.setController(controller);
|
||||
}
|
||||
|
||||
private void bindVideo(final ViewerPostModel item) {
|
||||
final SimpleExoPlayer player = new SimpleExoPlayer.Builder(itemView.getContext()).build();
|
||||
final PlayerView playerView = (PlayerView) itemView;
|
||||
playerView.setPlayer(player);
|
||||
float vol = Utils.settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
if (vol == 0f && Utils.sessionVolumeFull) vol = 1f;
|
||||
player.setVolume(vol);
|
||||
player.setPlayWhenReady(Utils.settingsHelper.getBoolean(Constants.AUTOPLAY_VIDEOS));
|
||||
final ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(
|
||||
new DefaultDataSourceFactory(itemView.getContext(), "instagram")
|
||||
).createMediaSource(MediaItem.fromUri(item.getDisplayUrl()));
|
||||
// mediaSource.addEventListener(new Handler(), new MediaSourceEventListener() {
|
||||
// @Override
|
||||
// public void onLoadCompleted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
// viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLoadStarted(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
// viewerBinding.progressView.setVisibility(View.VISIBLE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLoadCanceled(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||
// viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLoadError(final int windowIndex, @Nullable final MediaSource.MediaPeriodId mediaPeriodId, final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData, final IOException error, final boolean wasCanceled) {
|
||||
// viewerBinding.progressView.setVisibility(View.GONE);
|
||||
// }
|
||||
// });
|
||||
player.setMediaSource(mediaSource);
|
||||
player.prepare();
|
||||
player.setVolume(vol);
|
||||
// viewerBinding.bottomPanel.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24);
|
||||
// viewerBinding.bottomPanel.btnMute.setOnClickListener(onClickListener);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.PostViewHolder;
|
||||
import awais.instagrabber.databinding.ItemPostBinding;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
|
||||
public final class PostsAdapter extends MultiSelectListAdapter<PostModel, PostViewHolder> {
|
||||
|
||||
private static final DiffUtil.ItemCallback<PostModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<PostModel>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final PostModel oldItem, @NonNull final PostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final PostModel oldItem, @NonNull final PostModel newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
}
|
||||
};
|
||||
|
||||
public PostsAdapter(final OnItemClickListener<PostModel> clickListener,
|
||||
final OnItemLongClickListener<PostModel> longClickListener) {
|
||||
super(DIFF_CALLBACK, clickListener, longClickListener);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PostViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemPostBinding binding = ItemPostBinding.inflate(layoutInflater, parent, false);
|
||||
return new PostViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final PostViewHolder holder, final int position) {
|
||||
final PostModel postModel = getItem(position);
|
||||
holder.bind(postModel, position, getInternalOnItemClickListener(), getInternalOnLongItemClickListener());
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.viewholder.PostMediaViewHolder;
|
||||
import awais.instagrabber.databinding.ItemChildPostBinding;
|
||||
import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
|
||||
public final class PostsMediaAdapter extends RecyclerView.Adapter<PostMediaViewHolder> {
|
||||
private final View.OnClickListener clickListener;
|
||||
private ViewerPostModel[] postModels;
|
||||
|
||||
public PostsMediaAdapter(final ViewerPostModel[] postModels, final View.OnClickListener clickListener) {
|
||||
this.postModels = postModels;
|
||||
this.clickListener = clickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PostMediaViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
layoutInflater.inflate(R.layout.item_child_post, parent, false);
|
||||
final ItemChildPostBinding binding = ItemChildPostBinding.inflate(layoutInflater, parent, false);
|
||||
return new PostMediaViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final PostMediaViewHolder holder, final int position) {
|
||||
final ViewerPostModel postModel = postModels[position];
|
||||
holder.bind(postModel, position, clickListener);
|
||||
}
|
||||
|
||||
public void setData(final ViewerPostModel[] postModels) {
|
||||
this.postModels = postModels;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public ViewerPostModel getItemAt(final int position) {
|
||||
return postModels == null ? null : postModels[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return postModels == null ? 0 : postModels.length;
|
||||
}
|
||||
|
||||
public BasePostModel[] getPostModels() {
|
||||
return postModels;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import awais.instagrabber.adapters.viewholder.TopicClusterViewHolder;
|
||||
import awais.instagrabber.databinding.ItemDiscoverTopicBinding;
|
||||
import awais.instagrabber.repositories.responses.saved.SavedCollection;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class SavedCollectionsAdapter extends ListAdapter<SavedCollection, TopicClusterViewHolder> {
|
||||
private static final DiffUtil.ItemCallback<SavedCollection> DIFF_CALLBACK = new DiffUtil.ItemCallback<SavedCollection>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final SavedCollection oldItem, @NonNull final SavedCollection newItem) {
|
||||
return oldItem.getId().equals(newItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final SavedCollection oldItem, @NonNull final SavedCollection newItem) {
|
||||
if (oldItem.getCoverMedias() != null && newItem.getCoverMedias() != null
|
||||
&& oldItem.getCoverMedias().size() == newItem.getCoverMedias().size()) {
|
||||
return oldItem.getCoverMedias().get(0).getId().equals(newItem.getCoverMedias().get(0).getId());
|
||||
}
|
||||
else if (oldItem.getCoverMedia() != null && newItem.getCoverMedia() != null) {
|
||||
return oldItem.getCoverMedia().getId().equals(newItem.getCoverMedia().getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private final OnCollectionClickListener onCollectionClickListener;
|
||||
|
||||
public SavedCollectionsAdapter(final OnCollectionClickListener onCollectionClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.onCollectionClickListener = onCollectionClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TopicClusterViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final ItemDiscoverTopicBinding binding = ItemDiscoverTopicBinding.inflate(layoutInflater, parent, false);
|
||||
return new TopicClusterViewHolder(binding, null, onCollectionClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final TopicClusterViewHolder holder, final int position) {
|
||||
final SavedCollection topicCluster = getItem(position);
|
||||
holder.bind(topicCluster);
|
||||
}
|
||||
|
||||
public interface OnCollectionClickListener {
|
||||
void onCollectionClick(SavedCollection savedCollection, View root, View cover, View title, int titleColor, int backgroundColor);
|
||||
}
|
||||
}
|
@ -12,4 +12,7 @@ public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback
|
||||
|
||||
@Override
|
||||
public void onPlayerPause(final int position) {}
|
||||
|
||||
@Override
|
||||
public void onPlayerRelease(final int position) {}
|
||||
}
|
||||
|
@ -14,25 +14,25 @@ import awais.instagrabber.customviews.VerticalDragHelper;
|
||||
import awais.instagrabber.databinding.ItemSliderPhotoBinding;
|
||||
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding;
|
||||
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
|
||||
import awais.instagrabber.models.PostChild;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemViewHolder> {
|
||||
public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewHolder> {
|
||||
|
||||
private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener;
|
||||
private final boolean loadVideoOnItemClick;
|
||||
private final SliderCallback sliderCallback;
|
||||
private final LayoutExoCustomControlsBinding controlsBinding;
|
||||
|
||||
private static final DiffUtil.ItemCallback<PostChild> DIFF_CALLBACK = new DiffUtil.ItemCallback<PostChild>() {
|
||||
private static final DiffUtil.ItemCallback<Media> DIFF_CALLBACK = new DiffUtil.ItemCallback<Media>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final PostChild oldItem, @NonNull final PostChild newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
public boolean areItemsTheSame(@NonNull final Media oldItem, @NonNull final Media newItem) {
|
||||
return oldItem.getPk().equals(newItem.getPk());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final PostChild oldItem, @NonNull final PostChild newItem) {
|
||||
return oldItem.getPostId().equals(newItem.getPostId());
|
||||
public boolean areContentsTheSame(@NonNull final Media oldItem, @NonNull final Media newItem) {
|
||||
return oldItem.getPk().equals(newItem.getPk());
|
||||
}
|
||||
};
|
||||
|
||||
@ -66,14 +66,14 @@ public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemV
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final SliderItemViewHolder holder, final int position) {
|
||||
final PostChild model = getItem(position);
|
||||
holder.bind(model, position, sliderCallback);
|
||||
final Media media = getItem(position);
|
||||
holder.bind(media, position, sliderCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
final PostChild viewerPostModel = getItem(position);
|
||||
return viewerPostModel.getItemType().getId();
|
||||
final Media media = getItem(position);
|
||||
return media.getMediaType().getId();
|
||||
}
|
||||
|
||||
// @NonNull
|
||||
@ -148,5 +148,7 @@ public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemV
|
||||
void onPlayerPlay(int position);
|
||||
|
||||
void onPlayerPause(int position);
|
||||
|
||||
void onPlayerRelease(int position);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,151 @@
|
||||
package awais.instagrabber.adapters;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import awais.instagrabber.adapters.DirectUsersAdapter.OnDirectUserClickListener;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectUserViewHolder;
|
||||
import awais.instagrabber.adapters.viewholder.directmessages.RecipientThreadViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
||||
|
||||
public final class UserSearchResultsAdapter extends ListAdapter<RankedRecipient, RecyclerView.ViewHolder> {
|
||||
private static final int VIEW_TYPE_USER = 0;
|
||||
private static final int VIEW_TYPE_THREAD = 1;
|
||||
private static final DiffUtil.ItemCallback<RankedRecipient> DIFF_CALLBACK = new DiffUtil.ItemCallback<RankedRecipient>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull final RankedRecipient oldItem, @NonNull final RankedRecipient newItem) {
|
||||
final boolean bothUsers = oldItem.getUser() != null && newItem.getUser() != null;
|
||||
if (!bothUsers) return false;
|
||||
final boolean bothThreads = oldItem.getThread() != null && newItem.getThread() != null;
|
||||
if (!bothThreads) return false;
|
||||
if (bothUsers) {
|
||||
return oldItem.getUser().getPk() == newItem.getUser().getPk();
|
||||
}
|
||||
return Objects.equals(oldItem.getThread().getThreadId(), newItem.getThread().getThreadId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull final RankedRecipient oldItem, @NonNull final RankedRecipient newItem) {
|
||||
final boolean bothUsers = oldItem.getUser() != null && newItem.getUser() != null;
|
||||
if (bothUsers) {
|
||||
return Objects.equals(oldItem.getUser().getUsername(), newItem.getUser().getUsername()) &&
|
||||
Objects.equals(oldItem.getUser().getFullName(), newItem.getUser().getFullName());
|
||||
}
|
||||
return Objects.equals(oldItem.getThread().getThreadTitle(), newItem.getThread().getThreadTitle());
|
||||
}
|
||||
};
|
||||
|
||||
private final boolean showSelection;
|
||||
private final Set<RankedRecipient> selectedRecipients;
|
||||
private final OnDirectUserClickListener onUserClickListener;
|
||||
private final OnRecipientClickListener onRecipientClickListener;
|
||||
|
||||
public UserSearchResultsAdapter(final boolean showSelection,
|
||||
final OnRecipientClickListener onRecipientClickListener) {
|
||||
super(DIFF_CALLBACK);
|
||||
this.showSelection = showSelection;
|
||||
selectedRecipients = showSelection ? new HashSet<>() : null;
|
||||
this.onRecipientClickListener = onRecipientClickListener;
|
||||
this.onUserClickListener = (position, user, selected) -> {
|
||||
if (onRecipientClickListener != null) {
|
||||
onRecipientClickListener.onClick(position, RankedRecipient.of(user), selected);
|
||||
}
|
||||
};
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
final LayoutDmUserItemBinding binding = LayoutDmUserItemBinding.inflate(layoutInflater, parent, false);
|
||||
if (viewType == VIEW_TYPE_USER) {
|
||||
return new DirectUserViewHolder(binding, onUserClickListener, null);
|
||||
}
|
||||
return new RecipientThreadViewHolder(binding, onRecipientClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
|
||||
final RankedRecipient recipient = getItem(position);
|
||||
final int itemViewType = getItemViewType(position);
|
||||
if (itemViewType == VIEW_TYPE_USER) {
|
||||
boolean isSelected = false;
|
||||
if (selectedRecipients != null) {
|
||||
isSelected = selectedRecipients.stream()
|
||||
.anyMatch(rankedRecipient -> rankedRecipient.getUser() != null
|
||||
&& rankedRecipient.getUser().getPk() == recipient.getUser().getPk());
|
||||
}
|
||||
((DirectUserViewHolder) holder).bind(position, recipient.getUser(), false, false, showSelection, isSelected);
|
||||
return;
|
||||
}
|
||||
boolean isSelected = false;
|
||||
if (selectedRecipients != null) {
|
||||
isSelected = selectedRecipients.stream()
|
||||
.anyMatch(rankedRecipient -> rankedRecipient.getThread() != null
|
||||
&& Objects.equals(rankedRecipient.getThread().getThreadId(), recipient.getThread().getThreadId()));
|
||||
}
|
||||
((RecipientThreadViewHolder) holder).bind(position, recipient.getThread(), showSelection, isSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
final RankedRecipient recipient = getItem(position);
|
||||
if (recipient.getUser() != null) {
|
||||
return recipient.getUser().getPk();
|
||||
}
|
||||
if (recipient.getThread() != null) {
|
||||
return recipient.getThread().getThreadTitle().hashCode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(final int position) {
|
||||
final RankedRecipient recipient = getItem(position);
|
||||
return recipient.getUser() != null ? VIEW_TYPE_USER : VIEW_TYPE_THREAD;
|
||||
}
|
||||
|
||||
public void setSelectedRecipient(final RankedRecipient recipient, final boolean selected) {
|
||||
if (selectedRecipients == null || recipient == null || (recipient.getUser() == null && recipient.getThread() == null)) return;
|
||||
final boolean isUser = recipient.getUser() != null;
|
||||
int position = -1;
|
||||
final List<RankedRecipient> currentList = getCurrentList();
|
||||
for (int i = 0; i < currentList.size(); i++) {
|
||||
final RankedRecipient temp = currentList.get(i);
|
||||
if (isUser) {
|
||||
if (temp.getUser() != null && temp.getUser().getPk() == recipient.getUser().getPk()) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (temp.getThread() != null && Objects.equals(temp.getThread().getThreadId(), recipient.getThread().getThreadId())) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (position < 0) return;
|
||||
if (selected) {
|
||||
selectedRecipients.add(recipient);
|
||||
} else {
|
||||
selectedRecipients.remove(recipient);
|
||||
}
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
public interface OnRecipientClickListener {
|
||||
void onClick(int position, RankedRecipient recipient, final boolean isSelected);
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.common.ResizeOptions;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.direct_messages.InboxThreadModel;
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
|
||||
public final class DirectMessageInboxItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private final LinearLayout multipleProfilePicsContainer;
|
||||
private final SimpleDraweeView[] multipleProfilePics;
|
||||
private final LayoutDmInboxItemBinding binding;
|
||||
|
||||
public DirectMessageInboxItemViewHolder(@NonNull final LayoutDmInboxItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
multipleProfilePicsContainer = binding.multiPicContainer;
|
||||
final LinearLayout containerChild = (LinearLayout) multipleProfilePicsContainer.getChildAt(1);
|
||||
multipleProfilePics = new SimpleDraweeView[]{
|
||||
(SimpleDraweeView) multipleProfilePicsContainer.getChildAt(0),
|
||||
(SimpleDraweeView) containerChild.getChildAt(0),
|
||||
(SimpleDraweeView) containerChild.getChildAt(1)
|
||||
};
|
||||
binding.tvDate.setSelected(true);
|
||||
binding.tvUsername.setSelected(true);
|
||||
}
|
||||
|
||||
public void bind(final InboxThreadModel model) {
|
||||
final DirectItemModel[] itemModels;
|
||||
if (model == null || (itemModels = model.getItems()) == null) {
|
||||
return;
|
||||
}
|
||||
itemView.setTag(model);
|
||||
final ProfileModel[] users = model.getUsers();
|
||||
if (users.length > 1) {
|
||||
binding.ivProfilePic.setVisibility(View.GONE);
|
||||
multipleProfilePicsContainer.setVisibility(View.VISIBLE);
|
||||
for (int i = 0; i < Math.min(3, users.length); ++i) {
|
||||
multipleProfilePics[i].setImageURI(users[i].getSdProfilePic());
|
||||
}
|
||||
} else {
|
||||
final String uriString = users.length == 1 ? users[0].getSdProfilePic() : null;
|
||||
if (uriString == null) {
|
||||
binding.ivProfilePic.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.ivProfilePic.setVisibility(View.VISIBLE);
|
||||
multipleProfilePicsContainer.setVisibility(View.GONE);
|
||||
final ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uriString))
|
||||
.setResizeOptions(new ResizeOptions(50, 50))
|
||||
.build();
|
||||
binding.ivProfilePic.setController(
|
||||
Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding.ivProfilePic.getController())
|
||||
.setImageRequest(request)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
binding.tvUsername.setText(model.getThreadTitle());
|
||||
final int length = itemModels.length;
|
||||
DirectItemModel lastItemModel = null;
|
||||
if (length != 0) {
|
||||
lastItemModel = itemModels[length - 1];
|
||||
}
|
||||
if (lastItemModel == null) {
|
||||
return;
|
||||
}
|
||||
final DirectItemType itemType = lastItemModel.getItemType();
|
||||
// binding.notTextType.setVisibility(itemType != DirectItemType.TEXT ? View.VISIBLE : View.GONE);
|
||||
final Context context = itemView.getContext();
|
||||
final CharSequence messageText;
|
||||
switch (itemType) {
|
||||
case TEXT:
|
||||
case LIKE:
|
||||
messageText = lastItemModel.getText();
|
||||
break;
|
||||
case LINK:
|
||||
messageText = context.getString(R.string.direct_messages_sent_link);
|
||||
break;
|
||||
case MEDIA:
|
||||
case MEDIA_SHARE:
|
||||
case RAVEN_MEDIA:
|
||||
case CLIP:
|
||||
case FELIX_SHARE:
|
||||
messageText = context.getString(R.string.direct_messages_sent_media);
|
||||
break;
|
||||
case ACTION_LOG:
|
||||
final DirectItemModel.DirectItemActionLogModel logModel = lastItemModel.getActionLogModel();
|
||||
messageText = logModel != null ? logModel.getDescription() : "...";
|
||||
break;
|
||||
case REEL_SHARE:
|
||||
final DirectItemModel.DirectItemReelShareModel reelShare = lastItemModel.getReelShare();
|
||||
if (reelShare == null)
|
||||
messageText = context.getString(R.string.direct_messages_sent_media);
|
||||
else {
|
||||
final String reelType = reelShare.getType();
|
||||
final int textRes;
|
||||
if ("reply".equals(reelType))
|
||||
textRes = R.string.direct_messages_replied_story;
|
||||
else if ("mention".equals(reelType))
|
||||
textRes = R.string.direct_messages_mention_story;
|
||||
else if ("reaction".equals(reelType))
|
||||
textRes = R.string.direct_messages_reacted_story;
|
||||
else textRes = R.string.direct_messages_sent_media;
|
||||
|
||||
messageText = context.getString(textRes) + " : " + reelShare.getText();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
messageText = "<i>Unsupported message</i>";
|
||||
}
|
||||
binding.tvComment.setText(HtmlCompat.fromHtml(messageText.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT));
|
||||
binding.tvDate.setText(lastItemModel.getDateTime());
|
||||
binding.unread.setVisibility(model.getUnreadCount() > 0L ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;
|
||||
import com.facebook.imagepipeline.common.ResizeOptions;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
@ -20,9 +21,10 @@ import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.FeedAdapterV2;
|
||||
import awais.instagrabber.asyncs.DownloadedCheckerAsyncTask;
|
||||
import awais.instagrabber.databinding.ItemFeedGridBinding;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.PostChild;
|
||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static awais.instagrabber.models.PostsLayoutPreferences.PostsLayoutType.STAGGERED_GRID;
|
||||
@ -36,7 +38,7 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
|
||||
public void bind(final int position,
|
||||
@NonNull final FeedModel feedModel,
|
||||
@NonNull final Media media,
|
||||
@NonNull final PostsLayoutPreferences layoutPreferences,
|
||||
final FeedAdapterV2.FeedItemCallback feedItemCallback,
|
||||
final FeedAdapterV2.AdapterSelectionCallback adapterSelectionCallback,
|
||||
@ -44,28 +46,121 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder {
|
||||
final boolean selected) {
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (!selectionModeActive && feedItemCallback != null) {
|
||||
feedItemCallback.onPostClick(feedModel, binding.profilePic, binding.postImage);
|
||||
feedItemCallback.onPostClick(media, binding.profilePic, binding.postImage);
|
||||
return;
|
||||
}
|
||||
if (selectionModeActive && adapterSelectionCallback != null) {
|
||||
adapterSelectionCallback.onPostClick(position, feedModel);
|
||||
adapterSelectionCallback.onPostClick(position, media);
|
||||
}
|
||||
});
|
||||
if (adapterSelectionCallback != null) {
|
||||
itemView.setOnLongClickListener(v -> adapterSelectionCallback.onPostLongClick(position, feedModel));
|
||||
itemView.setOnLongClickListener(v -> adapterSelectionCallback.onPostLongClick(position, media));
|
||||
}
|
||||
binding.selectedView.setVisibility(selected ? View.VISIBLE : View.GONE);
|
||||
// for rounded borders (clip view to background shape)
|
||||
itemView.setClipToOutline(layoutPreferences.getHasRoundedCorners());
|
||||
if (layoutPreferences.getType() == STAGGERED_GRID) {
|
||||
final float aspectRatio = (float) feedModel.getImageWidth() / feedModel.getImageHeight();
|
||||
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
|
||||
binding.postImage.setAspectRatio(aspectRatio);
|
||||
} else {
|
||||
binding.postImage.setAspectRatio(1);
|
||||
}
|
||||
setUserDetails(media, layoutPreferences);
|
||||
String thumbnailUrl = null;
|
||||
final int typeIconRes;
|
||||
switch (media.getMediaType()) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
typeIconRes = -1;
|
||||
thumbnailUrl = ResponseBodyUtils.getThumbUrl(media);
|
||||
break;
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
thumbnailUrl = ResponseBodyUtils.getThumbUrl(media);
|
||||
typeIconRes = R.drawable.exo_icon_play;
|
||||
break;
|
||||
case MEDIA_TYPE_SLIDER:
|
||||
final List<Media> sliderItems = media.getCarouselMedia();
|
||||
if (sliderItems != null) {
|
||||
final Media child = sliderItems.get(0);
|
||||
if (child != null) {
|
||||
thumbnailUrl = ResponseBodyUtils.getThumbUrl(child);
|
||||
if (layoutPreferences.getType() == STAGGERED_GRID) {
|
||||
final float childAspectRatio = (float) child.getOriginalWidth() / child.getOriginalHeight();
|
||||
binding.postImage.setAspectRatio(childAspectRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
typeIconRes = R.drawable.ic_checkbox_multiple_blank_stroke;
|
||||
break;
|
||||
default:
|
||||
typeIconRes = -1;
|
||||
thumbnailUrl = null;
|
||||
}
|
||||
setThumbImage(thumbnailUrl);
|
||||
if (typeIconRes <= 0) {
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.typeIcon.setVisibility(View.VISIBLE);
|
||||
binding.typeIcon.setImageResource(typeIconRes);
|
||||
}
|
||||
final DownloadedCheckerAsyncTask task = new DownloadedCheckerAsyncTask(result -> {
|
||||
final List<Boolean> checkList = result.get(media.getPk());
|
||||
if (checkList == null || checkList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
switch (media.getMediaType()) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
binding.downloaded.setVisibility(checkList.get(0) ? View.VISIBLE : View.GONE);
|
||||
binding.downloaded.setImageTintList(ColorStateList.valueOf(itemView.getResources().getColor(R.color.green_A400)));
|
||||
break;
|
||||
case MEDIA_TYPE_SLIDER:
|
||||
binding.downloaded.setVisibility(checkList.get(0) ? View.VISIBLE : View.GONE);
|
||||
final List<Media> carouselMedia = media.getCarouselMedia();
|
||||
boolean allDownloaded = checkList.size() == (carouselMedia == null ? 0 : carouselMedia.size());
|
||||
if (allDownloaded) {
|
||||
allDownloaded = checkList.stream().allMatch(downloaded -> downloaded);
|
||||
}
|
||||
binding.downloaded.setImageTintList(ColorStateList.valueOf(itemView.getResources().getColor(
|
||||
allDownloaded ? R.color.green_A400 : R.color.yellow_400)));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
task.execute(media);
|
||||
}
|
||||
|
||||
private void setThumbImage(final String thumbnailUrl) {
|
||||
if (TextUtils.isEmpty(thumbnailUrl)) {
|
||||
binding.postImage.setController(null);
|
||||
return;
|
||||
}
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(thumbnailUrl))
|
||||
.setResizeOptions(ResizeOptions.forDimensions(binding.postImage.getWidth(),
|
||||
binding.postImage.getHeight()))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(requestBuilder)
|
||||
.setOldController(binding.postImage.getController());
|
||||
binding.postImage.setController(builder.build());
|
||||
}
|
||||
|
||||
private void setUserDetails(@NonNull final Media media,
|
||||
@NonNull final PostsLayoutPreferences layoutPreferences) {
|
||||
final User user = media.getUser();
|
||||
if (layoutPreferences.isAvatarVisible()) {
|
||||
binding.profilePic.setVisibility(TextUtils.isEmpty(feedModel.getProfileModel().getSdProfilePic()) ? View.GONE : View.VISIBLE);
|
||||
binding.profilePic.setImageURI(feedModel.getProfileModel().getSdProfilePic());
|
||||
if (user == null) {
|
||||
binding.profilePic.setVisibility(View.GONE);
|
||||
} else {
|
||||
final String profilePicUrl = user.getProfilePicUrl();
|
||||
if (TextUtils.isEmpty(profilePicUrl)) {
|
||||
binding.profilePic.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.profilePic.setVisibility(View.VISIBLE);
|
||||
binding.profilePic.setImageURI(profilePicUrl);
|
||||
}
|
||||
}
|
||||
final ViewGroup.LayoutParams layoutParams = binding.profilePic.getLayoutParams();
|
||||
@DimenRes final int dimenRes;
|
||||
switch (layoutPreferences.getProfilePicSize()) {
|
||||
@ -88,74 +183,19 @@ public class FeedGridItemViewHolder extends RecyclerView.ViewHolder {
|
||||
binding.profilePic.setVisibility(View.GONE);
|
||||
}
|
||||
if (layoutPreferences.isNameVisible()) {
|
||||
binding.name.setVisibility(TextUtils.isEmpty(feedModel.getProfileModel().getUsername()) ? View.GONE : View.VISIBLE);
|
||||
binding.name.setText(feedModel.getProfileModel().getUsername());
|
||||
if (user == null) {
|
||||
binding.name.setVisibility(View.GONE);
|
||||
} else {
|
||||
final String username = user.getUsername();
|
||||
if (username == null) {
|
||||
binding.name.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.name.setVisibility(View.VISIBLE);
|
||||
binding.name.setText(username);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.name.setVisibility(View.GONE);
|
||||
}
|
||||
String thumbnailUrl = null;
|
||||
final int typeIconRes;
|
||||
switch (feedModel.getItemType()) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
typeIconRes = -1;
|
||||
thumbnailUrl = feedModel.getThumbnailUrl();
|
||||
break;
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
thumbnailUrl = feedModel.getThumbnailUrl();
|
||||
typeIconRes = R.drawable.exo_icon_play;
|
||||
break;
|
||||
case MEDIA_TYPE_SLIDER:
|
||||
final List<PostChild> sliderItems = feedModel.getSliderItems();
|
||||
if (sliderItems != null) {
|
||||
thumbnailUrl = sliderItems.get(0).getThumbnailUrl();
|
||||
}
|
||||
typeIconRes = R.drawable.ic_checkbox_multiple_blank_stroke;
|
||||
break;
|
||||
default:
|
||||
typeIconRes = -1;
|
||||
thumbnailUrl = null;
|
||||
}
|
||||
if (TextUtils.isEmpty(thumbnailUrl)) {
|
||||
binding.postImage.setController(null);
|
||||
return;
|
||||
}
|
||||
if (typeIconRes <= 0) {
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.typeIcon.setVisibility(View.VISIBLE);
|
||||
binding.typeIcon.setImageResource(typeIconRes);
|
||||
}
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(thumbnailUrl))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
final PipelineDraweeControllerBuilder builder = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(requestBuilder)
|
||||
.setOldController(binding.postImage.getController());
|
||||
binding.postImage.setController(builder.build());
|
||||
final DownloadedCheckerAsyncTask task = new DownloadedCheckerAsyncTask(result -> {
|
||||
final List<Boolean> checkList = result.get(feedModel.getPostId());
|
||||
if (checkList == null || checkList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
switch (feedModel.getItemType()) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
binding.downloaded.setVisibility(checkList.get(0) ? View.VISIBLE : View.GONE);
|
||||
binding.downloaded.setImageTintList(ColorStateList.valueOf(itemView.getResources().getColor(R.color.green_A400)));
|
||||
break;
|
||||
case MEDIA_TYPE_SLIDER:
|
||||
binding.downloaded.setVisibility(checkList.get(0) ? View.VISIBLE : View.GONE);
|
||||
boolean allDownloaded = checkList.size() == feedModel.getSliderItems().size();
|
||||
if (allDownloaded) {
|
||||
allDownloaded = checkList.stream().allMatch(downloaded -> downloaded);
|
||||
}
|
||||
binding.downloaded.setImageTintList(ColorStateList.valueOf(itemView.getResources().getColor(
|
||||
allDownloaded ? R.color.green_A400 : R.color.yellow_400)));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
task.execute(feedModel);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import awais.instagrabber.adapters.FeedStoriesAdapter;
|
||||
import awais.instagrabber.databinding.ItemHighlightBinding;
|
||||
import awais.instagrabber.models.FeedStoryModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public final class FeedStoryViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@ -28,10 +28,10 @@ public final class FeedStoryViewHolder extends RecyclerView.ViewHolder {
|
||||
if (listener != null) listener.onFeedStoryLongClick(model, position);
|
||||
return true;
|
||||
});
|
||||
final ProfileModel profileModel = model.getProfileModel();
|
||||
final User profileModel = model.getProfileModel();
|
||||
binding.title.setText(profileModel.getUsername());
|
||||
binding.title.setAlpha(model.isFullyRead() ? 0.5F : 1.0F);
|
||||
binding.icon.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.icon.setImageURI(profileModel.getProfilePicUrl());
|
||||
binding.icon.setAlpha(model.isFullyRead() ? 0.5F : 1.0F);
|
||||
|
||||
if (model.isLive()) binding.icon.setStoriesBorder(2);
|
||||
|
@ -0,0 +1,72 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import awais.instagrabber.adapters.FiltersAdapter;
|
||||
import awais.instagrabber.databinding.ItemFilterBinding;
|
||||
import awais.instagrabber.fragments.imageedit.filters.filters.Filter;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
import awais.instagrabber.utils.BitmapUtils;
|
||||
import jp.co.cyberagent.android.gpuimage.GPUImage;
|
||||
import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;
|
||||
|
||||
public class FilterViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = FilterViewHolder.class.getSimpleName();
|
||||
|
||||
private final ItemFilterBinding binding;
|
||||
private final Collection<GPUImageFilter> tuneFilters;
|
||||
private final FiltersAdapter.OnFilterClickListener onFilterClickListener;
|
||||
private final AppExecutors appExecutors;
|
||||
|
||||
public FilterViewHolder(@NonNull final ItemFilterBinding binding,
|
||||
final Collection<GPUImageFilter> tuneFilters,
|
||||
final FiltersAdapter.OnFilterClickListener onFilterClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.tuneFilters = tuneFilters;
|
||||
this.onFilterClickListener = onFilterClickListener;
|
||||
appExecutors = AppExecutors.getInstance();
|
||||
}
|
||||
|
||||
public void bind(final int position, final String originalKey, final Bitmap originalBitmap, final Filter<?> item, final boolean isSelected) {
|
||||
if (originalBitmap == null || item == null) return;
|
||||
if (onFilterClickListener != null) {
|
||||
itemView.setOnClickListener(v -> onFilterClickListener.onClick(position, item));
|
||||
}
|
||||
if (item.getLabel() != -1) {
|
||||
binding.name.setVisibility(View.VISIBLE);
|
||||
binding.name.setText(item.getLabel());
|
||||
binding.name.setSelected(isSelected);
|
||||
} else {
|
||||
binding.name.setVisibility(View.GONE);
|
||||
}
|
||||
final String filterKey = item.getLabel() + "_" + originalKey;
|
||||
// avoid resetting the bitmap
|
||||
if (binding.preview.getTag() != null && binding.preview.getTag().equals(filterKey)) return;
|
||||
binding.preview.setTag(filterKey);
|
||||
final Bitmap bitmap = BitmapUtils.getBitmapFromMemCache(filterKey);
|
||||
if (bitmap == null) {
|
||||
final GPUImageFilter filter = item.getInstance();
|
||||
appExecutors.tasksThread().submit(() -> {
|
||||
GPUImage.getBitmapForMultipleFilters(
|
||||
originalBitmap,
|
||||
ImmutableList.<GPUImageFilter>builder().add(filter).addAll(tuneFilters).build(),
|
||||
filteredBitmap -> {
|
||||
BitmapUtils.addBitmapToMemoryCache(filterKey, filteredBitmap, true);
|
||||
appExecutors.mainThread().execute(() -> binding.getRoot().post(() -> binding.preview.setImageBitmap(filteredBitmap)));
|
||||
}
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
binding.getRoot().post(() -> binding.preview.setImageBitmap(bitmap));
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@ -9,7 +8,7 @@ import java.util.List;
|
||||
|
||||
import awais.instagrabber.databinding.ItemFollowBinding;
|
||||
import awais.instagrabber.models.FollowModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public final class FollowsViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@ -20,18 +19,18 @@ public final class FollowsViewHolder extends RecyclerView.ViewHolder {
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final ProfileModel model,
|
||||
public void bind(final User model,
|
||||
final List<Long> admins,
|
||||
final View.OnClickListener onClickListener) {
|
||||
if (model == null) return;
|
||||
itemView.setTag(model);
|
||||
itemView.setOnClickListener(onClickListener);
|
||||
binding.tvUsername.setText(model.getUsername());
|
||||
binding.tvFullName.setText(model.getName());
|
||||
if (admins != null && admins.contains(Long.parseLong(model.getId()))) {
|
||||
binding.tvFullName.setText(model.getFullName());
|
||||
if (admins != null && admins.contains(model.getPk())) {
|
||||
binding.isAdmin.setVisibility(View.VISIBLE);
|
||||
}
|
||||
binding.ivProfilePic.setImageURI(model.getSdProfilePic());
|
||||
binding.ivProfilePic.setImageURI(model.getProfilePicUrl());
|
||||
}
|
||||
|
||||
public void bind(final FollowModel model,
|
||||
|
@ -1,17 +1,16 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.models.NotificationModel;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
import awais.instagrabber.repositories.responses.NotificationArgs;
|
||||
|
||||
public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ItemNotificationBinding binding;
|
||||
@ -21,22 +20,19 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final NotificationModel model,
|
||||
public void bind(final Notification model,
|
||||
final OnNotificationClickListener notificationClickListener) {
|
||||
if (model == null) return;
|
||||
int text = -1;
|
||||
CharSequence subtext = null;
|
||||
final NotificationArgs args = model.getArgs();
|
||||
switch (model.getType()) {
|
||||
case LIKE:
|
||||
text = R.string.liked_notif;
|
||||
break;
|
||||
case COMMENT:
|
||||
case COMMENT: // untested
|
||||
text = R.string.comment_notif;
|
||||
subtext = model.getText();
|
||||
break;
|
||||
case MENTION:
|
||||
text = R.string.mention_notif;
|
||||
subtext = model.getText();
|
||||
subtext = args.getText();
|
||||
break;
|
||||
case TAGGED:
|
||||
text = R.string.tagged_notif;
|
||||
@ -46,47 +42,50 @@ public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
||||
break;
|
||||
case REQUEST:
|
||||
text = R.string.request_notif;
|
||||
subtext = model.getText();
|
||||
break;
|
||||
case COMMENT_MENTION:
|
||||
case COMMENT_LIKE:
|
||||
case TAGGED_COMMENT:
|
||||
case RESPONDED_STORY:
|
||||
subtext = model.getText();
|
||||
subtext = args.getText();
|
||||
break;
|
||||
case AYML:
|
||||
subtext = model.getPostId();
|
||||
subtext = args.getFullName();
|
||||
break;
|
||||
}
|
||||
binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? model.getText() : subtext);
|
||||
binding.tvSubComment.setText(model.getType() == NotificationType.AYML ? args.getText() : subtext);
|
||||
if (text == -1 && subtext != null) {
|
||||
binding.tvComment.setText(subtext);
|
||||
binding.tvComment.setVisibility(TextUtils.isEmpty(subtext) ? View.GONE : View.VISIBLE);
|
||||
binding.tvComment.setText(args.getText());
|
||||
binding.tvComment.setVisibility(TextUtils.isEmpty(args.getText()) || args.getText().equals(args.getFullName())
|
||||
? View.GONE : View.VISIBLE);
|
||||
binding.tvSubComment.setText(subtext);
|
||||
binding.tvSubComment.setVisibility(model.getType() == NotificationType.AYML ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
else if (text != -1) {
|
||||
} else if (text != -1) {
|
||||
binding.tvComment.setText(text);
|
||||
binding.tvSubComment.setVisibility(subtext == null ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
if (model.getType() != NotificationType.REQUEST && model.getType() != NotificationType.AYML) {
|
||||
binding.tvDate.setText(model.getDateTime());
|
||||
binding.tvDate.setVisibility(model.getType() == NotificationType.AYML ? View.GONE : View.VISIBLE);
|
||||
if (model.getType() != NotificationType.AYML) {
|
||||
binding.tvDate.setText(args.getDateTime());
|
||||
}
|
||||
|
||||
binding.tvUsername.setText(model.getUsername());
|
||||
binding.ivProfilePic.setImageURI(model.getProfilePic());
|
||||
binding.isVerified.setVisibility(args.isVerified() ? View.VISIBLE : View.GONE);
|
||||
|
||||
binding.tvUsername.setText(args.getUsername());
|
||||
binding.ivProfilePic.setImageURI(args.getProfilePic());
|
||||
binding.ivProfilePic.setOnClickListener(v -> {
|
||||
if (notificationClickListener == null) return;
|
||||
notificationClickListener.onProfileClick(model.getUsername());
|
||||
notificationClickListener.onProfileClick(args.getUsername());
|
||||
});
|
||||
|
||||
if (model.getType() == NotificationType.AYML) {
|
||||
binding.ivPreviewPic.setVisibility(View.GONE);
|
||||
}
|
||||
else if (TextUtils.isEmpty(model.getPreviewPic())) {
|
||||
} else if (args.getMedia() == null) {
|
||||
binding.ivPreviewPic.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
||||
binding.ivPreviewPic.setImageURI(model.getPreviewPic());
|
||||
binding.ivPreviewPic.setImageURI(args.getMedia().get(0).getImage());
|
||||
binding.ivPreviewPic.setOnClickListener(v -> {
|
||||
if (notificationClickListener == null) return;
|
||||
notificationClickListener.onPreviewClick(model);
|
||||
|
@ -1,29 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.databinding.ItemChildPostBinding;
|
||||
import awais.instagrabber.models.ViewerPostModel;
|
||||
|
||||
public final class PostMediaViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final ItemChildPostBinding binding;
|
||||
|
||||
public PostMediaViewHolder(@NonNull final ItemChildPostBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final ViewerPostModel model, final int position, final View.OnClickListener clickListener) {
|
||||
if (model == null) return;
|
||||
// model.setPosition(position);
|
||||
itemView.setTag(model);
|
||||
itemView.setOnClickListener(clickListener);
|
||||
binding.selectedView.setVisibility(model.isCurrentSlide() ? View.VISIBLE : View.GONE);
|
||||
binding.isDownloaded.setVisibility(model.isDownloaded() ? View.VISIBLE : View.GONE);
|
||||
binding.icon.setImageURI(model.getDisplayUrl());
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.MultiSelectListAdapter.OnItemClickListener;
|
||||
import awais.instagrabber.adapters.MultiSelectListAdapter.OnItemLongClickListener;
|
||||
import awais.instagrabber.databinding.ItemPostBinding;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
|
||||
public final class PostViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ItemPostBinding binding;
|
||||
|
||||
public PostViewHolder(@NonNull final ItemPostBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(final PostModel postModel,
|
||||
final int position,
|
||||
final OnItemClickListener<PostModel> clickListener,
|
||||
final OnItemLongClickListener<PostModel> longClickListener) {
|
||||
if (postModel == null) return;
|
||||
// postModel.setPosition(position);
|
||||
itemView.setOnClickListener(v -> clickListener.onItemClick(postModel, position));
|
||||
itemView.setOnLongClickListener(v -> longClickListener.onItemLongClick(postModel, position));
|
||||
|
||||
final MediaItemType itemType = postModel.getItemType();
|
||||
final boolean isSlider = itemType == MediaItemType.MEDIA_TYPE_SLIDER;
|
||||
|
||||
binding.isDownloaded.setVisibility(postModel.isDownloaded() ? View.VISIBLE : View.GONE);
|
||||
|
||||
binding.typeIcon.setVisibility(itemType == MediaItemType.MEDIA_TYPE_VIDEO || isSlider ? View.VISIBLE : View.GONE);
|
||||
binding.typeIcon.setImageResource(isSlider ? R.drawable.ic_slider_24 : R.drawable.ic_video_24);
|
||||
|
||||
binding.selectedView.setVisibility(postModel.isSelected() ? View.VISIBLE : View.GONE);
|
||||
binding.postImage.setImageURI(postModel.getThumbnailUrl());
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.adapters.SliderItemsAdapter;
|
||||
import awais.instagrabber.models.PostChild;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public abstract class SliderItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = "FeedSliderItemViewHolder";
|
||||
@ -15,7 +15,7 @@ public abstract class SliderItemViewHolder extends RecyclerView.ViewHolder {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public abstract void bind(final PostChild model,
|
||||
public abstract void bind(final Media media,
|
||||
final int position,
|
||||
final SliderItemsAdapter.SliderCallback sliderCallback);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.net.Uri;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@ -15,7 +17,8 @@ import awais.instagrabber.adapters.SliderItemsAdapter;
|
||||
import awais.instagrabber.customviews.VerticalDragHelper;
|
||||
import awais.instagrabber.customviews.drawee.AnimatedZoomableController;
|
||||
import awais.instagrabber.databinding.ItemSliderPhotoBinding;
|
||||
import awais.instagrabber.models.PostChild;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class SliderPhotoViewHolder extends SliderItemViewHolder {
|
||||
private static final String TAG = "FeedSliderPhotoViewHolder";
|
||||
@ -30,11 +33,11 @@ public class SliderPhotoViewHolder extends SliderItemViewHolder {
|
||||
this.onVerticalDragListener = onVerticalDragListener;
|
||||
}
|
||||
|
||||
public void bind(@NonNull final PostChild model,
|
||||
public void bind(@NonNull final Media model,
|
||||
final int position,
|
||||
final SliderItemsAdapter.SliderCallback sliderCallback) {
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(model.getDisplayUrl()))
|
||||
.newBuilderWithSource(Uri.parse(ResponseBodyUtils.getImageUrl(model)))
|
||||
.setLocalThumbnailPreviewsEnabled(true)
|
||||
.build();
|
||||
binding.getRoot()
|
||||
@ -57,11 +60,21 @@ public class SliderPhotoViewHolder extends SliderItemViewHolder {
|
||||
}
|
||||
}
|
||||
})
|
||||
.setLowResImageRequest(ImageRequest.fromUri(model.getThumbnailUrl()))
|
||||
.setLowResImageRequest(ImageRequest.fromUri(ResponseBodyUtils.getThumbUrl(model)))
|
||||
.build());
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
if (sliderCallback != null) {
|
||||
sliderCallback.onItemClicked(position);
|
||||
// binding.getRoot().setOnClickListener(v -> {
|
||||
// if (sliderCallback != null) {
|
||||
// sliderCallback.onItemClicked(position);
|
||||
// }
|
||||
// });
|
||||
binding.getRoot().setTapListener(new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapUp(final MotionEvent e) {
|
||||
if (sliderCallback != null) {
|
||||
sliderCallback.onItemClicked(position);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
final AnimatedZoomableController zoomableController = AnimatedZoomableController.newInstance();
|
||||
|
@ -1,19 +1,25 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.adapters.SliderItemsAdapter;
|
||||
import awais.instagrabber.customviews.VerticalDragHelper;
|
||||
import awais.instagrabber.customviews.VideoPlayerCallbackAdapter;
|
||||
import awais.instagrabber.customviews.VideoPlayerViewHelper;
|
||||
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding;
|
||||
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
|
||||
import awais.instagrabber.models.PostChild;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.VideoVersion;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -24,6 +30,14 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
|
||||
private final LayoutVideoPlayerWithThumbnailBinding binding;
|
||||
private final LayoutExoCustomControlsBinding controlsBinding;
|
||||
private final boolean loadVideoOnItemClick;
|
||||
private final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(final MotionEvent e) {
|
||||
binding.playerView.performClick();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private VideoPlayerViewHelper videoPlayerViewHelper;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@ -35,29 +49,27 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
|
||||
this.binding = binding;
|
||||
this.controlsBinding = controlsBinding;
|
||||
this.loadVideoOnItemClick = loadVideoOnItemClick;
|
||||
if (onVerticalDragListener != null) {
|
||||
final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent);
|
||||
final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.playerView);
|
||||
thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
|
||||
playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
|
||||
binding.thumbnailParent.setOnTouchListener((v, event) -> {
|
||||
final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event);
|
||||
if (onDragTouch) {
|
||||
return true;
|
||||
}
|
||||
return thumbnailVerticalDragHelper.onGestureTouchEvent(event);
|
||||
});
|
||||
binding.playerView.setOnTouchListener((v, event) -> {
|
||||
final boolean onDragTouch = playerVerticalDragHelper.onDragTouch(event);
|
||||
if (onDragTouch) {
|
||||
return true;
|
||||
}
|
||||
return playerVerticalDragHelper.onGestureTouchEvent(event);
|
||||
});
|
||||
}
|
||||
// if (onVerticalDragListener != null) {
|
||||
// final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent);
|
||||
// final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.playerView);
|
||||
// thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
|
||||
// playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
|
||||
// binding.thumbnailParent.setOnTouchListener((v, event) -> {
|
||||
// final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event);
|
||||
// if (onDragTouch) {
|
||||
// return true;
|
||||
// }
|
||||
// return thumbnailVerticalDragHelper.onGestureTouchEvent(event);
|
||||
// });
|
||||
// }
|
||||
final GestureDetector gestureDetector = new GestureDetector(itemView.getContext(), videoPlayerViewGestureListener);
|
||||
binding.playerView.setOnTouchListener((v, event) -> {
|
||||
gestureDetector.onTouchEvent(event);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public void bind(@NonNull final PostChild model,
|
||||
public void bind(@NonNull final Media media,
|
||||
final int position,
|
||||
final SliderItemsAdapter.SliderCallback sliderCallback) {
|
||||
final float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
@ -82,7 +94,7 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
|
||||
// binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.playerView.getLayoutParams();
|
||||
final int requiredWidth = Utils.displayMetrics.widthPixels;
|
||||
final int resultingHeight = NumberUtils.getResultingHeight(requiredWidth, model.getHeight(), model.getWidth());
|
||||
final int resultingHeight = NumberUtils.getResultingHeight(requiredWidth, media.getOriginalHeight(), media.getOriginalWidth());
|
||||
layoutParams.width = requiredWidth;
|
||||
layoutParams.height = resultingHeight;
|
||||
binding.playerView.requestLayout();
|
||||
@ -102,14 +114,30 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
|
||||
sliderCallback.onPlayerPause(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease() {
|
||||
if (sliderCallback != null) {
|
||||
sliderCallback.onPlayerRelease(position);
|
||||
}
|
||||
}
|
||||
};
|
||||
final float aspectRatio = (float) model.getWidth() / model.getHeight();
|
||||
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
|
||||
String videoUrl = null;
|
||||
final List<VideoVersion> videoVersions = media.getVideoVersions();
|
||||
if (videoVersions != null && !videoVersions.isEmpty()) {
|
||||
final VideoVersion videoVersion = videoVersions.get(0);
|
||||
if (videoVersion != null) {
|
||||
videoUrl = videoVersion.getUrl();
|
||||
}
|
||||
}
|
||||
if (videoUrl == null) return;
|
||||
videoPlayerViewHelper = new VideoPlayerViewHelper(binding.getRoot().getContext(),
|
||||
binding,
|
||||
model.getDisplayUrl(),
|
||||
videoUrl,
|
||||
vol,
|
||||
aspectRatio,
|
||||
model.getThumbnailUrl(),
|
||||
ResponseBodyUtils.getThumbUrl(media),
|
||||
loadVideoOnItemClick,
|
||||
controlsBinding,
|
||||
videoPlayerCallback);
|
||||
|
@ -1,6 +1,5 @@
|
||||
package awais.instagrabber.adapters.viewholder;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@ -34,7 +33,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder {
|
||||
binding.tvDate.setText(model.getDateTime());
|
||||
|
||||
binding.tvUsername.setText(model.getProfileModel().getUsername());
|
||||
binding.ivProfilePic.setImageURI(model.getProfileModel().getSdProfilePic());
|
||||
binding.ivProfilePic.setImageURI(model.getProfileModel().getProfilePicUrl());
|
||||
binding.ivProfilePic.setOnClickListener(v -> {
|
||||
if (notificationClickListener == null) return;
|
||||
notificationClickListener.onProfileClick(model.getProfileModel().getUsername());
|
||||
@ -43,8 +42,7 @@ public final class StoryListViewHolder extends RecyclerView.ViewHolder {
|
||||
if (model.getFirstStoryModel() != null) {
|
||||
binding.ivPreviewPic.setVisibility(View.VISIBLE);
|
||||
binding.ivPreviewPic.setImageURI(model.getFirstStoryModel().getThumbnail());
|
||||
}
|
||||
else binding.ivPreviewPic.setVisibility(View.INVISIBLE);
|
||||
} else binding.ivPreviewPic.setVisibility(View.INVISIBLE);
|
||||
|
||||
float alpha = model.isFullyRead() ? 0.5F : 1.0F;
|
||||
binding.ivProfilePic.setAlpha(alpha);
|
||||
|
@ -25,18 +25,24 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DiscoverTopicsAdapter;
|
||||
import awais.instagrabber.adapters.SavedCollectionsAdapter;
|
||||
import awais.instagrabber.databinding.ItemDiscoverTopicBinding;
|
||||
import awais.instagrabber.models.TopicCluster;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicCluster;
|
||||
import awais.instagrabber.repositories.responses.saved.SavedCollection;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class TopicClusterViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ItemDiscoverTopicBinding binding;
|
||||
private final DiscoverTopicsAdapter.OnTopicClickListener onTopicClickListener;
|
||||
private final SavedCollectionsAdapter.OnCollectionClickListener onCollectionClickListener;
|
||||
|
||||
public TopicClusterViewHolder(@NonNull final ItemDiscoverTopicBinding binding,
|
||||
final DiscoverTopicsAdapter.OnTopicClickListener onTopicClickListener) {
|
||||
final DiscoverTopicsAdapter.OnTopicClickListener onTopicClickListener,
|
||||
final SavedCollectionsAdapter.OnCollectionClickListener onCollectionClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.onTopicClickListener = onTopicClickListener;
|
||||
this.onCollectionClickListener = onCollectionClickListener;
|
||||
}
|
||||
|
||||
public void bind(final TopicCluster topicCluster) {
|
||||
@ -57,43 +63,115 @@ public class TopicClusterViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
// binding.title.setTransitionName("title-" + topicCluster.getId());
|
||||
binding.cover.setTransitionName("cover-" + topicCluster.getId());
|
||||
final ImageRequest imageRequest = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(topicCluster.getCoverMedia().getDisplayUrl()))
|
||||
.build();
|
||||
final ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline
|
||||
.fetchDecodedImage(imageRequest, CallerThreadExecutor.getInstance());
|
||||
dataSource.subscribe(new BaseBitmapDataSubscriber() {
|
||||
@Override
|
||||
public void onNewResultImpl(@Nullable Bitmap bitmap) {
|
||||
if (dataSource.isFinished()) {
|
||||
final String thumbUrl = ResponseBodyUtils.getThumbUrl(topicCluster.getCoverMedia());
|
||||
if (thumbUrl == null) {
|
||||
binding.cover.setImageURI((String) null);
|
||||
} else {
|
||||
final ImageRequest imageRequest = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(thumbUrl))
|
||||
.build();
|
||||
final ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline
|
||||
.fetchDecodedImage(imageRequest, CallerThreadExecutor.getInstance());
|
||||
dataSource.subscribe(new BaseBitmapDataSubscriber() {
|
||||
@Override
|
||||
public void onNewResultImpl(@Nullable Bitmap bitmap) {
|
||||
if (dataSource.isFinished()) {
|
||||
dataSource.close();
|
||||
}
|
||||
if (bitmap != null) {
|
||||
Palette.from(bitmap).generate(p -> {
|
||||
final Resources resources = itemView.getResources();
|
||||
int titleTextColor = resources.getColor(R.color.white);
|
||||
if (p != null) {
|
||||
final Palette.Swatch swatch = p.getDominantSwatch();
|
||||
if (swatch != null) {
|
||||
backgroundColor.set(swatch.getRgb());
|
||||
GradientDrawable gd = new GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
new int[]{Color.TRANSPARENT, backgroundColor.get()});
|
||||
titleTextColor = swatch.getTitleTextColor();
|
||||
binding.background.setBackground(gd);
|
||||
}
|
||||
}
|
||||
titleColor.set(titleTextColor);
|
||||
binding.title.setTextColor(titleTextColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureImpl(@NonNull DataSource dataSource) {
|
||||
dataSource.close();
|
||||
}
|
||||
if (bitmap != null) {
|
||||
Palette.from(bitmap).generate(p -> {
|
||||
final Palette.Swatch swatch = p.getDominantSwatch();
|
||||
final Resources resources = itemView.getResources();
|
||||
int titleTextColor = resources.getColor(R.color.white);
|
||||
if (swatch != null) {
|
||||
backgroundColor.set(swatch.getRgb());
|
||||
GradientDrawable gd = new GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
new int[]{Color.TRANSPARENT, backgroundColor.get()});
|
||||
titleTextColor = swatch.getTitleTextColor();
|
||||
binding.background.setBackground(gd);
|
||||
}
|
||||
titleColor.set(titleTextColor);
|
||||
binding.title.setTextColor(titleTextColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, CallerThreadExecutor.getInstance());
|
||||
binding.cover.setImageRequest(imageRequest);
|
||||
}
|
||||
binding.title.setText(topicCluster.getTitle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureImpl(@NonNull DataSource dataSource) {
|
||||
dataSource.close();
|
||||
}
|
||||
}, CallerThreadExecutor.getInstance());
|
||||
binding.cover.setImageRequest(imageRequest);
|
||||
public void bind(final SavedCollection topicCluster) {
|
||||
if (topicCluster == null) {
|
||||
return;
|
||||
}
|
||||
final AtomicInteger titleColor = new AtomicInteger(-1);
|
||||
final AtomicInteger backgroundColor = new AtomicInteger(-1);
|
||||
if (onCollectionClickListener != null) {
|
||||
itemView.setOnClickListener(v -> onCollectionClickListener.onCollectionClick(
|
||||
topicCluster,
|
||||
binding.getRoot(),
|
||||
binding.cover,
|
||||
binding.title,
|
||||
titleColor.get(),
|
||||
backgroundColor.get()
|
||||
));
|
||||
}
|
||||
// binding.title.setTransitionName("title-" + topicCluster.getId());
|
||||
binding.cover.setTransitionName("cover-" + topicCluster.getId());
|
||||
final String thumbUrl = ResponseBodyUtils.getThumbUrl(topicCluster.getCoverMedias() == null
|
||||
? topicCluster.getCoverMedia()
|
||||
: topicCluster.getCoverMedias().get(0));
|
||||
if (thumbUrl == null) {
|
||||
binding.cover.setImageURI((String) null);
|
||||
} else {
|
||||
final ImageRequest imageRequest = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(thumbUrl))
|
||||
.build();
|
||||
final ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline
|
||||
.fetchDecodedImage(imageRequest, CallerThreadExecutor.getInstance());
|
||||
dataSource.subscribe(new BaseBitmapDataSubscriber() {
|
||||
@Override
|
||||
public void onNewResultImpl(@Nullable Bitmap bitmap) {
|
||||
if (dataSource.isFinished()) {
|
||||
dataSource.close();
|
||||
}
|
||||
if (bitmap != null) {
|
||||
Palette.from(bitmap).generate(p -> {
|
||||
final Palette.Swatch swatch = p.getDominantSwatch();
|
||||
final Resources resources = itemView.getResources();
|
||||
int titleTextColor = resources.getColor(R.color.white);
|
||||
if (swatch != null) {
|
||||
backgroundColor.set(swatch.getRgb());
|
||||
GradientDrawable gd = new GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
new int[]{Color.TRANSPARENT, backgroundColor.get()});
|
||||
titleTextColor = swatch.getTitleTextColor();
|
||||
binding.background.setBackground(gd);
|
||||
}
|
||||
titleColor.set(titleTextColor);
|
||||
binding.title.setTextColor(titleTextColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureImpl(@NonNull DataSource dataSource) {
|
||||
dataSource.close();
|
||||
}
|
||||
}, CallerThreadExecutor.getInstance());
|
||||
binding.cover.setImageRequest(imageRequest);
|
||||
}
|
||||
binding.title.setText(topicCluster.getTitle());
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.CommentsAdapter.CommentCallback;
|
||||
import awais.instagrabber.databinding.ItemCommentSmallBinding;
|
||||
import awais.instagrabber.models.CommentModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public final class ChildCommentViewHolder extends RecyclerView.ViewHolder {
|
||||
@ -75,10 +75,10 @@ public final class ChildCommentViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
|
||||
private void setUser(final CommentModel comment) {
|
||||
final ProfileModel profileModel = comment.getProfileModel();
|
||||
final User profileModel = comment.getProfileModel();
|
||||
if (profileModel == null) return;
|
||||
binding.tvUsername.setText(profileModel.getUsername());
|
||||
binding.ivProfilePic.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.ivProfilePic.setImageURI(profileModel.getProfilePicUrl());
|
||||
binding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.CommentsAdapter.CommentCallback;
|
||||
import awais.instagrabber.databinding.ItemCommentBinding;
|
||||
import awais.instagrabber.models.CommentModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public final class ParentCommentViewHolder extends RecyclerView.ViewHolder {
|
||||
@ -75,10 +75,10 @@ public final class ParentCommentViewHolder extends RecyclerView.ViewHolder {
|
||||
}
|
||||
|
||||
private void setUser(final CommentModel comment) {
|
||||
final ProfileModel profileModel = comment.getProfileModel();
|
||||
final User profileModel = comment.getProfileModel();
|
||||
if (profileModel == null) return;
|
||||
binding.tvUsername.setText(profileModel.getUsername());
|
||||
binding.ivProfilePic.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.ivProfilePic.setImageURI(profileModel.getProfilePicUrl());
|
||||
binding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,51 @@
|
||||
package awais.instagrabber.adapters.viewholder.dialogs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.KeywordsFilterAdapter;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.SettingsHelper;
|
||||
|
||||
public class KeywordsFilterDialogViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final Button deleteButton;
|
||||
private final TextView item;
|
||||
|
||||
public KeywordsFilterDialogViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
deleteButton = itemView.findViewById(R.id.keyword_delete);
|
||||
item = itemView.findViewById(R.id.keyword_text);
|
||||
}
|
||||
|
||||
public void bind(ArrayList<String> items, int position, Context context, KeywordsFilterAdapter adapter){
|
||||
item.setText(items.get(position));
|
||||
deleteButton.setOnClickListener(view -> {
|
||||
final String s = items.get(position);
|
||||
SettingsHelper settingsHelper = new SettingsHelper(context);
|
||||
items.remove(position);
|
||||
settingsHelper.putStringSet(Constants.KEYWORD_FILTERS, new HashSet<>(items));
|
||||
adapter.notifyDataSetChanged();
|
||||
final String message = context.getString(R.string.removed_keywords, s);
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}
|
||||
|
||||
public Button getDeleteButton(){
|
||||
return deleteButton;
|
||||
}
|
||||
|
||||
public TextView getTextView(){
|
||||
return item;
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Typeface;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.constraintlayout.widget.ConstraintSet;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectMessageInboxAdapter.OnItemClickListener;
|
||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThreadDirectStory;
|
||||
import awais.instagrabber.utils.DMUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public final class DirectInboxItemViewHolder extends RecyclerView.ViewHolder {
|
||||
// private static final String TAG = "DMInboxItemVH";
|
||||
private final LayoutDmInboxItemBinding binding;
|
||||
private final OnItemClickListener onClickListener;
|
||||
private final List<SimpleDraweeView> multipleProfilePics;
|
||||
private final int childSmallSize;
|
||||
private final int childTinySize;
|
||||
|
||||
public DirectInboxItemViewHolder(@NonNull final LayoutDmInboxItemBinding binding,
|
||||
final OnItemClickListener onClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.onClickListener = onClickListener;
|
||||
multipleProfilePics = ImmutableList.of(
|
||||
binding.multiPic1,
|
||||
binding.multiPic2,
|
||||
binding.multiPic3
|
||||
);
|
||||
childSmallSize = itemView.getResources().getDimensionPixelSize(R.dimen.dm_inbox_avatar_size_small);
|
||||
childTinySize = itemView.getResources().getDimensionPixelSize(R.dimen.dm_inbox_avatar_size_tiny);
|
||||
}
|
||||
|
||||
public void bind(final DirectThread thread) {
|
||||
if (thread == null) return;
|
||||
if (onClickListener != null) {
|
||||
itemView.setOnClickListener((v) -> onClickListener.onItemClick(thread));
|
||||
}
|
||||
setProfilePics(thread);
|
||||
setTitle(thread);
|
||||
final List<DirectItem> items = thread.getItems();
|
||||
if (items == null || items.isEmpty()) return;
|
||||
final DirectItem item = thread.getFirstDirectItem();
|
||||
if (item == null) return;
|
||||
setDateTime(item);
|
||||
setSubtitle(thread);
|
||||
setReadState(thread);
|
||||
}
|
||||
|
||||
private void setProfilePics(@NonNull final DirectThread thread) {
|
||||
final List<User> users = thread.getUsers();
|
||||
if (users.size() > 1) {
|
||||
binding.profilePic.setVisibility(View.GONE);
|
||||
binding.multiPicContainer.setVisibility(View.VISIBLE);
|
||||
for (int i = 0; i < Math.min(3, users.size()); ++i) {
|
||||
final User user = users.get(i);
|
||||
final SimpleDraweeView view = multipleProfilePics.get(i);
|
||||
view.setVisibility(user == null ? View.GONE : View.VISIBLE);
|
||||
if (user == null) return;
|
||||
final String profilePicUrl = user.getProfilePicUrl();
|
||||
view.setImageURI(profilePicUrl);
|
||||
setChildSize(view, users.size());
|
||||
if (i == 1) {
|
||||
updateConstraints(view, users.size());
|
||||
}
|
||||
view.requestLayout();
|
||||
}
|
||||
return;
|
||||
}
|
||||
binding.profilePic.setVisibility(View.VISIBLE);
|
||||
binding.multiPicContainer.setVisibility(View.GONE);
|
||||
final String profilePicUrl = users.size() == 1 ? users.get(0).getProfilePicUrl() : null;
|
||||
if (profilePicUrl == null) {
|
||||
binding.profilePic.setController(null);
|
||||
return;
|
||||
}
|
||||
binding.profilePic.setImageURI(profilePicUrl);
|
||||
}
|
||||
|
||||
private void updateConstraints(final SimpleDraweeView view, final int length) {
|
||||
final ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) view.getLayoutParams();
|
||||
if (length >= 2) {
|
||||
layoutParams.endToEnd = ConstraintSet.PARENT_ID;
|
||||
layoutParams.bottomToBottom = ConstraintSet.PARENT_ID;
|
||||
}
|
||||
if (length == 3) {
|
||||
layoutParams.startToStart = ConstraintSet.PARENT_ID;
|
||||
layoutParams.topToTop = ConstraintSet.PARENT_ID;
|
||||
}
|
||||
}
|
||||
|
||||
private void setChildSize(final SimpleDraweeView view, final int length) {
|
||||
final int size = length == 3 ? childTinySize : childSmallSize;
|
||||
final ConstraintLayout.LayoutParams viewLayoutParams = new ConstraintLayout.LayoutParams(size, size);
|
||||
view.setLayoutParams(viewLayoutParams);
|
||||
}
|
||||
|
||||
private void setTitle(@NonNull final DirectThread thread) {
|
||||
final String threadTitle = thread.getThreadTitle();
|
||||
binding.threadTitle.setText(threadTitle);
|
||||
}
|
||||
|
||||
private void setSubtitle(@NonNull final DirectThread thread) {
|
||||
final Resources resources = itemView.getResources();
|
||||
final long viewerId = thread.getViewerId();
|
||||
// final DirectThreadDirectStory directStory = thread.getDirectStory();
|
||||
// if (directStory != null && !directStory.getItems().isEmpty()) {
|
||||
// final DirectItem item = directStory.getItems().get(0);
|
||||
// final MediaItemType mediaType = item.getVisualMedia().getMedia().getMediaType();
|
||||
// final String username = DMUtils.getUsername(thread.getUsers(), item.getUserId(), viewerId, resources);
|
||||
// final String subtitle = DMUtils.getMediaSpecificSubtitle(username, resources, mediaType);
|
||||
// binding.subtitle.setText(subtitle);
|
||||
// return;
|
||||
// }
|
||||
final DirectItem item = thread.getFirstDirectItem();
|
||||
if (item == null) return;
|
||||
final String subtitle = DMUtils.getMessageString(thread, resources, viewerId, item);
|
||||
binding.subtitle.setText(subtitle != null ? subtitle : "");
|
||||
}
|
||||
|
||||
private void setDateTime(@NonNull final DirectItem item) {
|
||||
final long timestamp = item.getTimestamp() / 1000;
|
||||
final String dateTimeString = TextUtils.getRelativeDateTimeString(itemView.getContext(), timestamp);
|
||||
binding.tvDate.setText(dateTimeString);
|
||||
}
|
||||
|
||||
private void setReadState(@NonNull final DirectThread thread) {
|
||||
final boolean read = DMUtils.isRead(thread);
|
||||
binding.unread.setVisibility(read ? View.GONE : View.VISIBLE);
|
||||
binding.threadTitle.setTypeface(null, read ? Typeface.NORMAL : Typeface.BOLD);
|
||||
binding.subtitle.setTypeface(null, read ? Typeface.NORMAL : Typeface.BOLD);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmActionLogBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemActionLog;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemActionLogViewHolder extends DirectItemViewHolder {
|
||||
private static final String TAG = DirectItemActionLogViewHolder.class.getSimpleName();
|
||||
|
||||
private final LayoutDmActionLogBinding binding;
|
||||
|
||||
public DirectItemActionLogViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
final LayoutDmActionLogBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
binding.tvMessage.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final DirectItemActionLog actionLog = directItemModel.getActionLog();
|
||||
final String text = actionLog.getDescription();
|
||||
final SpannableStringBuilder sb = new SpannableStringBuilder(text);
|
||||
final List<DirectItemActionLog.TextRange> bold = actionLog.getBold();
|
||||
if (bold != null && !bold.isEmpty()) {
|
||||
for (final DirectItemActionLog.TextRange textRange : bold) {
|
||||
final StyleSpan boldStyleSpan = new StyleSpan(Typeface.BOLD);
|
||||
sb.setSpan(boldStyleSpan, textRange.getStart(), textRange.getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
}
|
||||
final List<DirectItemActionLog.TextRange> textAttributes = actionLog.getTextAttributes();
|
||||
if (textAttributes != null && !textAttributes.isEmpty()) {
|
||||
for (final DirectItemActionLog.TextRange textAttribute : textAttributes) {
|
||||
if (!TextUtils.isEmpty(textAttribute.getColor())) {
|
||||
final ForegroundColorSpan colorSpan = new ForegroundColorSpan(itemView.getResources().getColor(R.color.deep_orange_400));
|
||||
sb.setSpan(colorSpan, textAttribute.getStart(), textAttribute.getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
if (!TextUtils.isEmpty(textAttribute.getIntent())) {
|
||||
final ClickableSpan clickableSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull final View widget) {
|
||||
handleDeepLink(textAttribute.getIntent());
|
||||
}
|
||||
};
|
||||
sb.setSpan(clickableSpan, textAttribute.getStart(), textAttribute.getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.tvMessage.setText(sb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowMessageDirectionGravity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showUserDetailsInGroup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showMessageInfo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowLongClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmAnimatedMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.repositories.responses.AnimatedMediaFixedHeight;
|
||||
import awais.instagrabber.repositories.responses.AnimatedMediaImages;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemAnimatedMedia;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
|
||||
public class DirectItemAnimatedMediaViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmAnimatedMediaBinding binding;
|
||||
|
||||
public DirectItemAnimatedMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmAnimatedMediaBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
||||
final DirectItemAnimatedMedia animatedMediaModel = item.getAnimatedMedia();
|
||||
final AnimatedMediaImages images = animatedMediaModel.getImages();
|
||||
if (images == null) return;
|
||||
final AnimatedMediaFixedHeight fixedHeight = images.getFixedHeight();
|
||||
if (fixedHeight == null) return;
|
||||
final String url = fixedHeight.getWebp();
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
fixedHeight.getHeight(),
|
||||
fixedHeight.getWidth(),
|
||||
mediaImageMaxHeight,
|
||||
mediaImageMaxWidth
|
||||
);
|
||||
binding.ivAnimatedMessage.setVisibility(View.VISIBLE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivAnimatedMessage.getLayoutParams();
|
||||
final int width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
final int height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
layoutParams.width = width;
|
||||
layoutParams.height = height;
|
||||
binding.ivAnimatedMessage.requestLayout();
|
||||
binding.ivAnimatedMessage.setController(Fresco.newDraweeControllerBuilder()
|
||||
.setUri(url)
|
||||
.setAutoPlayAnimations(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
|
||||
public class DirectItemDefaultViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectItemDefaultViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final Context context = itemView.getContext();
|
||||
binding.tvMessage.setText(context.getText(R.string.dms_inbox_raven_message_unknown));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowLongClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLikeBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
|
||||
public class DirectItemLikeViewHolder extends DirectItemViewHolder {
|
||||
|
||||
public DirectItemLikeViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmLikeBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {}
|
||||
|
||||
@Override
|
||||
protected boolean canForward() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLinkBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemLink;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemLinkContext;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemLinkViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmLinkBinding binding;
|
||||
|
||||
public DirectItemLinkViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
final LayoutDmLinkBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
final int width = windowWidth - margin - dmRadiusSmall;
|
||||
final ViewGroup.LayoutParams layoutParams = binding.preview.getLayoutParams();
|
||||
layoutParams.width = width;
|
||||
binding.preview.requestLayout();
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
||||
final DirectItemLink link = item.getLink();
|
||||
final DirectItemLinkContext linkContext = link.getLinkContext();
|
||||
final String linkImageUrl = linkContext.getLinkImageUrl();
|
||||
if (TextUtils.isEmpty(linkImageUrl)) {
|
||||
binding.preview.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.preview.setVisibility(View.VISIBLE);
|
||||
binding.preview.setImageURI(linkImageUrl);
|
||||
}
|
||||
if (TextUtils.isEmpty(linkContext.getLinkTitle())) {
|
||||
binding.title.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.title.setVisibility(View.VISIBLE);
|
||||
binding.title.setText(linkContext.getLinkTitle());
|
||||
}
|
||||
if (TextUtils.isEmpty(linkContext.getLinkSummary())) {
|
||||
binding.summary.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.summary.setVisibility(View.VISIBLE);
|
||||
binding.summary.setText(linkContext.getLinkSummary());
|
||||
}
|
||||
if (TextUtils.isEmpty(linkContext.getLinkUrl())) {
|
||||
binding.url.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.url.setVisibility(View.VISIBLE);
|
||||
binding.url.setText(linkContext.getLinkUrl());
|
||||
}
|
||||
binding.text.setText(link.getText());
|
||||
setupListeners(linkContext);
|
||||
}
|
||||
|
||||
private void setupListeners(final DirectItemLinkContext linkContext) {
|
||||
setupRamboTextListeners(binding.text);
|
||||
final View.OnClickListener onClickListener = v -> openURL(linkContext.getLinkUrl());
|
||||
binding.preview.setOnClickListener(onClickListener);
|
||||
// binding.preview.setOnLongClickListener(v -> itemView.performLongClick());
|
||||
binding.title.setOnClickListener(onClickListener);
|
||||
binding.summary.setOnClickListener(onClickListener);
|
||||
binding.url.setOnClickListener(onClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showBackground() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaShareBinding;
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.Caption;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemClip;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemFelixShare;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class DirectItemMediaShareViewHolder extends DirectItemViewHolder {
|
||||
private static final String TAG = DirectItemMediaShareViewHolder.class.getSimpleName();
|
||||
|
||||
private final LayoutDmMediaShareBinding binding;
|
||||
private final RoundingParams incomingRoundingParams;
|
||||
private final RoundingParams outgoingRoundingParams;
|
||||
private DirectItemType itemType;
|
||||
|
||||
public DirectItemMediaShareViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmMediaShareBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
incomingRoundingParams = RoundingParams.fromCornersRadii(dmRadiusSmall, dmRadius, dmRadius, dmRadius);
|
||||
outgoingRoundingParams = RoundingParams.fromCornersRadii(dmRadius, dmRadiusSmall, dmRadius, dmRadius);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
||||
binding.topBg.setBackgroundResource(messageDirection == MessageDirection.INCOMING
|
||||
? R.drawable.bg_media_share_top_incoming
|
||||
: R.drawable.bg_media_share_top_outgoing);
|
||||
Media media = getMedia(item);
|
||||
if (media == null) return;
|
||||
itemView.post(() -> {
|
||||
setupUser(media);
|
||||
setupTitle(media);
|
||||
setupCaption(media);
|
||||
});
|
||||
itemView.post(() -> {
|
||||
final MediaItemType mediaType = media.getMediaType();
|
||||
setupTypeIndicator(mediaType);
|
||||
if (mediaType == MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
setupPreview(media.getCarouselMedia().get(0), messageDirection);
|
||||
return;
|
||||
}
|
||||
setupPreview(media, messageDirection);
|
||||
});
|
||||
itemView.setOnClickListener(v -> openMedia(media));
|
||||
}
|
||||
|
||||
private void setupTypeIndicator(final MediaItemType mediaType) {
|
||||
final boolean showTypeIcon = mediaType == MediaItemType.MEDIA_TYPE_VIDEO || mediaType == MediaItemType.MEDIA_TYPE_SLIDER;
|
||||
if (!showTypeIcon) {
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.typeIcon.setVisibility(View.VISIBLE);
|
||||
binding.typeIcon.setImageResource(mediaType == MediaItemType.MEDIA_TYPE_VIDEO
|
||||
? R.drawable.ic_video_24
|
||||
: R.drawable.ic_checkbox_multiple_blank_stroke);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPreview(@NonNull final Media media,
|
||||
final MessageDirection messageDirection) {
|
||||
final String url = ResponseBodyUtils.getThumbUrl(media);
|
||||
if (Objects.equals(url, binding.mediaPreview.getTag())) {
|
||||
return;
|
||||
}
|
||||
final RoundingParams roundingParams = messageDirection == MessageDirection.INCOMING ? incomingRoundingParams : outgoingRoundingParams;
|
||||
binding.mediaPreview.setHierarchy(new GenericDraweeHierarchyBuilder(itemView.getResources())
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
|
||||
.setRoundingParams(roundingParams)
|
||||
.build());
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
media.getOriginalHeight(),
|
||||
media.getOriginalWidth(),
|
||||
mediaImageMaxHeight,
|
||||
mediaImageMaxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.mediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.mediaPreview.requestLayout();
|
||||
binding.mediaPreview.setTag(url);
|
||||
binding.mediaPreview.setImageURI(url);
|
||||
}
|
||||
|
||||
private void setupCaption(@NonNull final Media media) {
|
||||
final Caption caption = media.getCaption();
|
||||
if (caption != null) {
|
||||
binding.caption.setVisibility(View.VISIBLE);
|
||||
binding.caption.setText(caption.getText());
|
||||
binding.caption.setEllipsize(TextUtils.TruncateAt.END);
|
||||
binding.caption.setMaxLines(2);
|
||||
} else {
|
||||
binding.caption.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupTitle(@NonNull final Media media) {
|
||||
final String title = media.getTitle();
|
||||
if (!TextUtils.isEmpty(title)) {
|
||||
binding.title.setVisibility(View.VISIBLE);
|
||||
binding.title.setText(title);
|
||||
} else {
|
||||
binding.title.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupUser(@NonNull final Media media) {
|
||||
final User user = media.getUser();
|
||||
if (user != null) {
|
||||
binding.username.setVisibility(View.VISIBLE);
|
||||
binding.profilePic.setVisibility(View.VISIBLE);
|
||||
binding.username.setText(user.getUsername());
|
||||
binding.profilePic.setImageURI(user.getProfilePicUrl());
|
||||
} else {
|
||||
binding.username.setVisibility(View.GONE);
|
||||
binding.profilePic.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Media getMedia(@NonNull final DirectItem item) {
|
||||
Media media = null;
|
||||
itemType = item.getItemType();
|
||||
if (itemType == DirectItemType.MEDIA_SHARE) {
|
||||
media = item.getMediaShare();
|
||||
} else if (itemType == DirectItemType.CLIP) {
|
||||
final DirectItemClip clip = item.getClip();
|
||||
if (clip == null) return null;
|
||||
media = clip.getClip();
|
||||
} else if (itemType == DirectItemType.FELIX_SHARE) {
|
||||
final DirectItemFelixShare felixShare = item.getFelixShare();
|
||||
if (felixShare == null) return null;
|
||||
media = felixShare.getVideo();
|
||||
}
|
||||
return media;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getReactionsTranslationY() {
|
||||
return reactionTranslationYType2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
if (itemType != null && (itemType == DirectItemType.CLIP || itemType == DirectItemType.FELIX_SHARE)) {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
return super.getSwipeDirection();
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaBinding;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.ImageVersions2;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class DirectItemMediaViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmMediaBinding binding;
|
||||
private final RoundingParams incomingRoundingParams;
|
||||
private final RoundingParams outgoingRoundingParams;
|
||||
|
||||
public DirectItemMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmMediaBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
incomingRoundingParams = RoundingParams.fromCornersRadii(dmRadiusSmall, dmRadius, dmRadius, dmRadius);
|
||||
outgoingRoundingParams = RoundingParams.fromCornersRadii(dmRadius, dmRadiusSmall, dmRadius, dmRadius);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final RoundingParams roundingParams = messageDirection == MessageDirection.INCOMING ? incomingRoundingParams : outgoingRoundingParams;
|
||||
binding.mediaPreview.setHierarchy(new GenericDraweeHierarchyBuilder(itemView.getResources())
|
||||
.setRoundingParams(roundingParams)
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
|
||||
.build());
|
||||
final Media media = directItemModel.getMedia();
|
||||
itemView.setOnClickListener(v -> openMedia(media));
|
||||
final MediaItemType modelMediaType = media.getMediaType();
|
||||
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO || modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
media.getOriginalHeight(),
|
||||
media.getOriginalWidth(),
|
||||
mediaImageMaxHeight,
|
||||
mediaImageMaxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.mediaPreview.getLayoutParams();
|
||||
final int width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.width = width;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.mediaPreview.requestLayout();
|
||||
binding.bgTime.getLayoutParams().width = width;
|
||||
binding.bgTime.requestLayout();
|
||||
final String thumbUrl = ResponseBodyUtils.getThumbUrl(media);
|
||||
binding.mediaPreview.setImageURI(thumbUrl);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
|
||||
public class DirectItemPlaceholderViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectItemPlaceholderViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
final LayoutDmTextBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final String text = String.format("%s: %s", directItemModel.getPlaceholder().getTitle(), directItemModel.getPlaceholder().getMessage());
|
||||
binding.tvMessage.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showBackground() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowLongClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmProfileBinding;
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
import awais.instagrabber.repositories.responses.ImageVersions2;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemProfileViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmProfileBinding binding;
|
||||
private final ImmutableList<SimpleDraweeView> previewViews;
|
||||
|
||||
public DirectItemProfileViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmProfileBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
previewViews = ImmutableList.of(
|
||||
binding.preview1,
|
||||
binding.preview2,
|
||||
binding.preview3,
|
||||
binding.preview4,
|
||||
binding.preview5,
|
||||
binding.preview6
|
||||
);
|
||||
final Resources resources = itemView.getResources();
|
||||
binding.preview4.setHierarchy(new GenericDraweeHierarchyBuilder(resources)
|
||||
.setRoundingParams(RoundingParams.fromCornersRadii(0, 0, 0, dmRadius))
|
||||
.build());
|
||||
binding.preview6.setHierarchy(new GenericDraweeHierarchyBuilder(resources)
|
||||
.setRoundingParams(RoundingParams.fromCornersRadii(0, 0, dmRadius, 0))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(@NonNull final DirectItem item,
|
||||
final MessageDirection messageDirection) {
|
||||
binding.getRoot().setBackgroundResource(messageDirection == MessageDirection.INCOMING
|
||||
? R.drawable.bg_speech_bubble_incoming
|
||||
: R.drawable.bg_speech_bubble_outgoing);
|
||||
if (item.getItemType() == DirectItemType.PROFILE) {
|
||||
setProfile(item);
|
||||
} else if (item.getItemType() == DirectItemType.LOCATION) {
|
||||
setLocation(item);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
for (final SimpleDraweeView previewView : previewViews) {
|
||||
previewView.setImageURI((String) null);
|
||||
}
|
||||
final List<Media> previewMedias = item.getPreviewMedias();
|
||||
if (previewMedias.size() <= 0) {
|
||||
binding.firstRow.setVisibility(View.GONE);
|
||||
binding.secondRow.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
if (previewMedias.size() <= 3) {
|
||||
binding.firstRow.setVisibility(View.VISIBLE);
|
||||
binding.secondRow.setVisibility(View.GONE);
|
||||
}
|
||||
for (int i = 0; i < previewMedias.size(); i++) {
|
||||
final Media previewMedia = previewMedias.get(i);
|
||||
if (previewMedia == null) continue;
|
||||
final String url = ResponseBodyUtils.getThumbUrl(previewMedia);
|
||||
if (url == null) continue;
|
||||
previewViews.get(i).setImageURI(url);
|
||||
}
|
||||
}
|
||||
|
||||
private void setProfile(@NonNull final DirectItem item) {
|
||||
final User profile = item.getProfile();
|
||||
if (profile == null) return;
|
||||
binding.profilePic.setImageURI(profile.getProfilePicUrl());
|
||||
binding.username.setText(profile.getUsername());
|
||||
binding.fullName.setText(profile.getFullName());
|
||||
binding.isVerified.setVisibility(profile.isVerified() ? View.VISIBLE : View.GONE);
|
||||
itemView.setOnClickListener(v -> openProfile(profile.getUsername()));
|
||||
}
|
||||
|
||||
private void setLocation(@NonNull final DirectItem item) {
|
||||
final Location location = item.getLocation();
|
||||
if (location == null) return;
|
||||
binding.profilePic.setVisibility(View.GONE);
|
||||
binding.username.setText(location.getName());
|
||||
final String address = location.getAddress();
|
||||
if (!TextUtils.isEmpty(address)) {
|
||||
binding.fullName.setText(address);
|
||||
binding.fullName.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.fullName.setVisibility(View.GONE);
|
||||
}
|
||||
binding.isVerified.setVisibility(View.GONE);
|
||||
itemView.setOnClickListener(v -> openLocation(location.getPk()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.models.enums.RavenMediaViewMode;
|
||||
import awais.instagrabber.repositories.responses.ImageVersions2;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemVisualMedia;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmRavenMediaBinding binding;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectItemRavenMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmRavenMediaBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
maxWidth = windowWidth - margin - dmRadiusSmall;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final DirectItemVisualMedia visualMedia = directItemModel.getVisualMedia();
|
||||
final Media media = visualMedia.getMedia();
|
||||
if (media == null) return;
|
||||
setExpiryInfo(visualMedia);
|
||||
setPreview(visualMedia, messageDirection);
|
||||
final boolean expired = media.getPk() == null;
|
||||
if (expired) return;
|
||||
itemView.setOnClickListener(v -> openMedia(media));
|
||||
/*final boolean isExpired = visualMedia == null || (mediaModel = visualMedia.getMedia()) == null ||
|
||||
TextUtils.isEmpty(mediaModel.getThumbUrl()) && mediaModel.getPk() < 1;
|
||||
|
||||
RavenExpiringMediaActionSummary mediaActionSummary = null;
|
||||
if (visualMedia != null) {
|
||||
mediaActionSummary = visualMedia.getExpiringMediaActionSummary();
|
||||
}
|
||||
binding.mediaExpiredIcon.setVisibility(isExpired ? View.VISIBLE : View.GONE);
|
||||
|
||||
int textRes = R.string.dms_inbox_raven_media_unknown;
|
||||
if (isExpired) textRes = R.string.dms_inbox_raven_media_expired;
|
||||
|
||||
if (!isExpired) {
|
||||
if (mediaActionSummary != null) {
|
||||
final ActionType expiringMediaType = mediaActionSummary.getType();
|
||||
|
||||
if (expiringMediaType == ActionType.DELIVERED)
|
||||
textRes = R.string.dms_inbox_raven_media_delivered;
|
||||
else if (expiringMediaType == ActionType.SENT)
|
||||
textRes = R.string.dms_inbox_raven_media_sent;
|
||||
else if (expiringMediaType == ActionType.OPENED)
|
||||
textRes = R.string.dms_inbox_raven_media_opened;
|
||||
else if (expiringMediaType == ActionType.REPLAYED)
|
||||
textRes = R.string.dms_inbox_raven_media_replayed;
|
||||
else if (expiringMediaType == ActionType.SENDING)
|
||||
textRes = R.string.dms_inbox_raven_media_sending;
|
||||
else if (expiringMediaType == ActionType.BLOCKED)
|
||||
textRes = R.string.dms_inbox_raven_media_blocked;
|
||||
else if (expiringMediaType == ActionType.SUGGESTED)
|
||||
textRes = R.string.dms_inbox_raven_media_suggested;
|
||||
else if (expiringMediaType == ActionType.SCREENSHOT)
|
||||
textRes = R.string.dms_inbox_raven_media_screenshot;
|
||||
else if (expiringMediaType == ActionType.CANNOT_DELIVER)
|
||||
textRes = R.string.dms_inbox_raven_media_cant_deliver;
|
||||
}
|
||||
|
||||
final RavenMediaViewMode ravenMediaViewMode = visualMedia.getViewType();
|
||||
if (ravenMediaViewMode == RavenMediaViewMode.PERMANENT || ravenMediaViewMode == RavenMediaViewMode.REPLAYABLE) {
|
||||
final MediaItemType mediaType = mediaModel.getMediaType();
|
||||
textRes = -1;
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO || mediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
mediaModel.getHeight(),
|
||||
mediaModel.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
}
|
||||
}
|
||||
if (textRes != -1) {
|
||||
binding.tvMessage.setText(context.getText(textRes));
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
}*/
|
||||
}
|
||||
|
||||
private void setExpiryInfo(final DirectItemVisualMedia visualMedia) {
|
||||
final Media media = visualMedia.getMedia();
|
||||
final RavenMediaViewMode viewMode = visualMedia.getViewMode();
|
||||
if (viewMode != RavenMediaViewMode.PERMANENT) {
|
||||
final MediaItemType mediaType = media.getMediaType();
|
||||
final boolean expired = media.getPk() == null;
|
||||
final int info;
|
||||
switch (mediaType) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
if (expired) {
|
||||
info = R.string.raven_image_expired;
|
||||
break;
|
||||
}
|
||||
info = R.string.raven_image_info;
|
||||
break;
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
if (expired) {
|
||||
info = R.string.raven_video_expired;
|
||||
break;
|
||||
}
|
||||
info = R.string.raven_video_info;
|
||||
break;
|
||||
default:
|
||||
if (expired) {
|
||||
info = R.string.raven_msg_expired;
|
||||
break;
|
||||
}
|
||||
info = R.string.raven_msg_info;
|
||||
break;
|
||||
}
|
||||
binding.expiryInfo.setVisibility(View.VISIBLE);
|
||||
binding.expiryInfo.setText(info);
|
||||
return;
|
||||
}
|
||||
binding.expiryInfo.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setPreview(final DirectItemVisualMedia visualMedia,
|
||||
final MessageDirection messageDirection) {
|
||||
final Media media = visualMedia.getMedia();
|
||||
final boolean expired = media.getPk() == null;
|
||||
if (expired) {
|
||||
binding.preview.setVisibility(View.GONE);
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
final RoundingParams roundingParams = messageDirection == MessageDirection.INCOMING
|
||||
? RoundingParams.fromCornersRadii(dmRadiusSmall, dmRadius, dmRadius, dmRadius)
|
||||
: RoundingParams.fromCornersRadii(dmRadius, dmRadiusSmall, dmRadius, dmRadius);
|
||||
binding.preview.setHierarchy(new GenericDraweeHierarchyBuilder(itemView.getResources())
|
||||
.setRoundingParams(roundingParams)
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
|
||||
.build());
|
||||
final MediaItemType modelMediaType = media.getMediaType();
|
||||
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO || modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
media.getOriginalHeight(),
|
||||
media.getOriginalWidth(),
|
||||
mediaImageMaxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.preview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.preview.requestLayout();
|
||||
final String thumbUrl = ResponseBodyUtils.getThumbUrl(media);
|
||||
binding.preview.setImageURI(thumbUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowLongClick() {
|
||||
return false; // disabling until confirmed
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmReelShareBinding;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.ImageVersions2;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemReelShare;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemReelShareViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmReelShareBinding binding;
|
||||
|
||||
public DirectItemReelShareViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmReelShareBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
||||
final DirectItemReelShare reelShare = item.getReelShare();
|
||||
final String type = reelShare.getType();
|
||||
if (type == null) return;
|
||||
final boolean isSelf = isSelf(item);
|
||||
final Media media = reelShare.getMedia();
|
||||
if (media == null) return;
|
||||
final User user = media.getUser();
|
||||
if (user == null) return;
|
||||
final boolean expired = media.getMediaType() == null;
|
||||
if (expired) {
|
||||
binding.preview.setVisibility(View.GONE);
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
binding.quoteLine.setVisibility(View.GONE);
|
||||
binding.reaction.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.preview.setVisibility(View.VISIBLE);
|
||||
binding.typeIcon.setVisibility(View.VISIBLE);
|
||||
binding.quoteLine.setVisibility(View.VISIBLE);
|
||||
binding.reaction.setVisibility(View.VISIBLE);
|
||||
}
|
||||
setGravity(messageDirection, expired);
|
||||
if (type.equals("reply")) {
|
||||
setReply(messageDirection, reelShare, isSelf);
|
||||
}
|
||||
if (type.equals("reaction")) {
|
||||
setReaction(messageDirection, reelShare, isSelf, expired);
|
||||
}
|
||||
if (type.equals("mention")) {
|
||||
setMention(isSelf);
|
||||
}
|
||||
if (!expired) {
|
||||
setPreview(media);
|
||||
itemView.setOnClickListener(v -> openMedia(media));
|
||||
}
|
||||
}
|
||||
|
||||
private void setGravity(final MessageDirection messageDirection, final boolean expired) {
|
||||
final boolean isIncoming = messageDirection == MessageDirection.INCOMING;
|
||||
binding.shareInfo.setGravity(isIncoming ? Gravity.START : Gravity.END);
|
||||
if (!expired) {
|
||||
binding.quoteLine.setVisibility(isIncoming ? View.VISIBLE : View.GONE);
|
||||
binding.quoteLineEnd.setVisibility(isIncoming ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
final ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) binding.quoteLine.getLayoutParams();
|
||||
layoutParams.horizontalBias = isIncoming ? 0 : 1;
|
||||
final ConstraintLayout.LayoutParams messageLayoutParams = (ConstraintLayout.LayoutParams) binding.message.getLayoutParams();
|
||||
messageLayoutParams.startToStart = isIncoming ? ConstraintLayout.LayoutParams.PARENT_ID : ConstraintLayout.LayoutParams.UNSET;
|
||||
messageLayoutParams.endToEnd = isIncoming ? ConstraintLayout.LayoutParams.UNSET : ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
messageLayoutParams.setMarginStart(isIncoming ? messageInfoPaddingSmall : 0);
|
||||
messageLayoutParams.setMarginEnd(isIncoming ? 0 : messageInfoPaddingSmall);
|
||||
final ConstraintLayout.LayoutParams reactionLayoutParams = (ConstraintLayout.LayoutParams) binding.reaction.getLayoutParams();
|
||||
final int previewId = binding.preview.getId();
|
||||
if (isIncoming) {
|
||||
reactionLayoutParams.startToEnd = previewId;
|
||||
reactionLayoutParams.endToEnd = previewId;
|
||||
reactionLayoutParams.startToStart = ConstraintLayout.LayoutParams.UNSET;
|
||||
reactionLayoutParams.endToStart = ConstraintLayout.LayoutParams.UNSET;
|
||||
} else {
|
||||
reactionLayoutParams.startToStart = previewId;
|
||||
reactionLayoutParams.endToStart = previewId;
|
||||
reactionLayoutParams.startToEnd = ConstraintLayout.LayoutParams.UNSET;
|
||||
reactionLayoutParams.endToEnd = ConstraintLayout.LayoutParams.UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
private void setReply(final MessageDirection messageDirection,
|
||||
final DirectItemReelShare reelShare,
|
||||
final boolean isSelf) {
|
||||
final int info = isSelf ? R.string.replied_story_outgoing : R.string.replied_story_incoming;
|
||||
binding.shareInfo.setText(info);
|
||||
binding.reaction.setVisibility(View.GONE);
|
||||
final String text = reelShare.getText();
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
binding.message.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
setMessage(messageDirection, text);
|
||||
}
|
||||
|
||||
private void setReaction(final MessageDirection messageDirection,
|
||||
final DirectItemReelShare reelShare,
|
||||
final boolean isSelf,
|
||||
final boolean expired) {
|
||||
final int info = isSelf ? R.string.reacted_story_outgoing : R.string.reacted_story_incoming;
|
||||
binding.shareInfo.setText(info);
|
||||
binding.message.setVisibility(View.GONE);
|
||||
final String text = reelShare.getText();
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
binding.reaction.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
if (expired) {
|
||||
setMessage(messageDirection, text);
|
||||
return;
|
||||
}
|
||||
binding.reaction.setVisibility(View.VISIBLE);
|
||||
binding.reaction.setText(text);
|
||||
}
|
||||
|
||||
private void setMention(final boolean isSelf) {
|
||||
final int info = isSelf ? R.string.mentioned_story_outgoing : R.string.mentioned_story_incoming;
|
||||
binding.shareInfo.setText(info);
|
||||
binding.message.setVisibility(View.GONE);
|
||||
binding.reaction.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setMessage(final MessageDirection messageDirection, final String text) {
|
||||
binding.message.setVisibility(View.VISIBLE);
|
||||
binding.message.setBackgroundResource(messageDirection == MessageDirection.INCOMING
|
||||
? R.drawable.bg_speech_bubble_incoming
|
||||
: R.drawable.bg_speech_bubble_outgoing);
|
||||
binding.message.setText(text);
|
||||
}
|
||||
|
||||
private void setPreview(final Media media) {
|
||||
final MediaItemType mediaType = media.getMediaType();
|
||||
if (mediaType == null) return;
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO || mediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE : View.GONE);
|
||||
final RoundingParams roundingParams = RoundingParams.fromCornersRadii(dmRadiusSmall, dmRadiusSmall, dmRadiusSmall, dmRadiusSmall);
|
||||
binding.preview.setHierarchy(new GenericDraweeHierarchyBuilder(itemView.getResources())
|
||||
.setRoundingParams(roundingParams)
|
||||
.build());
|
||||
final String thumbUrl = ResponseBodyUtils.getThumbUrl(media);
|
||||
binding.preview.setImageURI(thumbUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canForward() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmStoryShareBinding;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.ImageVersions2;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemStoryShareViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmStoryShareBinding binding;
|
||||
|
||||
public DirectItemStoryShareViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmStoryShareBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem item, final MessageDirection messageDirection) {
|
||||
final Resources resources = itemView.getResources();
|
||||
int format = R.string.story_share;
|
||||
final String reelType = item.getStoryShare().getReelType();
|
||||
if (reelType == null || item.getStoryShare().getMedia() == null) {
|
||||
setExpiredStoryInfo(item);
|
||||
return;
|
||||
}
|
||||
if (reelType.equals("highlight_reel")) {
|
||||
format = R.string.story_share_highlight;
|
||||
}
|
||||
final User user = item.getStoryShare().getMedia().getUser();
|
||||
final String info = resources.getString(format, user != null ? user.getUsername() : "");
|
||||
binding.shareInfo.setText(info);
|
||||
binding.text.setVisibility(View.GONE);
|
||||
binding.ivMediaPreview.setController(null);
|
||||
final DirectItemStoryShare storyShare = item.getStoryShare();
|
||||
if (storyShare == null) return;
|
||||
setText(storyShare);
|
||||
final Media media = storyShare.getMedia();
|
||||
setupPreview(messageDirection, media);
|
||||
itemView.setOnClickListener(v -> openStory(storyShare));
|
||||
}
|
||||
|
||||
private void setupPreview(final MessageDirection messageDirection, final Media storyShareMedia) {
|
||||
final MediaItemType mediaType = storyShareMedia.getMediaType();
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO ? View.VISIBLE : View.GONE);
|
||||
final RoundingParams roundingParams = messageDirection == MessageDirection.INCOMING
|
||||
? RoundingParams.fromCornersRadii(dmRadiusSmall, dmRadius, dmRadius, dmRadius)
|
||||
: RoundingParams.fromCornersRadii(dmRadius, dmRadiusSmall, dmRadius, dmRadius);
|
||||
binding.ivMediaPreview.setHierarchy(new GenericDraweeHierarchyBuilder(itemView.getResources())
|
||||
.setRoundingParams(roundingParams)
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
|
||||
.build());
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
storyShareMedia.getOriginalHeight(),
|
||||
storyShareMedia.getOriginalWidth(),
|
||||
mediaImageMaxHeight,
|
||||
mediaImageMaxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
final String thumbUrl = ResponseBodyUtils.getThumbUrl(storyShareMedia);
|
||||
binding.ivMediaPreview.setImageURI(thumbUrl);
|
||||
}
|
||||
|
||||
private void setText(final DirectItemStoryShare storyShare) {
|
||||
final String text = storyShare.getText();
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
binding.text.setText(text);
|
||||
binding.text.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
binding.text.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setExpiredStoryInfo(final DirectItem item) {
|
||||
binding.shareInfo.setText(item.getStoryShare().getTitle());
|
||||
binding.text.setVisibility(View.VISIBLE);
|
||||
binding.text.setText(item.getStoryShare().getMessage());
|
||||
binding.ivMediaPreview.setVisibility(View.GONE);
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canForward() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
|
||||
public class DirectItemTextViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectItemTextViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
@NonNull final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final String text = directItemModel.getText();
|
||||
if (text == null) return;
|
||||
binding.tvMessage.setText(text);
|
||||
setupRamboTextListeners(binding.tvMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showBackground() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmActionLogBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemActionLog;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemVideoCallEvent;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemVideoCallEventViewHolder extends DirectItemViewHolder {
|
||||
|
||||
private final LayoutDmActionLogBinding binding;
|
||||
|
||||
public DirectItemVideoCallEventViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
final LayoutDmActionLogBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final DirectItemVideoCallEvent videoCallEvent = directItemModel.getVideoCallEvent();
|
||||
final String text = videoCallEvent.getDescription();
|
||||
final SpannableStringBuilder sb = new SpannableStringBuilder(text);
|
||||
final List<DirectItemActionLog.TextRange> textAttributes = videoCallEvent.getTextAttributes();
|
||||
if (textAttributes != null && !textAttributes.isEmpty()) {
|
||||
for (final DirectItemActionLog.TextRange textAttribute : textAttributes) {
|
||||
if (!TextUtils.isEmpty(textAttribute.getColor())) {
|
||||
final ForegroundColorSpan colorSpan = new ForegroundColorSpan(itemView.getResources().getColor(R.color.deep_orange_400));
|
||||
sb.setSpan(colorSpan, textAttribute.getStart(), textAttribute.getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
if (!TextUtils.isEmpty(textAttribute.getIntent())) {
|
||||
final ClickableSpan clickableSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull final View widget) {
|
||||
|
||||
}
|
||||
};
|
||||
sb.setSpan(clickableSpan, textAttribute.getStart(), textAttribute.getEnd(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.tvMessage.setMaxLines(1);
|
||||
binding.tvMessage.setText(sb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowMessageDirectionGravity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showUserDetailsInGroup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showMessageInfo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowLongClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,608 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.transition.TransitionManager;
|
||||
|
||||
import com.google.android.material.transition.MaterialFade;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemInternalLongClickListener;
|
||||
import awais.instagrabber.customviews.DirectItemContextMenu;
|
||||
import awais.instagrabber.customviews.DirectItemFrameLayout;
|
||||
import awais.instagrabber.customviews.RamboTextViewV2;
|
||||
import awais.instagrabber.customviews.helpers.SwipeAndRestoreItemTouchHelperCallback.SwipeableViewHolder;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.models.enums.DirectItemType;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemReactions;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.DMUtils;
|
||||
import awais.instagrabber.utils.DeepLinkParser;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
|
||||
public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder implements SwipeableViewHolder {
|
||||
private static final String TAG = DirectItemViewHolder.class.getSimpleName();
|
||||
// private static final List<Integer> THREAD_CHANGING_OPTIONS = ImmutableList.of(R.id.unsend);
|
||||
|
||||
private final LayoutDmBaseBinding binding;
|
||||
private final User currentUser;
|
||||
private final DirectThread thread;
|
||||
private final int groupMessageWidth;
|
||||
private final List<Long> userIds;
|
||||
private final DirectItemCallback callback;
|
||||
private final int reactionAdjustMargin;
|
||||
private final AccelerateDecelerateInterpolator accelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
|
||||
|
||||
protected final int margin;
|
||||
protected final int dmRadius;
|
||||
protected final int dmRadiusSmall;
|
||||
protected final int messageInfoPaddingSmall;
|
||||
protected final int mediaImageMaxHeight;
|
||||
protected final int windowWidth;
|
||||
protected final int mediaImageMaxWidth;
|
||||
protected final int reactionTranslationYType1;
|
||||
protected final int reactionTranslationYType2;
|
||||
|
||||
private boolean selected = false;
|
||||
private DirectItemInternalLongClickListener longClickListener;
|
||||
private DirectItem item;
|
||||
private ViewPropertyAnimator shrinkGrowAnimator;
|
||||
private MessageDirection messageDirection;
|
||||
// private View.OnLayoutChangeListener layoutChangeListener;
|
||||
|
||||
public DirectItemViewHolder(@NonNull final LayoutDmBaseBinding binding,
|
||||
@NonNull final User currentUser,
|
||||
@NonNull final DirectThread thread,
|
||||
@NonNull final DirectItemCallback callback) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.currentUser = currentUser;
|
||||
this.thread = thread;
|
||||
this.callback = callback;
|
||||
userIds = thread.getUsers()
|
||||
.stream()
|
||||
.map(User::getPk)
|
||||
.collect(Collectors.toList());
|
||||
binding.ivProfilePic.setVisibility(thread.isGroup() ? View.VISIBLE : View.GONE);
|
||||
binding.ivProfilePic.setOnClickListener(null);
|
||||
final Resources resources = itemView.getResources();
|
||||
margin = resources.getDimensionPixelSize(R.dimen.dm_message_item_margin);
|
||||
final int avatarSize = resources.getDimensionPixelSize(R.dimen.dm_message_item_avatar_size);
|
||||
dmRadius = resources.getDimensionPixelSize(R.dimen.dm_message_card_radius);
|
||||
dmRadiusSmall = resources.getDimensionPixelSize(R.dimen.dm_message_card_radius_small);
|
||||
messageInfoPaddingSmall = resources.getDimensionPixelSize(R.dimen.dm_message_info_padding_small);
|
||||
windowWidth = resources.getDisplayMetrics().widthPixels;
|
||||
mediaImageMaxHeight = resources.getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
reactionAdjustMargin = resources.getDimensionPixelSize(R.dimen.dm_reaction_adjust_margin);
|
||||
final int groupWidthCorrection = avatarSize + messageInfoPaddingSmall * 3;
|
||||
mediaImageMaxWidth = windowWidth - margin - (thread.isGroup() ? groupWidthCorrection : messageInfoPaddingSmall * 2);
|
||||
// messageInfoPaddingSmall is used cuz it's also 4dp, 1 avatar margin + 2 paddings = 3
|
||||
groupMessageWidth = windowWidth - margin - groupWidthCorrection;
|
||||
reactionTranslationYType1 = resources.getDimensionPixelSize(R.dimen.dm_reaction_translation_y_type_1);
|
||||
reactionTranslationYType2 = resources.getDimensionPixelSize(R.dimen.dm_reaction_translation_y_type_2);
|
||||
}
|
||||
|
||||
public void bind(final int position, final DirectItem item) {
|
||||
this.item = item;
|
||||
messageDirection = isSelf(item) ? MessageDirection.OUTGOING : MessageDirection.INCOMING;
|
||||
// Asynchronous binding causes some weird behaviour
|
||||
// itemView.post(() -> bindBase(item, messageDirection, position));
|
||||
// itemView.post(() -> bindItem(item, messageDirection));
|
||||
// itemView.post(() -> setupLongClickListener(position, messageDirection));
|
||||
bindBase(item, messageDirection, position);
|
||||
bindItem(item, messageDirection);
|
||||
setupLongClickListener(position, messageDirection);
|
||||
}
|
||||
|
||||
private void bindBase(final DirectItem item, final MessageDirection messageDirection, final int position) {
|
||||
final FrameLayout.LayoutParams containerLayoutParams = (FrameLayout.LayoutParams) binding.container.getLayoutParams();
|
||||
final DirectItemType itemType = item.getItemType();
|
||||
setMessageDirectionGravity(messageDirection, containerLayoutParams);
|
||||
setGroupUserDetails(item, messageDirection);
|
||||
setBackground(messageDirection);
|
||||
setMessageInfo(item, messageDirection);
|
||||
if (itemType == DirectItemType.REEL_SHARE) {
|
||||
containerLayoutParams.setMarginStart(0);
|
||||
containerLayoutParams.setMarginEnd(0);
|
||||
}
|
||||
if (itemType == DirectItemType.TEXT || itemType == DirectItemType.LINK) {
|
||||
binding.messageInfo.setPadding(0, 0, dmRadius, dmRadiusSmall);
|
||||
} else {
|
||||
if (showMessageInfo()) {
|
||||
binding.messageInfo.setPadding(0, 0, messageInfoPaddingSmall, dmRadiusSmall);
|
||||
}
|
||||
}
|
||||
setupReply(item, messageDirection);
|
||||
setReactions(item, position);
|
||||
if (item.getRepliedToMessage() == null && item.showForwardAttribution()) {
|
||||
setForwardInfo(messageDirection);
|
||||
}
|
||||
}
|
||||
|
||||
private void setBackground(final MessageDirection messageDirection) {
|
||||
if (showBackground()) {
|
||||
binding.background.setBackgroundResource(messageDirection == MessageDirection.INCOMING ? R.drawable.bg_speech_bubble_incoming
|
||||
: R.drawable.bg_speech_bubble_outgoing);
|
||||
return;
|
||||
}
|
||||
binding.background.setBackgroundResource(0);
|
||||
}
|
||||
|
||||
private void setGroupUserDetails(final DirectItem item, final MessageDirection messageDirection) {
|
||||
if (showUserDetailsInGroup()) {
|
||||
binding.ivProfilePic.setVisibility(messageDirection == MessageDirection.INCOMING && thread.isGroup() ? View.VISIBLE : View.GONE);
|
||||
binding.tvUsername.setVisibility(messageDirection == MessageDirection.INCOMING && thread.isGroup() ? View.VISIBLE : View.GONE);
|
||||
if (messageDirection == MessageDirection.INCOMING && thread.isGroup()) {
|
||||
final User user = getUser(item.getUserId(), thread.getUsers());
|
||||
if (user != null) {
|
||||
binding.tvUsername.setText(user.getUsername());
|
||||
binding.ivProfilePic.setImageURI(user.getProfilePicUrl());
|
||||
}
|
||||
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) binding.chatMessageLayout.getLayoutParams();
|
||||
layoutParams.matchConstraintMaxWidth = groupMessageWidth;
|
||||
binding.chatMessageLayout.setLayoutParams(layoutParams);
|
||||
}
|
||||
return;
|
||||
}
|
||||
binding.ivProfilePic.setVisibility(View.GONE);
|
||||
binding.tvUsername.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setMessageDirectionGravity(final MessageDirection messageDirection,
|
||||
final FrameLayout.LayoutParams containerLayoutParams) {
|
||||
if (allowMessageDirectionGravity()) {
|
||||
containerLayoutParams.setMarginStart(messageDirection == MessageDirection.OUTGOING ? margin : 0);
|
||||
containerLayoutParams.setMarginEnd(messageDirection == MessageDirection.INCOMING ? margin : 0);
|
||||
containerLayoutParams.gravity = messageDirection == MessageDirection.INCOMING ? Gravity.START : Gravity.END;
|
||||
return;
|
||||
}
|
||||
containerLayoutParams.gravity = Gravity.CENTER;
|
||||
}
|
||||
|
||||
private void setMessageInfo(final DirectItem item, final MessageDirection messageDirection) {
|
||||
if (showMessageInfo()) {
|
||||
binding.messageInfo.setVisibility(View.VISIBLE);
|
||||
binding.deliveryStatus.setVisibility(messageDirection == MessageDirection.OUTGOING ? View.VISIBLE : View.GONE);
|
||||
binding.messageTime.setText(DateFormat.getTimeFormat(itemView.getContext()).format(item.getDate()));
|
||||
if (messageDirection == MessageDirection.OUTGOING) {
|
||||
if (item.isPending()) {
|
||||
binding.deliveryStatus.setImageResource(R.drawable.ic_check_24);
|
||||
} else {
|
||||
final boolean read = DMUtils.isRead(item,
|
||||
thread.getLastSeenAt(),
|
||||
userIds
|
||||
);
|
||||
binding.deliveryStatus.setImageResource(R.drawable.ic_check_all_24);
|
||||
ImageViewCompat.setImageTintList(
|
||||
binding.deliveryStatus,
|
||||
ColorStateList.valueOf(itemView.getResources().getColor(read ? R.color.blue_500 : R.color.grey_500))
|
||||
);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
binding.messageInfo.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setupReply(final DirectItem item, final MessageDirection messageDirection) {
|
||||
if (item.getRepliedToMessage() != null) {
|
||||
setReply(item, messageDirection, thread.getUsers());
|
||||
} else {
|
||||
binding.quoteLine.setVisibility(View.GONE);
|
||||
binding.replyContainer.setVisibility(View.GONE);
|
||||
binding.replyInfo.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setReply(final DirectItem item,
|
||||
final MessageDirection messageDirection,
|
||||
final List<User> users) {
|
||||
final DirectItem replied = item.getRepliedToMessage();
|
||||
final DirectItemType itemType = replied.getItemType();
|
||||
final Resources resources = itemView.getResources();
|
||||
String text = null;
|
||||
String url = null;
|
||||
switch (itemType) {
|
||||
case TEXT:
|
||||
text = replied.getText();
|
||||
break;
|
||||
case LINK:
|
||||
text = replied.getLink().getText();
|
||||
break;
|
||||
case PLACEHOLDER:
|
||||
text = replied.getPlaceholder().getMessage();
|
||||
break;
|
||||
case MEDIA:
|
||||
url = ResponseBodyUtils.getThumbUrl(replied.getMedia());
|
||||
break;
|
||||
case RAVEN_MEDIA:
|
||||
url = ResponseBodyUtils.getThumbUrl(replied.getVisualMedia().getMedia());
|
||||
break;
|
||||
case VOICE_MEDIA:
|
||||
text = resources.getString(R.string.voice_message);
|
||||
break;
|
||||
case MEDIA_SHARE:
|
||||
Media mediaShare = replied.getMediaShare();
|
||||
if (mediaShare.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
mediaShare = mediaShare.getCarouselMedia().get(0);
|
||||
}
|
||||
url = ResponseBodyUtils.getThumbUrl(mediaShare);
|
||||
break;
|
||||
case REEL_SHARE:
|
||||
text = replied.getReelShare().getText();
|
||||
break;
|
||||
// Below types cannot be replied to
|
||||
// case LIKE:
|
||||
// text = "❤️";
|
||||
// break;
|
||||
// case PROFILE:
|
||||
// text = "@" + replied.getProfile().getUsername();
|
||||
// break;
|
||||
// case CLIP:
|
||||
// url = ResponseBodyUtils.getThumbUrl(replied.getClip().getClip().getImageVersions2());
|
||||
// break;
|
||||
// case FELIX_SHARE:
|
||||
// url = ResponseBodyUtils.getThumbUrl(replied.getFelixShare().getVideo().getImageVersions2());
|
||||
// break;
|
||||
// case STORY_SHARE:
|
||||
// final DirectItemMedia media = replied.getStoryShare().getMedia();
|
||||
// if (media == null) break;
|
||||
// url = ResponseBodyUtils.getThumbUrl(media.getImageVersions2());
|
||||
// break;
|
||||
// case LOCATION
|
||||
}
|
||||
if (text == null && url == null) {
|
||||
binding.quoteLine.setVisibility(View.GONE);
|
||||
binding.replyContainer.setVisibility(View.GONE);
|
||||
binding.replyInfo.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
setReplyGravity(messageDirection);
|
||||
final String info = setReplyInfo(item, replied, users, resources);
|
||||
binding.replyInfo.setVisibility(View.VISIBLE);
|
||||
binding.replyInfo.setText(info);
|
||||
binding.quoteLine.setVisibility(View.VISIBLE);
|
||||
binding.replyContainer.setVisibility(View.VISIBLE);
|
||||
if (url != null) {
|
||||
binding.replyText.setVisibility(View.GONE);
|
||||
binding.replyImage.setVisibility(View.VISIBLE);
|
||||
binding.replyImage.setImageURI(url);
|
||||
return;
|
||||
}
|
||||
binding.replyImage.setVisibility(View.GONE);
|
||||
final Drawable background = binding.replyText.getBackground().mutate();
|
||||
background.setTint(replied.getUserId() != currentUser.getPk()
|
||||
? resources.getColor(R.color.grey_600)
|
||||
: resources.getColor(R.color.deep_purple_400));
|
||||
binding.replyText.setBackgroundDrawable(background);
|
||||
binding.replyText.setVisibility(View.VISIBLE);
|
||||
binding.replyText.setText(text);
|
||||
}
|
||||
|
||||
private String setReplyInfo(final DirectItem item,
|
||||
final DirectItem replied,
|
||||
final List<User> users,
|
||||
final Resources resources) {
|
||||
final long repliedToUserId = replied.getUserId();
|
||||
if (repliedToUserId == item.getUserId() && item.getUserId() == currentUser.getPk()) {
|
||||
// User replied to own message
|
||||
return resources.getString(R.string.replied_to_yourself);
|
||||
}
|
||||
if (repliedToUserId == item.getUserId()) {
|
||||
// opposite user replied to their own message
|
||||
return resources.getString(R.string.replied_to_themself);
|
||||
}
|
||||
final User user = getUser(repliedToUserId, users);
|
||||
final String repliedToUsername = user != null ? user.getUsername() : "";
|
||||
if (item.getUserId() == currentUser.getPk()) {
|
||||
return thread.isGroup()
|
||||
? resources.getString(R.string.replied_you_group, repliedToUsername)
|
||||
: resources.getString(R.string.replied_you);
|
||||
}
|
||||
if (repliedToUserId == currentUser.getPk()) {
|
||||
return resources.getString(R.string.replied_to_you);
|
||||
}
|
||||
return resources.getString(R.string.replied_group, repliedToUsername);
|
||||
}
|
||||
|
||||
private void setForwardInfo(final MessageDirection direction) {
|
||||
binding.replyInfo.setVisibility(View.VISIBLE);
|
||||
binding.replyInfo.setText(direction == MessageDirection.OUTGOING ? R.string.forward_outgoing : R.string.forward_incoming);
|
||||
}
|
||||
|
||||
private void setReplyGravity(final MessageDirection messageDirection) {
|
||||
final boolean isIncoming = messageDirection == MessageDirection.INCOMING;
|
||||
final ConstraintLayout.LayoutParams quoteLineLayoutParams = (ConstraintLayout.LayoutParams) binding.quoteLine.getLayoutParams();
|
||||
final ConstraintLayout.LayoutParams replyContainerLayoutParams = (ConstraintLayout.LayoutParams) binding.replyContainer.getLayoutParams();
|
||||
final ConstraintLayout.LayoutParams replyInfoLayoutParams = (ConstraintLayout.LayoutParams) binding.replyInfo.getLayoutParams();
|
||||
final int profilePicId = binding.ivProfilePic.getId();
|
||||
final int replyContainerId = binding.replyContainer.getId();
|
||||
final int quoteLineId = binding.quoteLine.getId();
|
||||
quoteLineLayoutParams.startToEnd = isIncoming ? profilePicId : replyContainerId;
|
||||
quoteLineLayoutParams.endToStart = isIncoming ? replyContainerId : ConstraintLayout.LayoutParams.UNSET;
|
||||
quoteLineLayoutParams.endToEnd = isIncoming ? ConstraintLayout.LayoutParams.UNSET : ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
replyContainerLayoutParams.startToEnd = isIncoming ? quoteLineId : profilePicId;
|
||||
replyContainerLayoutParams.endToEnd = isIncoming ? ConstraintLayout.LayoutParams.PARENT_ID : ConstraintLayout.LayoutParams.UNSET;
|
||||
replyContainerLayoutParams.endToStart = isIncoming ? ConstraintLayout.LayoutParams.UNSET : quoteLineId;
|
||||
replyInfoLayoutParams.startToEnd = isIncoming ? quoteLineId : ConstraintLayout.LayoutParams.UNSET;
|
||||
replyInfoLayoutParams.endToStart = isIncoming ? ConstraintLayout.LayoutParams.UNSET : quoteLineId;
|
||||
}
|
||||
|
||||
private void setReactions(final DirectItem item, final int position) {
|
||||
binding.getRoot().post(() -> {
|
||||
MaterialFade materialFade = new MaterialFade();
|
||||
materialFade.addTarget(binding.emojis);
|
||||
TransitionManager.beginDelayedTransition(binding.getRoot(), materialFade);
|
||||
final DirectItemReactions reactions = item.getReactions();
|
||||
final List<DirectItemEmojiReaction> emojis = reactions != null ? reactions.getEmojis() : null;
|
||||
if (emojis == null || emojis.isEmpty()) {
|
||||
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, 0);
|
||||
binding.reactionsWrapper.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
binding.reactionsWrapper.setVisibility(View.VISIBLE);
|
||||
binding.reactionsWrapper.setTranslationY(getReactionsTranslationY());
|
||||
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, reactionAdjustMargin);
|
||||
binding.emojis.setEmojis(emojis.stream()
|
||||
.map(DirectItemEmojiReaction::getEmoji)
|
||||
.collect(Collectors.toList()));
|
||||
// binding.emojis.setEmojis(ImmutableList.of("😣",
|
||||
// "😖",
|
||||
// "😫",
|
||||
// "😩",
|
||||
// "🥺",
|
||||
// "😢",
|
||||
// "😭",
|
||||
// "😤",
|
||||
// "😠",
|
||||
// "😡",
|
||||
// "🤬"));
|
||||
binding.emojis.setOnClickListener(v -> callback.onReactionClick(item, position));
|
||||
// final List<DirectUser> reactedUsers = emojis.stream()
|
||||
// .map(DirectItemEmojiReaction::getSenderId)
|
||||
// .distinct()
|
||||
// .map(userId -> getUser(userId, users))
|
||||
// .collect(Collectors.toList());
|
||||
// for (final DirectUser user : reactedUsers) {
|
||||
// if (user == null) continue;
|
||||
// final ProfilePicView profilePicView = new ProfilePicView(itemView.getContext());
|
||||
// profilePicView.setSize(ProfilePicView.Size.TINY);
|
||||
// profilePicView.setImageURI(user.getProfilePicUrl());
|
||||
// binding.reactions.addView(profilePicView);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean isSelf(final DirectItem directItem) {
|
||||
return directItem.getUserId() == currentUser.getPk();
|
||||
}
|
||||
|
||||
public void setItemView(final View view) {
|
||||
this.binding.message.addView(view);
|
||||
}
|
||||
|
||||
public abstract void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection);
|
||||
|
||||
@Nullable
|
||||
protected User getUser(final long userId, final List<User> users) {
|
||||
if (userId == currentUser.getPk()) {
|
||||
return currentUser;
|
||||
}
|
||||
if (users == null) return null;
|
||||
for (final User user : users) {
|
||||
if (userId != user.getPk()) continue;
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean allowMessageDirectionGravity() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean showUserDetailsInGroup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean showBackground() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean showMessageInfo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean allowLongClick() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean allowReaction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean canForward() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List<DirectItemContextMenu.MenuItem> getLongClickOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected int getReactionsTranslationY() {
|
||||
return reactionTranslationYType1;
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public void cleanup() {
|
||||
// if (layoutChangeListener != null) {
|
||||
// binding.container.removeOnLayoutChangeListener(layoutChangeListener);
|
||||
// }
|
||||
}
|
||||
|
||||
protected void setupRamboTextListeners(@NonNull final RamboTextViewV2 textView) {
|
||||
textView.addOnHashtagListener(autoLinkItem -> callback.onHashtagClick(autoLinkItem.getOriginalText().trim()));
|
||||
textView.addOnMentionClickListener(autoLinkItem -> openProfile(autoLinkItem.getOriginalText().trim()));
|
||||
textView.addOnEmailClickListener(autoLinkItem -> callback.onEmailClick(autoLinkItem.getOriginalText().trim()));
|
||||
textView.addOnURLClickListener(autoLinkItem -> openURL(autoLinkItem.getOriginalText().trim()));
|
||||
}
|
||||
|
||||
protected void openProfile(final String username) {
|
||||
callback.onMentionClick(username);
|
||||
}
|
||||
|
||||
protected void openLocation(final long locationId) {
|
||||
callback.onLocationClick(locationId);
|
||||
}
|
||||
|
||||
protected void openURL(final String url) {
|
||||
callback.onURLClick(url);
|
||||
}
|
||||
|
||||
protected void openMedia(final Media media) {
|
||||
callback.onMediaClick(media);
|
||||
}
|
||||
|
||||
protected void openStory(final DirectItemStoryShare storyShare) {
|
||||
callback.onStoryClick(storyShare);
|
||||
}
|
||||
|
||||
protected void handleDeepLink(final String deepLinkText) {
|
||||
if (deepLinkText == null) return;
|
||||
final DeepLinkParser.DeepLink deepLink = DeepLinkParser.parse(deepLinkText);
|
||||
if (deepLink == null) return;
|
||||
switch (deepLink.getType()) {
|
||||
case USER:
|
||||
callback.onMentionClick(deepLink.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private void setupLongClickListener(final int position, final MessageDirection messageDirection) {
|
||||
if (!allowLongClick()) return;
|
||||
binding.getRoot().setOnItemLongClickListener(new DirectItemFrameLayout.OnItemLongClickListener() {
|
||||
@Override
|
||||
public void onLongClickStart(final View view) {
|
||||
itemView.post(() -> shrink());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClickCancel(final View view) {
|
||||
itemView.post(() -> grow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongClick(final View view, final float x, final float y) {
|
||||
// if (longClickListener == null) return false;
|
||||
// longClickListener.onLongClick(position, this);
|
||||
itemView.post(() -> grow());
|
||||
setSelected(true);
|
||||
showLongClickOptions(new Point((int) x, (int) y), messageDirection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showLongClickOptions(final Point location, final MessageDirection messageDirection) {
|
||||
final List<DirectItemContextMenu.MenuItem> longClickOptions = getLongClickOptions();
|
||||
final ImmutableList.Builder<DirectItemContextMenu.MenuItem> builder = ImmutableList.builder();
|
||||
if (longClickOptions != null) {
|
||||
builder.addAll(longClickOptions);
|
||||
}
|
||||
if (canForward()) {
|
||||
builder.add(new DirectItemContextMenu.MenuItem(R.id.forward, R.string.forward));
|
||||
}
|
||||
if (thread.getInputMode() != 1 && messageDirection == MessageDirection.OUTGOING) {
|
||||
builder.add(new DirectItemContextMenu.MenuItem(R.id.unsend, R.string.dms_inbox_unsend));
|
||||
}
|
||||
final DirectItemType itemType = item.getItemType();
|
||||
switch (itemType) {
|
||||
case ANIMATED_MEDIA:
|
||||
builder.add(new DirectItemContextMenu.MenuItem(R.id.detail, R.string.dms_inbox_giphy));
|
||||
break;
|
||||
case VOICE_MEDIA:
|
||||
builder.add(new DirectItemContextMenu.MenuItem(R.id.detail, R.string.action_download));
|
||||
break;
|
||||
}
|
||||
final boolean showReactions = thread.getInputMode() != 1 && allowReaction();
|
||||
final ImmutableList<DirectItemContextMenu.MenuItem> menuItems = builder.build();
|
||||
if (!showReactions && menuItems.isEmpty()) return;
|
||||
final DirectItemContextMenu menu = new DirectItemContextMenu(itemView.getContext(), showReactions, menuItems);
|
||||
menu.setOnDismissListener(() -> setSelected(false));
|
||||
menu.setOnReactionClickListener(emoji -> callback.onReaction(item, emoji));
|
||||
menu.setOnOptionSelectListener(itemId -> callback.onOptionSelect(item, itemId));
|
||||
menu.show(itemView, location);
|
||||
}
|
||||
|
||||
public void setLongClickListener(final DirectItemInternalLongClickListener longClickListener) {
|
||||
this.longClickListener = longClickListener;
|
||||
}
|
||||
|
||||
public void setSelected(final boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
private void shrink() {
|
||||
if (shrinkGrowAnimator != null) {
|
||||
shrinkGrowAnimator.cancel();
|
||||
}
|
||||
shrinkGrowAnimator = itemView.animate()
|
||||
.scaleX(0.8f)
|
||||
.scaleY(0.8f)
|
||||
.setInterpolator(accelerateDecelerateInterpolator)
|
||||
.setDuration(ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout());
|
||||
shrinkGrowAnimator.start();
|
||||
}
|
||||
|
||||
private void grow() {
|
||||
if (shrinkGrowAnimator != null) {
|
||||
shrinkGrowAnimator.cancel();
|
||||
}
|
||||
shrinkGrowAnimator = itemView.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.setInterpolator(accelerateDecelerateInterpolator)
|
||||
.setDuration(200)
|
||||
.withEndAction(() -> shrinkGrowAnimator = null);
|
||||
shrinkGrowAnimator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirection() {
|
||||
if (item == null || messageDirection == null) return ItemTouchHelper.ACTION_STATE_IDLE;
|
||||
return messageDirection == MessageDirection.OUTGOING ? ItemTouchHelper.START : ItemTouchHelper.END;
|
||||
}
|
||||
|
||||
public enum MessageDirection {
|
||||
INCOMING,
|
||||
OUTGOING
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.common.primitives.Floats;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmVoiceMediaBinding;
|
||||
import awais.instagrabber.repositories.responses.Audio;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemVoiceMedia;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static com.google.android.exoplayer2.C.TIME_UNSET;
|
||||
|
||||
public class DirectItemVoiceMediaViewHolder extends DirectItemViewHolder {
|
||||
private static final String TAG = "DirectItemVoiceMediaVH";
|
||||
|
||||
private final LayoutDmVoiceMediaBinding binding;
|
||||
private final DefaultDataSourceFactory dataSourceFactory;
|
||||
private SimpleExoPlayer player;
|
||||
private Handler handler;
|
||||
private Runnable positionChecker;
|
||||
private Player.EventListener listener;
|
||||
|
||||
public DirectItemVoiceMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmVoiceMediaBinding binding,
|
||||
final User currentUser,
|
||||
final DirectThread thread,
|
||||
final DirectItemCallback callback) {
|
||||
super(baseBinding, currentUser, thread, callback);
|
||||
this.binding = binding;
|
||||
this.dataSourceFactory = new DefaultDataSourceFactory(binding.getRoot().getContext(), "instagram");
|
||||
setItemView(binding.getRoot());
|
||||
binding.voiceMedia.getLayoutParams().width = mediaImageMaxWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection) {
|
||||
final DirectItemVoiceMedia voiceMedia = directItemModel.getVoiceMedia();
|
||||
if (voiceMedia == null) return;
|
||||
final Media media = voiceMedia.getMedia();
|
||||
if (media == null) return;
|
||||
final Audio audio = media.getAudio();
|
||||
if (audio == null) return;
|
||||
final List<Float> waveformData = audio.getWaveformData();
|
||||
binding.waveformSeekBar.setSample(Floats.toArray(waveformData));
|
||||
binding.waveformSeekBar.setEnabled(false);
|
||||
final String text = String.format("%s/%s", TextUtils.millisToTimeString(0), TextUtils.millisToTimeString(audio.getDuration()));
|
||||
binding.duration.setText(text);
|
||||
final AudioItemState audioItemState = new AudioItemState();
|
||||
player = new SimpleExoPlayer.Builder(itemView.getContext()).build();
|
||||
player.setVolume(1);
|
||||
player.setPlayWhenReady(true);
|
||||
player.setRepeatMode(Player.REPEAT_MODE_OFF);
|
||||
handler = new Handler();
|
||||
final long initialDelay = 0;
|
||||
final long recurringDelay = 60;
|
||||
positionChecker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (handler != null) {
|
||||
handler.removeCallbacks(this);
|
||||
}
|
||||
if (player == null) return;
|
||||
final long currentPosition = player.getCurrentPosition();
|
||||
final long duration = player.getDuration();
|
||||
// Log.d(TAG, "currentPosition: " + currentPosition + ", duration: " + duration);
|
||||
if (duration == TIME_UNSET) return;
|
||||
// final float progress = ((float) currentPosition / duration /* * 100 */);
|
||||
final int progress = (int) ((float) currentPosition / duration * 100);
|
||||
// Log.d(TAG, "progress: " + progress);
|
||||
final String text = String.format("%s/%s", TextUtils.millisToTimeString(currentPosition), TextUtils.millisToTimeString(duration));
|
||||
binding.duration.setText(text);
|
||||
binding.waveformSeekBar.setProgress(progress);
|
||||
if (handler != null) {
|
||||
handler.postDelayed(this, recurringDelay);
|
||||
}
|
||||
}
|
||||
};
|
||||
player.addListener(listener = new Player.EventListener() {
|
||||
@Override
|
||||
public void onPlaybackStateChanged(final int state) {
|
||||
if (!audioItemState.isPrepared() && state == Player.STATE_READY) {
|
||||
binding.playPause.setIconResource(R.drawable.ic_round_pause_24);
|
||||
audioItemState.setPrepared(true);
|
||||
binding.playPause.setVisibility(View.VISIBLE);
|
||||
binding.progressBar.setVisibility(View.GONE);
|
||||
if (handler != null) {
|
||||
handler.postDelayed(positionChecker, initialDelay);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (state == Player.STATE_ENDED) {
|
||||
// binding.waveformSeekBar.setProgressInPercentage(0);
|
||||
binding.waveformSeekBar.setProgress(0);
|
||||
binding.playPause.setIconResource(R.drawable.ic_round_play_arrow_24);
|
||||
if (handler != null) {
|
||||
handler.removeCallbacks(positionChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(final ExoPlaybackException error) {
|
||||
Log.e(TAG, "onPlayerError: ", error);
|
||||
}
|
||||
});
|
||||
final ProgressiveMediaSource.Factory sourceFactory = new ProgressiveMediaSource.Factory(dataSourceFactory);
|
||||
final MediaItem mediaItem = MediaItem.fromUri(audio.getAudioSrc());
|
||||
final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem);
|
||||
player.setMediaSource(mediaSource);
|
||||
binding.playPause.setOnClickListener(v -> {
|
||||
if (player == null) return;
|
||||
if (!audioItemState.isPrepared()) {
|
||||
player.prepare();
|
||||
binding.playPause.setVisibility(View.GONE);
|
||||
binding.progressBar.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
if (player.isPlaying()) {
|
||||
binding.playPause.setIconResource(R.drawable.ic_round_play_arrow_24);
|
||||
player.pause();
|
||||
return;
|
||||
}
|
||||
binding.playPause.setIconResource(R.drawable.ic_round_pause_24);
|
||||
if (player.getPlaybackState() == Player.STATE_ENDED) {
|
||||
player.seekTo(0);
|
||||
if (handler != null) {
|
||||
handler.postDelayed(positionChecker, initialDelay);
|
||||
}
|
||||
}
|
||||
binding.waveformSeekBar.setEnabled(true);
|
||||
player.play();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
super.cleanup();
|
||||
if (handler != null && positionChecker != null) {
|
||||
handler.removeCallbacks(positionChecker);
|
||||
handler = null;
|
||||
positionChecker = null;
|
||||
}
|
||||
if (player != null) {
|
||||
player.release();
|
||||
if (listener != null) {
|
||||
player.removeListener(listener);
|
||||
}
|
||||
player = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canForward() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class AudioItemState {
|
||||
private boolean prepared;
|
||||
|
||||
private AudioItemState() {}
|
||||
|
||||
public boolean isPrepared() {
|
||||
return prepared;
|
||||
}
|
||||
|
||||
public void setPrepared(final boolean prepared) {
|
||||
this.prepared = prepared;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
|
||||
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||
|
||||
public class DirectMessageActionLogViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectMessageActionLogViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final String text = directItemModel.getActionLogModel().getDescription();
|
||||
binding.tvMessage.setText(HtmlCompat.fromHtml("<small>" + text + "</small>", FROM_HTML_MODE_COMPACT));
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmAnimatedMediaBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class DirectMessageAnimatedMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmAnimatedMediaBinding binding;
|
||||
private final int maxHeight;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectMessageAnimatedMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmAnimatedMediaBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
maxWidth = Utils.displayMetrics.widthPixels - Utils.convertDpToPx(64) - getItemMargin();
|
||||
setItemView(binding.getRoot());
|
||||
setupForAnimatedMedia();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemAnimatedMediaModel animatedMediaModel = directItemModel.getAnimatedMediaModel();
|
||||
final String url = animatedMediaModel.getWebpUrl();
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
animatedMediaModel.getHeight(),
|
||||
animatedMediaModel.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
binding.ivAnimatedMessage.setVisibility(View.VISIBLE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivAnimatedMessage.getLayoutParams();
|
||||
final int width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
final int height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
layoutParams.width = width;
|
||||
layoutParams.height = height;
|
||||
binding.ivAnimatedMessage.requestLayout();
|
||||
binding.ivAnimatedMessage.setController(Fresco.newDraweeControllerBuilder()
|
||||
.setUri(url)
|
||||
.setAutoPlayAnimations(true)
|
||||
.build());
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
|
||||
public class DirectMessageDefaultViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectMessageDefaultViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final Context context = itemView.getContext();
|
||||
binding.tvMessage.setText(context.getText(R.string.dms_inbox_raven_message_unknown));
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public abstract class DirectMessageItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final int MESSAGE_INCOMING = 69;
|
||||
private static final int MESSAGE_OUTGOING = 420;
|
||||
|
||||
private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel(
|
||||
CookieUtils.getUserIdFromCookie(Utils.settingsHelper.getString(Constants.COOKIE)));
|
||||
private final LayoutDmBaseBinding binding;
|
||||
private final int itemMargin;
|
||||
|
||||
public DirectMessageItemViewHolder(@NonNull final LayoutDmBaseBinding binding, @NonNull final View.OnClickListener onClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
binding.ivProfilePic.setOnClickListener(onClickListener);
|
||||
binding.messageCard.setOnClickListener(onClickListener);
|
||||
// final String strDmYou = binding.getRoot().getContext().getString(R.string.direct_messages_you);
|
||||
itemMargin = Utils.displayMetrics.widthPixels / 5;
|
||||
}
|
||||
|
||||
public void bind(final DirectItemModel directItemModel, final List<ProfileModel> users, final List<ProfileModel> leftUsers) {
|
||||
final ProfileModel user = getUser(directItemModel.getUserId(), users, leftUsers);
|
||||
final int type = user == myProfileHolder ? MESSAGE_OUTGOING : MESSAGE_INCOMING;
|
||||
|
||||
final RecyclerView.LayoutParams itemViewLayoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams();
|
||||
itemViewLayoutParams.setMargins(type == MESSAGE_OUTGOING ? itemMargin : 0, 0,
|
||||
type == MESSAGE_INCOMING ? itemMargin : 0, 0);
|
||||
|
||||
final ViewGroup messageCardParent = (ViewGroup) binding.messageCard.getParent();
|
||||
binding.contentContainer.setGravity(type == MESSAGE_INCOMING ? Gravity.START : Gravity.END);
|
||||
|
||||
CharSequence text = "?";
|
||||
if (user != null && user != myProfileHolder) {
|
||||
text = user.getUsername();
|
||||
} else if (user == myProfileHolder) text = "";
|
||||
text = (TextUtils.isEmpty(text) ? "" : text + " - ") + directItemModel.getDateTime();
|
||||
binding.tvUsername.setText(text);
|
||||
binding.tvUsername.setGravity(type == MESSAGE_INCOMING ? Gravity.START : Gravity.END);
|
||||
binding.ivProfilePic.setVisibility(type == MESSAGE_INCOMING ? View.VISIBLE : View.GONE);
|
||||
binding.ivProfilePic.setTag(user);
|
||||
binding.likedContainer.setVisibility(directItemModel.isLiked() ? View.VISIBLE : View.GONE);
|
||||
messageCardParent.setTag(directItemModel);
|
||||
binding.messageCard.setTag(directItemModel);
|
||||
|
||||
if (type == MESSAGE_INCOMING && user != null) {
|
||||
binding.ivProfilePic.setImageURI(user.getSdProfilePic());
|
||||
}
|
||||
|
||||
bindItem(directItemModel);
|
||||
}
|
||||
|
||||
public void setItemView(final View view) {
|
||||
this.binding.messageCard.addView(view);
|
||||
}
|
||||
|
||||
public int getItemMargin() {
|
||||
return itemMargin;
|
||||
}
|
||||
|
||||
public abstract void bindItem(final DirectItemModel directItemModel);
|
||||
|
||||
@Nullable
|
||||
private ProfileModel getUser(final long userId, final List<ProfileModel> users, final List<ProfileModel> leftUsers) {
|
||||
if (users != null) {
|
||||
ProfileModel result = myProfileHolder;
|
||||
for (final ProfileModel user : users) {
|
||||
if (Long.toString(userId).equals(user.getId())) result = user;
|
||||
}
|
||||
if (leftUsers != null)
|
||||
for (final ProfileModel leftUser : leftUsers) {
|
||||
if (Long.toString(userId).equals(leftUser.getId())) result = leftUser;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void setupForAnimatedMedia() {
|
||||
binding.messageCard.setCardElevation(0);
|
||||
binding.messageCard.setCardBackgroundColor(itemView.getResources().getColor(android.R.color.transparent));
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmLinkBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectMessageLinkViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmLinkBinding binding;
|
||||
|
||||
public DirectMessageLinkViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmLinkBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemLinkModel link = directItemModel.getLinkModel();
|
||||
final DirectItemModel.DirectItemLinkContext linkContext = link.getLinkContext();
|
||||
final String linkImageUrl = linkContext.getLinkImageUrl();
|
||||
if (TextUtils.isEmpty(linkImageUrl)) {
|
||||
binding.ivLinkPreview.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.ivLinkPreview.setImageURI(linkImageUrl);
|
||||
}
|
||||
if (TextUtils.isEmpty(linkContext.getLinkTitle())) {
|
||||
binding.tvLinkTitle.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.tvLinkTitle.setText(linkContext.getLinkTitle());
|
||||
}
|
||||
if (TextUtils.isEmpty(linkContext.getLinkSummary())) {
|
||||
binding.tvLinkSummary.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.tvLinkSummary.setText(linkContext.getLinkSummary());
|
||||
}
|
||||
binding.tvMessage.setText(TextUtils.getSpannableUrl(link.getText()));
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaShareBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel.DirectItemMediaModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||
|
||||
public class DirectMessageMediaShareViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmMediaShareBinding binding;
|
||||
private final int maxHeight;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectMessageMediaShareViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmMediaShareBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
maxWidth = (int) (Utils.displayMetrics.widthPixels * 0.8);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final Context context = itemView.getContext();
|
||||
final DirectItemMediaModel mediaModel = directItemModel.getMediaModel();
|
||||
final ProfileModel modelUser = mediaModel.getUser();
|
||||
if (modelUser != null) {
|
||||
binding.tvMessage.setText(HtmlCompat.fromHtml(
|
||||
"<small>" + context.getString(R.string.dms_inbox_media_shared_from, modelUser.getUsername()) + "</small>",
|
||||
FROM_HTML_MODE_COMPACT));
|
||||
}
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
mediaModel.getHeight(),
|
||||
mediaModel.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
final MediaItemType modelMediaType = mediaModel.getMediaType();
|
||||
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO
|
||||
|| modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmMediaBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class DirectMessageMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmMediaBinding binding;
|
||||
private final int maxHeight;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectMessageMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmMediaBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
maxWidth = (int) (Utils.displayMetrics.widthPixels - Utils.convertDpToPx(64) - getItemMargin());
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemMediaModel mediaModel = directItemModel.getMediaModel();
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
mediaModel.getHeight(),
|
||||
mediaModel.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
final MediaItemType modelMediaType = mediaModel.getMediaType();
|
||||
binding.typeIcon.setVisibility(modelMediaType == MediaItemType.MEDIA_TYPE_VIDEO || modelMediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
|
||||
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||
|
||||
public class DirectMessagePlaceholderViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectMessagePlaceholderViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
binding.tvMessage.setText(HtmlCompat.fromHtml(directItemModel.getText().toString(), FROM_HTML_MODE_COMPACT));
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmProfileBinding;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
|
||||
public class DirectMessageProfileViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmProfileBinding binding;
|
||||
|
||||
public DirectMessageProfileViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmProfileBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
binding.btnOpenProfile.setOnClickListener(onClickListener);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final ProfileModel profileModel = directItemModel.getProfileModel();
|
||||
if (profileModel == null) return;
|
||||
binding.profileInfo.setImageURI(profileModel.getSdProfilePic());
|
||||
binding.btnOpenProfile.setTag(profileModel);
|
||||
binding.tvFullName.setText(profileModel.getName());
|
||||
binding.profileInfoText.setText(profileModel.getUsername());
|
||||
binding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.models.enums.RavenExpiringMediaType;
|
||||
import awais.instagrabber.models.enums.RavenMediaViewType;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class DirectMessageRavenMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmRavenMediaBinding binding;
|
||||
private final int maxHeight;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectMessageRavenMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmRavenMediaBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
maxWidth = (int) (Utils.displayMetrics.widthPixels * 0.8);
|
||||
binding.tvMessage.setVisibility(View.GONE);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final Context context = itemView.getContext();
|
||||
final DirectItemModel.DirectItemRavenMediaModel ravenMediaModel = directItemModel.getRavenMediaModel();
|
||||
DirectItemModel.DirectItemMediaModel mediaModel = directItemModel.getMediaModel();
|
||||
final boolean isExpired = ravenMediaModel == null || (mediaModel = ravenMediaModel.getMedia()) == null ||
|
||||
TextUtils.isEmpty(mediaModel.getThumbUrl()) && mediaModel.getPk() < 1;
|
||||
|
||||
DirectItemModel.RavenExpiringMediaActionSummaryModel mediaActionSummary = null;
|
||||
if (ravenMediaModel != null) {
|
||||
mediaActionSummary = ravenMediaModel.getExpiringMediaActionSummary();
|
||||
}
|
||||
binding.mediaExpiredIcon.setVisibility(isExpired ? View.VISIBLE : View.GONE);
|
||||
|
||||
int textRes = R.string.dms_inbox_raven_media_unknown;
|
||||
if (isExpired) textRes = R.string.dms_inbox_raven_media_expired;
|
||||
|
||||
if (!isExpired) {
|
||||
if (mediaActionSummary != null) {
|
||||
final RavenExpiringMediaType expiringMediaType = mediaActionSummary.getType();
|
||||
|
||||
if (expiringMediaType == RavenExpiringMediaType.RAVEN_DELIVERED)
|
||||
textRes = R.string.dms_inbox_raven_media_delivered;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_SENT)
|
||||
textRes = R.string.dms_inbox_raven_media_sent;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_OPENED)
|
||||
textRes = R.string.dms_inbox_raven_media_opened;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_REPLAYED)
|
||||
textRes = R.string.dms_inbox_raven_media_replayed;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_SENDING)
|
||||
textRes = R.string.dms_inbox_raven_media_sending;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_BLOCKED)
|
||||
textRes = R.string.dms_inbox_raven_media_blocked;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_SUGGESTED)
|
||||
textRes = R.string.dms_inbox_raven_media_suggested;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_SCREENSHOT)
|
||||
textRes = R.string.dms_inbox_raven_media_screenshot;
|
||||
else if (expiringMediaType == RavenExpiringMediaType.RAVEN_CANNOT_DELIVER)
|
||||
textRes = R.string.dms_inbox_raven_media_cant_deliver;
|
||||
}
|
||||
|
||||
final RavenMediaViewType ravenMediaViewType = ravenMediaModel.getViewType();
|
||||
if (ravenMediaViewType == RavenMediaViewType.PERMANENT || ravenMediaViewType == RavenMediaViewType.REPLAYABLE) {
|
||||
final MediaItemType mediaType = mediaModel.getMediaType();
|
||||
textRes = -1;
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO || mediaType == MediaItemType.MEDIA_TYPE_SLIDER
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
mediaModel.getHeight(),
|
||||
mediaModel.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
binding.ivMediaPreview.setImageURI(mediaModel.getThumbUrl());
|
||||
}
|
||||
}
|
||||
if (textRes != -1) {
|
||||
binding.tvMessage.setText(context.getText(textRes));
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmRavenMediaBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class DirectMessageReelShareViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmRavenMediaBinding binding;
|
||||
private final int maxHeight;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectMessageReelShareViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmRavenMediaBinding binding,
|
||||
final View.OnClickListener onClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
maxWidth = (int) (Utils.displayMetrics.widthPixels * 0.8);
|
||||
binding.tvMessage.setMentionClickListener(mentionClickListener);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemReelShareModel reelShare = directItemModel.getReelShare();
|
||||
CharSequence text = reelShare.getText();
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
binding.tvMessage.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (TextUtils.hasMentions(text)) text = TextUtils.getMentionText(text); // for mentions
|
||||
binding.tvMessage.setText(text);
|
||||
}
|
||||
final DirectItemModel.DirectItemMediaModel reelShareMedia = reelShare.getMedia();
|
||||
final MediaItemType mediaType = reelShareMedia.getMediaType();
|
||||
if (mediaType == null) {
|
||||
binding.mediaExpiredIcon.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO ||
|
||||
mediaType == MediaItemType.MEDIA_TYPE_SLIDER ? View.VISIBLE : View.GONE);
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
reelShareMedia.getHeight(),
|
||||
reelShareMedia.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
binding.ivMediaPreview.setImageURI(reelShareMedia.getThumbUrl());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmStoryShareBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT;
|
||||
|
||||
public class DirectMessageStoryShareViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmStoryShareBinding binding;
|
||||
private final int maxHeight;
|
||||
private final int maxWidth;
|
||||
|
||||
public DirectMessageStoryShareViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmStoryShareBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
maxHeight = itemView.getResources().getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
||||
maxWidth = (int) (Utils.displayMetrics.widthPixels * 0.8);
|
||||
binding.tvMessage.setVisibility(View.GONE);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemReelShareModel reelShare = directItemModel.getReelShare();
|
||||
if (reelShare == null) {
|
||||
binding.tvMessage.setText(HtmlCompat.fromHtml(directItemModel.getText().toString(), FROM_HTML_MODE_COMPACT));
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
final String text = reelShare.getText();
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
binding.tvMessage.setText(text);
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
final DirectItemModel.DirectItemMediaModel reelShareMedia = reelShare.getMedia();
|
||||
final MediaItemType mediaType = reelShareMedia.getMediaType();
|
||||
binding.typeIcon.setVisibility(mediaType == MediaItemType.MEDIA_TYPE_VIDEO ? View.VISIBLE : View.GONE);
|
||||
final Pair<Integer, Integer> widthHeight = NumberUtils.calculateWidthHeight(
|
||||
reelShareMedia.getHeight(),
|
||||
reelShareMedia.getWidth(),
|
||||
maxHeight,
|
||||
maxWidth
|
||||
);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.ivMediaPreview.getLayoutParams();
|
||||
layoutParams.width = widthHeight.first != null ? widthHeight.first : 0;
|
||||
layoutParams.height = widthHeight.second != null ? widthHeight.second : 0;
|
||||
binding.ivMediaPreview.requestLayout();
|
||||
binding.ivMediaPreview.setImageURI(reelShareMedia.getThumbUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Spanned;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.interfaces.MentionClickListener;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectMessageTextViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectMessageTextViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final View.OnClickListener onClickListener,
|
||||
final MentionClickListener mentionClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
this.binding.tvMessage.setMentionClickListener(mentionClickListener);
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final Context context = itemView.getContext();
|
||||
CharSequence text = directItemModel.getText();
|
||||
text = TextUtils.getSpannableUrl(text.toString()); // for urls
|
||||
if (TextUtils.hasMentions(text)) text = TextUtils.getMentionText(text); // for mentions
|
||||
if (text instanceof Spanned)
|
||||
binding.tvMessage.setText(text, TextView.BufferType.SPANNABLE);
|
||||
else if (text == "") {
|
||||
binding.tvMessage.setText(context.getText(R.string.dms_inbox_raven_message_unknown));
|
||||
} else binding.tvMessage.setText(text);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmTextBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
|
||||
public class DirectMessageVideoCallEventViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmTextBinding binding;
|
||||
|
||||
public DirectMessageVideoCallEventViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmTextBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
// todo add call event info
|
||||
binding.tvMessage.setVisibility(View.VISIBLE);
|
||||
binding.tvMessage.setBackgroundColor(0xFF_1F90E6);
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
||||
import awais.instagrabber.databinding.LayoutDmVoiceMediaBinding;
|
||||
import awais.instagrabber.models.direct_messages.DirectItemModel;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
|
||||
public class DirectMessageVoiceMediaViewHolder extends DirectMessageItemViewHolder {
|
||||
|
||||
private final LayoutDmVoiceMediaBinding binding;
|
||||
|
||||
private DirectItemModel.DirectItemVoiceMediaModel prevVoiceModel;
|
||||
private ImageView prevPlayIcon;
|
||||
|
||||
public DirectMessageVoiceMediaViewHolder(@NonNull final LayoutDmBaseBinding baseBinding,
|
||||
@NonNull final LayoutDmVoiceMediaBinding binding,
|
||||
final View.OnClickListener onClickListener) {
|
||||
super(baseBinding, onClickListener);
|
||||
this.binding = binding;
|
||||
|
||||
// todo pause / resume
|
||||
// todo release prev audio, start new voice
|
||||
binding.btnPlayVoice.setOnClickListener(v -> {
|
||||
final Object tag = v.getTag();
|
||||
final ImageView playIcon = (ImageView) ((ViewGroup) v).getChildAt(0);
|
||||
final DirectItemModel.DirectItemVoiceMediaModel voiceMediaModel = (DirectItemModel.DirectItemVoiceMediaModel) tag;
|
||||
final boolean voicePlaying = voiceMediaModel.isPlaying();
|
||||
voiceMediaModel.setPlaying(!voicePlaying);
|
||||
|
||||
if (voiceMediaModel == prevVoiceModel) {
|
||||
// todo pause / resume
|
||||
} else {
|
||||
// todo release prev audio, start new voice
|
||||
if (prevVoiceModel != null) prevVoiceModel.setPlaying(false);
|
||||
if (prevPlayIcon != null)
|
||||
prevPlayIcon.setImageResource(android.R.drawable.ic_media_play);
|
||||
}
|
||||
|
||||
if (voicePlaying) {
|
||||
playIcon.setImageResource(android.R.drawable.ic_media_play);
|
||||
} else {
|
||||
playIcon.setImageResource(android.R.drawable.ic_media_pause);
|
||||
}
|
||||
prevVoiceModel = voiceMediaModel;
|
||||
prevPlayIcon = playIcon;
|
||||
});
|
||||
setItemView(binding.getRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final DirectItemModel directItemModel) {
|
||||
final DirectItemModel.DirectItemVoiceMediaModel voiceMediaModel = directItemModel.getVoiceMediaModel();
|
||||
if (voiceMediaModel != null) {
|
||||
final int[] waveformData = voiceMediaModel.getWaveformData();
|
||||
if (waveformData != null) binding.waveformSeekBar.setSample(waveformData);
|
||||
|
||||
final long durationMs = voiceMediaModel.getDurationMs();
|
||||
binding.tvVoiceDuration.setText(NumberUtils.millisToString(durationMs));
|
||||
binding.waveformSeekBar.setProgress(voiceMediaModel.getProgress());
|
||||
binding.waveformSeekBar.setProgressChangeListener((waveformSeekBar, progress, fromUser) -> {
|
||||
// todo progress audio player
|
||||
voiceMediaModel.setProgress(progress);
|
||||
if (fromUser)
|
||||
binding.tvVoiceDuration.setText(NumberUtils.millisToString(durationMs * progress / 100));
|
||||
});
|
||||
binding.btnPlayVoice.setTag(voiceMediaModel);
|
||||
} else {
|
||||
binding.waveformSeekBar.setProgress(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectPendingUsersAdapter.PendingUser;
|
||||
import awais.instagrabber.adapters.DirectPendingUsersAdapter.PendingUserCallback;
|
||||
import awais.instagrabber.customviews.VerticalImageSpan;
|
||||
import awais.instagrabber.databinding.LayoutDmPendingUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class DirectPendingUserViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = DirectPendingUserViewHolder.class.getSimpleName();
|
||||
|
||||
private final LayoutDmPendingUserItemBinding binding;
|
||||
private final PendingUserCallback callback;
|
||||
private final int drawableSize;
|
||||
|
||||
private VerticalImageSpan verifiedSpan;
|
||||
|
||||
public DirectPendingUserViewHolder(@NonNull final LayoutDmPendingUserItemBinding binding,
|
||||
final PendingUserCallback callback) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.callback = callback;
|
||||
drawableSize = Utils.convertDpToPx(24);
|
||||
}
|
||||
|
||||
public void bind(final int position, final PendingUser pendingUser) {
|
||||
if (pendingUser == null) return;
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
if (callback == null) return;
|
||||
callback.onClick(position, pendingUser);
|
||||
});
|
||||
setUsername(pendingUser);
|
||||
binding.requester.setText(itemView.getResources().getString(R.string.added_by, pendingUser.getRequester()));
|
||||
binding.profilePic.setImageURI(pendingUser.getUser().getProfilePicUrl());
|
||||
if (pendingUser.isInProgress()) {
|
||||
binding.approve.setVisibility(View.GONE);
|
||||
binding.deny.setVisibility(View.GONE);
|
||||
binding.progress.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
binding.approve.setVisibility(View.VISIBLE);
|
||||
binding.deny.setVisibility(View.VISIBLE);
|
||||
binding.progress.setVisibility(View.GONE);
|
||||
binding.approve.setOnClickListener(v -> {
|
||||
if (callback == null) return;
|
||||
callback.onApprove(position, pendingUser);
|
||||
});
|
||||
binding.deny.setOnClickListener(v -> {
|
||||
if (callback == null) return;
|
||||
callback.onDeny(position, pendingUser);
|
||||
});
|
||||
}
|
||||
|
||||
private void setUsername(final PendingUser pendingUser) {
|
||||
final User user = pendingUser.getUser();
|
||||
final SpannableStringBuilder sb = new SpannableStringBuilder(user.getUsername());
|
||||
if (user.isVerified()) {
|
||||
if (verifiedSpan == null) {
|
||||
final Drawable verifiedDrawable = AppCompatResources.getDrawable(itemView.getContext(), R.drawable.verified);
|
||||
if (verifiedDrawable != null) {
|
||||
final Drawable drawable = verifiedDrawable.mutate();
|
||||
drawable.setBounds(0, 0, drawableSize, drawableSize);
|
||||
verifiedSpan = new VerticalImageSpan(drawable);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (verifiedSpan != null) {
|
||||
sb.append(" ");
|
||||
sb.setSpan(verifiedSpan, sb.length() - 1, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "bind: ", e);
|
||||
}
|
||||
}
|
||||
binding.username.setText(sb);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectReactionsAdapter.OnReactionClickListener;
|
||||
import awais.instagrabber.customviews.emoji.Emoji;
|
||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
||||
import awais.instagrabber.utils.emoji.EmojiParser;
|
||||
|
||||
public class DirectReactionViewHolder extends RecyclerView.ViewHolder {
|
||||
private final LayoutDmUserItemBinding binding;
|
||||
private final long viewerId;
|
||||
private final String itemId;
|
||||
private final OnReactionClickListener onReactionClickListener;
|
||||
private final EmojiParser emojiParser;
|
||||
|
||||
public DirectReactionViewHolder(final LayoutDmUserItemBinding binding,
|
||||
final long viewerId,
|
||||
final String itemId,
|
||||
final OnReactionClickListener onReactionClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.viewerId = viewerId;
|
||||
this.itemId = itemId;
|
||||
this.onReactionClickListener = onReactionClickListener;
|
||||
binding.info.setVisibility(View.GONE);
|
||||
binding.secondaryImage.setVisibility(View.VISIBLE);
|
||||
emojiParser = EmojiParser.getInstance();
|
||||
}
|
||||
|
||||
public void bind(final DirectItemEmojiReaction reaction,
|
||||
@Nullable final User user) {
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (onReactionClickListener == null) return;
|
||||
onReactionClickListener.onReactionClick(itemId, reaction);
|
||||
});
|
||||
setUser(user);
|
||||
setReaction(reaction);
|
||||
}
|
||||
|
||||
private void setReaction(final DirectItemEmojiReaction reaction) {
|
||||
final Emoji emoji = emojiParser.getEmoji(reaction.getEmoji());
|
||||
if (emoji == null) {
|
||||
binding.secondaryImage.setImageDrawable(null);
|
||||
return;
|
||||
}
|
||||
binding.secondaryImage.setImageDrawable(emoji.getDrawable());
|
||||
}
|
||||
|
||||
private void setUser(final User user) {
|
||||
if (user == null) {
|
||||
binding.fullName.setText("");
|
||||
binding.username.setText("");
|
||||
binding.profilePic.setImageURI((String) null);
|
||||
return;
|
||||
}
|
||||
binding.fullName.setText(user.getFullName());
|
||||
if (user.getPk() == viewerId) {
|
||||
binding.username.setText(R.string.tap_to_remove);
|
||||
} else {
|
||||
binding.username.setText(user.getUsername());
|
||||
}
|
||||
binding.profilePic.setImageURI(user.getProfilePicUrl());
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.DirectUsersAdapter.OnDirectUserClickListener;
|
||||
import awais.instagrabber.adapters.DirectUsersAdapter.OnDirectUserLongClickListener;
|
||||
import awais.instagrabber.customviews.VerticalImageSpan;
|
||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class DirectUserViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = DirectUserViewHolder.class.getSimpleName();
|
||||
|
||||
private final LayoutDmUserItemBinding binding;
|
||||
private final OnDirectUserClickListener onClickListener;
|
||||
private final OnDirectUserLongClickListener onLongClickListener;
|
||||
private final int drawableSize;
|
||||
|
||||
private VerticalImageSpan verifiedSpan;
|
||||
|
||||
public DirectUserViewHolder(@NonNull final LayoutDmUserItemBinding binding,
|
||||
final OnDirectUserClickListener onClickListener,
|
||||
final OnDirectUserLongClickListener onLongClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.onClickListener = onClickListener;
|
||||
this.onLongClickListener = onLongClickListener;
|
||||
drawableSize = Utils.convertDpToPx(24);
|
||||
}
|
||||
|
||||
public void bind(final int position,
|
||||
final User user,
|
||||
final boolean isAdmin,
|
||||
final boolean isInviter,
|
||||
final boolean showSelection,
|
||||
final boolean isSelected) {
|
||||
if (user == null) return;
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
if (onClickListener == null) return;
|
||||
onClickListener.onClick(position, user, isSelected);
|
||||
});
|
||||
binding.getRoot().setOnLongClickListener(v -> {
|
||||
if (onLongClickListener == null) return false;
|
||||
return onLongClickListener.onLongClick(position, user);
|
||||
});
|
||||
setFullName(user);
|
||||
binding.username.setText(user.getUsername());
|
||||
binding.profilePic.setImageURI(user.getProfilePicUrl());
|
||||
setInfo(isAdmin, isInviter);
|
||||
setSelection(showSelection, isSelected);
|
||||
}
|
||||
|
||||
private void setFullName(final User user) {
|
||||
final SpannableStringBuilder sb = new SpannableStringBuilder(user.getFullName());
|
||||
if (user.isVerified()) {
|
||||
if (verifiedSpan == null) {
|
||||
final Drawable verifiedDrawable = AppCompatResources.getDrawable(itemView.getContext(), R.drawable.verified);
|
||||
if (verifiedDrawable != null) {
|
||||
final Drawable drawable = verifiedDrawable.mutate();
|
||||
drawable.setBounds(0, 0, drawableSize, drawableSize);
|
||||
verifiedSpan = new VerticalImageSpan(drawable);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (verifiedSpan != null) {
|
||||
sb.append(" ");
|
||||
sb.setSpan(verifiedSpan, sb.length() - 1, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "bind: ", e);
|
||||
}
|
||||
}
|
||||
binding.fullName.setText(sb);
|
||||
}
|
||||
|
||||
private void setInfo(final boolean isAdmin, final boolean isInviter) {
|
||||
if (!isAdmin && !isInviter) {
|
||||
binding.info.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
if (isAdmin) {
|
||||
binding.info.setText(R.string.admin);
|
||||
return;
|
||||
}
|
||||
binding.info.setText(R.string.inviter);
|
||||
}
|
||||
|
||||
private void setSelection(final boolean showSelection, final boolean isSelected) {
|
||||
binding.select.setVisibility(showSelection ? View.VISIBLE : View.GONE);
|
||||
binding.getRoot().setSelected(isSelected);
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.UserSearchResultsAdapter.OnRecipientClickListener;
|
||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient;
|
||||
|
||||
public class RecipientThreadViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = RecipientThreadViewHolder.class.getSimpleName();
|
||||
|
||||
private final LayoutDmUserItemBinding binding;
|
||||
private final OnRecipientClickListener onThreadClickListener;
|
||||
private final float translateAmount;
|
||||
|
||||
public RecipientThreadViewHolder(@NonNull final LayoutDmUserItemBinding binding,
|
||||
final OnRecipientClickListener onThreadClickListener) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
this.onThreadClickListener = onThreadClickListener;
|
||||
binding.info.setVisibility(View.GONE);
|
||||
final Resources resources = itemView.getResources();
|
||||
final int avatarSize = resources.getDimensionPixelSize(R.dimen.dm_inbox_avatar_size);
|
||||
translateAmount = ((float) avatarSize) / 7;
|
||||
}
|
||||
|
||||
public void bind(final int position,
|
||||
final DirectThread thread,
|
||||
final boolean showSelection,
|
||||
final boolean isSelected) {
|
||||
if (thread == null) return;
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
if (onThreadClickListener == null) return;
|
||||
onThreadClickListener.onClick(position, RankedRecipient.of(thread), isSelected);
|
||||
});
|
||||
binding.fullName.setText(thread.getThreadTitle());
|
||||
setUsername(thread);
|
||||
setProfilePic(thread);
|
||||
setSelection(showSelection, isSelected);
|
||||
}
|
||||
|
||||
private void setProfilePic(final DirectThread thread) {
|
||||
final List<User> users = thread.getUsers();
|
||||
binding.profilePic.setImageURI(users.get(0).getProfilePicUrl());
|
||||
binding.profilePic.setScaleX(1);
|
||||
binding.profilePic.setScaleY(1);
|
||||
binding.profilePic.setTranslationX(0);
|
||||
binding.profilePic.setTranslationY(0);
|
||||
if (users.size() > 1) {
|
||||
binding.profilePic2.setVisibility(View.VISIBLE);
|
||||
binding.profilePic2.setImageURI(users.get(1).getProfilePicUrl());
|
||||
binding.profilePic2.setTranslationX(translateAmount);
|
||||
binding.profilePic2.setTranslationY(translateAmount);
|
||||
final float scaleAmount = 0.75f;
|
||||
binding.profilePic2.setScaleX(scaleAmount);
|
||||
binding.profilePic2.setScaleY(scaleAmount);
|
||||
binding.profilePic.setScaleX(scaleAmount);
|
||||
binding.profilePic.setScaleY(scaleAmount);
|
||||
binding.profilePic.setTranslationX(-translateAmount);
|
||||
binding.profilePic.setTranslationY(-translateAmount);
|
||||
return;
|
||||
}
|
||||
binding.profilePic2.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setUsername(final DirectThread thread) {
|
||||
if (thread.isGroup()) {
|
||||
binding.username.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
binding.username.setVisibility(View.VISIBLE);
|
||||
// for a non-group thread, the thread title is the username so set the full name in the username text view
|
||||
binding.username.setText(thread.getUsers().get(0).getFullName());
|
||||
}
|
||||
|
||||
private void setSelection(final boolean showSelection, final boolean isSelected) {
|
||||
binding.select.setVisibility(showSelection ? View.VISIBLE : View.GONE);
|
||||
binding.getRoot().setSelected(isSelected);
|
||||
}
|
||||
}
|
@ -11,9 +11,11 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import awais.instagrabber.adapters.FeedAdapterV2;
|
||||
import awais.instagrabber.databinding.ItemFeedBottomBinding;
|
||||
import awais.instagrabber.databinding.ItemFeedTopBinding;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.Caption;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
import static android.text.TextUtils.TruncateAt.END;
|
||||
@ -35,52 +37,60 @@ public abstract class FeedItemViewHolder extends RecyclerView.ViewHolder {
|
||||
this.feedItemCallback = feedItemCallback;
|
||||
}
|
||||
|
||||
public void bind(final FeedModel feedModel) {
|
||||
if (feedModel == null) {
|
||||
public void bind(final Media media) {
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
setupProfilePic(feedModel);
|
||||
setupLocation(feedModel);
|
||||
bottomBinding.tvPostDate.setText(feedModel.getPostDate());
|
||||
setupComments(feedModel);
|
||||
setupCaption(feedModel);
|
||||
if (feedModel.getItemType() != MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
bottomBinding.btnDownload.setOnClickListener(v -> feedItemCallback.onDownloadClick(feedModel, -1));
|
||||
setupProfilePic(media);
|
||||
setupLocation(media);
|
||||
bottomBinding.tvPostDate.setText(media.getDate());
|
||||
setupComments(media);
|
||||
setupCaption(media);
|
||||
if (media.getMediaType() != MediaItemType.MEDIA_TYPE_SLIDER) {
|
||||
bottomBinding.btnDownload.setOnClickListener(v -> feedItemCallback.onDownloadClick(media, -1));
|
||||
}
|
||||
bindItem(feedModel);
|
||||
bindItem(media);
|
||||
}
|
||||
|
||||
private void setupComments(final FeedModel feedModel) {
|
||||
final long commentsCount = feedModel.getCommentsCount();
|
||||
private void setupComments(@NonNull final Media feedModel) {
|
||||
final long commentsCount = feedModel.getCommentCount();
|
||||
bottomBinding.commentsCount.setText(String.valueOf(commentsCount));
|
||||
bottomBinding.commentsCount.setOnClickListener(v -> feedItemCallback.onCommentsClick(feedModel));
|
||||
}
|
||||
|
||||
private void setupProfilePic(final FeedModel feedModel) {
|
||||
final ProfileModel profileModel = feedModel.getProfileModel();
|
||||
if (profileModel != null) {
|
||||
topBinding.ivProfilePic.setOnClickListener(v -> feedItemCallback.onProfilePicClick(feedModel, topBinding.ivProfilePic));
|
||||
topBinding.ivProfilePic.setImageURI(profileModel.getSdProfilePic());
|
||||
setupTitle(feedModel);
|
||||
private void setupProfilePic(@NonNull final Media media) {
|
||||
final User user = media.getUser();
|
||||
if (user == null) {
|
||||
topBinding.ivProfilePic.setVisibility(View.GONE);
|
||||
topBinding.title.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
topBinding.ivProfilePic.setOnClickListener(v -> feedItemCallback.onProfilePicClick(media, topBinding.ivProfilePic));
|
||||
topBinding.ivProfilePic.setImageURI(user.getProfilePicUrl());
|
||||
setupTitle(media);
|
||||
}
|
||||
|
||||
private void setupTitle(final FeedModel feedModel) {
|
||||
private void setupTitle(@NonNull final Media media) {
|
||||
// final int titleLen = profileModel.getUsername().length() + 1;
|
||||
// final SpannableString spannableString = new SpannableString();
|
||||
// spannableString.setSpan(new CommentMentionClickSpan(), 0, titleLen, 0);
|
||||
final ProfileModel profileModel = feedModel.getProfileModel();
|
||||
final String title = "@" + profileModel.getUsername();
|
||||
final User user = media.getUser();
|
||||
final String title = "@" + user.getUsername();
|
||||
topBinding.title.setText(title);
|
||||
topBinding.title.setOnClickListener(v -> feedItemCallback.onNameClick(feedModel, topBinding.ivProfilePic));
|
||||
topBinding.title.setOnClickListener(v -> feedItemCallback.onNameClick(media, topBinding.ivProfilePic));
|
||||
}
|
||||
|
||||
private void setupCaption(final FeedModel feedModel) {
|
||||
private void setupCaption(final Media media) {
|
||||
bottomBinding.viewerCaption.clearOnMentionClickListeners();
|
||||
bottomBinding.viewerCaption.clearOnHashtagClickListeners();
|
||||
bottomBinding.viewerCaption.clearOnURLClickListeners();
|
||||
bottomBinding.viewerCaption.clearOnEmailClickListeners();
|
||||
final CharSequence postCaption = feedModel.getPostCaption();
|
||||
final Caption caption = media.getCaption();
|
||||
if (caption == null) {
|
||||
bottomBinding.viewerCaption.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
final CharSequence postCaption = caption.getText();
|
||||
final boolean captionEmpty = TextUtils.isEmpty(postCaption);
|
||||
bottomBinding.viewerCaption.setVisibility(captionEmpty ? View.GONE : View.VISIBLE);
|
||||
if (captionEmpty) return;
|
||||
@ -103,22 +113,31 @@ public abstract class FeedItemViewHolder extends RecyclerView.ViewHolder {
|
||||
bottomBinding.viewerCaption.addOnURLClickListener(autoLinkItem -> feedItemCallback.onURLClick(autoLinkItem.getOriginalText()));
|
||||
}
|
||||
|
||||
private void setupLocation(final FeedModel feedModel) {
|
||||
final String locationName = feedModel.getLocationName();
|
||||
if (TextUtils.isEmpty(locationName)) {
|
||||
private void setupLocation(@NonNull final Media media) {
|
||||
final Location location = media.getLocation();
|
||||
if (location == null) {
|
||||
topBinding.location.setVisibility(View.GONE);
|
||||
topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
} else {
|
||||
topBinding.location.setVisibility(View.VISIBLE);
|
||||
topBinding.location.setText(locationName);
|
||||
topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
topBinding.location.setOnClickListener(v -> feedItemCallback.onLocationClick(feedModel));
|
||||
}
|
||||
else {
|
||||
final String locationName = location.getName();
|
||||
if (TextUtils.isEmpty(locationName)) {
|
||||
topBinding.location.setVisibility(View.GONE);
|
||||
topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
} else {
|
||||
topBinding.location.setVisibility(View.VISIBLE);
|
||||
topBinding.location.setText(locationName);
|
||||
topBinding.title.setLayoutParams(new RelativeLayout.LayoutParams(
|
||||
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
topBinding.location.setOnClickListener(v -> feedItemCallback.onLocationClick(media));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void bindItem(final FeedModel feedModel);
|
||||
public abstract void bindItem(final Media media);
|
||||
}
|
@ -16,7 +16,8 @@ import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
|
||||
import awais.instagrabber.adapters.FeedAdapterV2;
|
||||
import awais.instagrabber.databinding.ItemFeedPhotoBinding;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class FeedPhotoViewHolder extends FeedItemViewHolder {
|
||||
@ -30,7 +31,7 @@ public class FeedPhotoViewHolder extends FeedItemViewHolder {
|
||||
super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, feedItemCallback);
|
||||
this.binding = binding;
|
||||
this.feedItemCallback = feedItemCallback;
|
||||
binding.itemFeedBottom.tvVideoViews.setVisibility(View.GONE);
|
||||
binding.itemFeedBottom.btnViews.setVisibility(View.GONE);
|
||||
// binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
|
||||
binding.imageViewer.setAllowTouchInterceptionWhileZoomed(false);
|
||||
final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(itemView.getContext().getResources())
|
||||
@ -40,14 +41,12 @@ public class FeedPhotoViewHolder extends FeedItemViewHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final FeedModel feedModel) {
|
||||
if (feedModel == null) {
|
||||
return;
|
||||
}
|
||||
public void bindItem(final Media media) {
|
||||
if (media == null) return;
|
||||
binding.getRoot().post(() -> {
|
||||
setDimensions(feedModel);
|
||||
final String thumbnailUrl = feedModel.getThumbnailUrl();
|
||||
String url = feedModel.getDisplayUrl();
|
||||
setDimensions(media);
|
||||
final String thumbnailUrl = ResponseBodyUtils.getThumbUrl(media);
|
||||
String url = ResponseBodyUtils.getImageUrl(media);
|
||||
if (TextUtils.isEmpty(url)) url = thumbnailUrl;
|
||||
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
|
||||
// .setLocalThumbnailPreviewsEnabled(true)
|
||||
@ -62,7 +61,7 @@ public class FeedPhotoViewHolder extends FeedItemViewHolder {
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(final MotionEvent e) {
|
||||
if (feedItemCallback != null) {
|
||||
feedItemCallback.onPostClick(feedModel, binding.itemFeedTop.ivProfilePic, binding.imageViewer);
|
||||
feedItemCallback.onPostClick(media, binding.itemFeedTop.ivProfilePic, binding.imageViewer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -71,8 +70,8 @@ public class FeedPhotoViewHolder extends FeedItemViewHolder {
|
||||
});
|
||||
}
|
||||
|
||||
private void setDimensions(final FeedModel feedModel) {
|
||||
final float aspectRatio = (float) feedModel.getImageWidth() / feedModel.getImageHeight();
|
||||
private void setDimensions(final Media feedModel) {
|
||||
final float aspectRatio = (float) feedModel.getOriginalWidth() / feedModel.getOriginalHeight();
|
||||
binding.imageViewer.setAspectRatio(aspectRatio);
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ import awais.instagrabber.adapters.FeedAdapterV2;
|
||||
import awais.instagrabber.adapters.SliderCallbackAdapter;
|
||||
import awais.instagrabber.adapters.SliderItemsAdapter;
|
||||
import awais.instagrabber.databinding.ItemFeedSliderBinding;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.PostChild;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
@ -30,7 +29,7 @@ public class FeedSliderViewHolder extends FeedItemViewHolder {
|
||||
super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, feedItemCallback);
|
||||
this.binding = binding;
|
||||
this.feedItemCallback = feedItemCallback;
|
||||
binding.itemFeedBottom.tvVideoViews.setVisibility(View.GONE);
|
||||
binding.itemFeedBottom.btnViews.setVisibility(View.GONE);
|
||||
// binding.itemFeedBottom.btnMute.setVisibility(View.GONE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.mediaList.getLayoutParams();
|
||||
layoutParams.height = Utils.displayMetrics.widthPixels + 1;
|
||||
@ -39,8 +38,8 @@ public class FeedSliderViewHolder extends FeedItemViewHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final FeedModel feedModel) {
|
||||
final List<PostChild> sliderItems = feedModel.getSliderItems();
|
||||
public void bindItem(final Media feedModel) {
|
||||
final List<Media> sliderItems = feedModel.getCarouselMedia();
|
||||
final int sliderItemLen = sliderItems != null ? sliderItems.size() : 0;
|
||||
if (sliderItemLen <= 0) return;
|
||||
final String text = "1/" + sliderItemLen;
|
||||
@ -68,7 +67,7 @@ public class FeedSliderViewHolder extends FeedItemViewHolder {
|
||||
adapter.submitList(sliderItems);
|
||||
}
|
||||
|
||||
private void setDimensions(final View view, final PostChild model) {
|
||||
private void setDimensions(final View view, final Media model) {
|
||||
final ViewGroup.LayoutParams layoutParams = binding.mediaList.getLayoutParams();
|
||||
int requiredWidth = layoutParams.width;
|
||||
if (requiredWidth <= 0) {
|
||||
@ -86,10 +85,10 @@ public class FeedSliderViewHolder extends FeedItemViewHolder {
|
||||
setLayoutParamDimens(binding.mediaList, model);
|
||||
}
|
||||
|
||||
private void setLayoutParamDimens(final View view, final PostChild model) {
|
||||
private void setLayoutParamDimens(final View view, final Media model) {
|
||||
final int requiredWidth = view.getMeasuredWidth();
|
||||
final ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
|
||||
final int spanHeight = NumberUtils.getResultingHeight(requiredWidth, model.getHeight(), model.getWidth());
|
||||
final int spanHeight = NumberUtils.getResultingHeight(requiredWidth, model.getOriginalHeight(), model.getOriginalWidth());
|
||||
layoutParams.height = spanHeight == 0 ? requiredWidth + 1 : spanHeight;
|
||||
view.requestLayout();
|
||||
}
|
||||
|
@ -12,13 +12,17 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.adapters.FeedAdapterV2;
|
||||
import awais.instagrabber.customviews.VideoPlayerCallbackAdapter;
|
||||
import awais.instagrabber.customviews.VideoPlayerViewHelper;
|
||||
import awais.instagrabber.databinding.ItemFeedVideoBinding;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.VideoVersion;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -32,7 +36,7 @@ public class FeedVideoViewHolder extends FeedItemViewHolder {
|
||||
private final DefaultDataSourceFactory dataSourceFactory;
|
||||
|
||||
private CacheDataSourceFactory cacheDataSourceFactory;
|
||||
private FeedModel feedModel;
|
||||
private Media media;
|
||||
|
||||
// private final Runnable loadRunnable = new Runnable() {
|
||||
// @Override
|
||||
@ -46,7 +50,7 @@ public class FeedVideoViewHolder extends FeedItemViewHolder {
|
||||
super(binding.getRoot(), binding.itemFeedTop, binding.itemFeedBottom, feedItemCallback);
|
||||
this.binding = binding;
|
||||
this.feedItemCallback = feedItemCallback;
|
||||
binding.itemFeedBottom.tvVideoViews.setVisibility(View.VISIBLE);
|
||||
binding.itemFeedBottom.btnViews.setVisibility(View.VISIBLE);
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
final Context context = binding.getRoot().getContext();
|
||||
dataSourceFactory = new DefaultDataSourceFactory(context, "instagram");
|
||||
@ -57,68 +61,55 @@ public class FeedVideoViewHolder extends FeedItemViewHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItem(final FeedModel feedModel) {
|
||||
public void bindItem(final Media media) {
|
||||
// Log.d(TAG, "Binding post: " + feedModel.getPostId());
|
||||
this.feedModel = feedModel;
|
||||
binding.itemFeedBottom.tvVideoViews.setText(String.valueOf(feedModel.getViewCount()));
|
||||
// showOrHideDetails(false);
|
||||
this.media = media;
|
||||
binding.itemFeedBottom.tvVideoViews.setText(String.valueOf(media.getViewCount()));
|
||||
final float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
|
||||
final VideoPlayerViewHelper.VideoPlayerCallback videoPlayerCallback = new VideoPlayerCallbackAdapter() {
|
||||
|
||||
@Override
|
||||
public void onThumbnailClick() {
|
||||
feedItemCallback.onPostClick(feedModel, binding.itemFeedTop.ivProfilePic, binding.videoPost.thumbnail);
|
||||
feedItemCallback.onPostClick(media, binding.itemFeedTop.ivProfilePic, binding.videoPost.thumbnail);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerViewLoaded() {
|
||||
// binding.itemFeedBottom.btnMute.setVisibility(View.VISIBLE);
|
||||
final ViewGroup.LayoutParams layoutParams = binding.videoPost.playerView.getLayoutParams();
|
||||
final int requiredWidth = Utils.displayMetrics.widthPixels;
|
||||
final int resultingHeight = NumberUtils.getResultingHeight(requiredWidth, feedModel.getImageHeight(), feedModel.getImageWidth());
|
||||
final int resultingHeight = NumberUtils.getResultingHeight(requiredWidth, media.getOriginalHeight(), media.getOriginalWidth());
|
||||
layoutParams.width = requiredWidth;
|
||||
layoutParams.height = resultingHeight;
|
||||
binding.videoPost.playerView.requestLayout();
|
||||
setMuteIcon(vol == 0f && Utils.sessionVolumeFull ? 1f : vol);
|
||||
}
|
||||
};
|
||||
// final DataSource.Factory factory = cacheDataSourceFactory != null ? cacheDataSourceFactory : dataSourceFactory;
|
||||
// final ProgressiveMediaSource.Factory sourceFactory = new ProgressiveMediaSource.Factory(factory);
|
||||
// final Uri uri = Uri.parse(feedModel.getDisplayUrl());
|
||||
// final MediaItem mediaItem = MediaItem.fromUri(uri);
|
||||
// final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem);
|
||||
final float aspectRatio = (float) feedModel.getImageWidth() / feedModel.getImageHeight();
|
||||
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
|
||||
String videoUrl = null;
|
||||
final List<VideoVersion> videoVersions = media.getVideoVersions();
|
||||
if (videoVersions != null && !videoVersions.isEmpty()) {
|
||||
final VideoVersion videoVersion = videoVersions.get(0);
|
||||
videoUrl = videoVersion.getUrl();
|
||||
}
|
||||
final VideoPlayerViewHelper videoPlayerViewHelper = new VideoPlayerViewHelper(binding.getRoot().getContext(),
|
||||
binding.videoPost,
|
||||
feedModel.getDisplayUrl(),
|
||||
videoUrl,
|
||||
vol,
|
||||
aspectRatio,
|
||||
feedModel.getThumbnailUrl(),
|
||||
ResponseBodyUtils.getThumbUrl(media),
|
||||
false,
|
||||
null,
|
||||
videoPlayerCallback);
|
||||
binding.videoPost.thumbnail.post(() -> {
|
||||
if (feedModel.getImageHeight() > 0.8 * Utils.displayMetrics.heightPixels) {
|
||||
if (media.getOriginalHeight() > 0.8 * Utils.displayMetrics.heightPixels) {
|
||||
final ViewGroup.LayoutParams layoutParams = binding.videoPost.thumbnail.getLayoutParams();
|
||||
layoutParams.height = (int) (0.8 * Utils.displayMetrics.heightPixels);
|
||||
binding.videoPost.thumbnail.requestLayout();
|
||||
}
|
||||
});
|
||||
// binding.itemFeedBottom.btnMute.setOnClickListener(v -> {
|
||||
// final float newVol = videoPlayerViewHelper.toggleMute();
|
||||
// setMuteIcon(newVol);
|
||||
// Utils.sessionVolumeFull = newVol == 1f;
|
||||
// });
|
||||
// binding.videoPost.playerView.setOnClickListener(v -> videoPlayerViewHelper.togglePlayback());
|
||||
}
|
||||
|
||||
|
||||
private void setMuteIcon(final float vol) {
|
||||
// binding.itemFeedBottom.btnMute.setImageResource(vol == 0f ? R.drawable.ic_volume_up_24 : R.drawable.ic_volume_off_24);
|
||||
}
|
||||
|
||||
public FeedModel getCurrentFeedModel() {
|
||||
return feedModel;
|
||||
public Media getCurrentFeedModel() {
|
||||
return media;
|
||||
}
|
||||
|
||||
// public void stopPlaying() {
|
||||
|
@ -0,0 +1,74 @@
|
||||
package awais.instagrabber.animations;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
public class CubicBezierInterpolator implements Interpolator {
|
||||
|
||||
public static final CubicBezierInterpolator DEFAULT = new CubicBezierInterpolator(0.25, 0.1, 0.25, 1);
|
||||
public static final CubicBezierInterpolator EASE_OUT = new CubicBezierInterpolator(0, 0, .58, 1);
|
||||
public static final CubicBezierInterpolator EASE_OUT_QUINT = new CubicBezierInterpolator(.23, 1, .32, 1);
|
||||
public static final CubicBezierInterpolator EASE_IN = new CubicBezierInterpolator(.42, 0, 1, 1);
|
||||
public static final CubicBezierInterpolator EASE_BOTH = new CubicBezierInterpolator(.42, 0, .58, 1);
|
||||
|
||||
protected PointF start;
|
||||
protected PointF end;
|
||||
protected PointF a = new PointF();
|
||||
protected PointF b = new PointF();
|
||||
protected PointF c = new PointF();
|
||||
|
||||
public CubicBezierInterpolator(PointF start, PointF end) throws IllegalArgumentException {
|
||||
if (start.x < 0 || start.x > 1) {
|
||||
throw new IllegalArgumentException("startX value must be in the range [0, 1]");
|
||||
}
|
||||
if (end.x < 0 || end.x > 1) {
|
||||
throw new IllegalArgumentException("endX value must be in the range [0, 1]");
|
||||
}
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public CubicBezierInterpolator(float startX, float startY, float endX, float endY) {
|
||||
this(new PointF(startX, startY), new PointF(endX, endY));
|
||||
}
|
||||
|
||||
public CubicBezierInterpolator(double startX, double startY, double endX, double endY) {
|
||||
this((float) startX, (float) startY, (float) endX, (float) endY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolation(float time) {
|
||||
return getBezierCoordinateY(getXForTime(time));
|
||||
}
|
||||
|
||||
protected float getBezierCoordinateY(float time) {
|
||||
c.y = 3 * start.y;
|
||||
b.y = 3 * (end.y - start.y) - c.y;
|
||||
a.y = 1 - c.y - b.y;
|
||||
return time * (c.y + time * (b.y + time * a.y));
|
||||
}
|
||||
|
||||
protected float getXForTime(float time) {
|
||||
float x = time;
|
||||
float z;
|
||||
for (int i = 1; i < 14; i++) {
|
||||
z = getBezierCoordinateX(x) - time;
|
||||
if (Math.abs(z) < 1e-3) {
|
||||
break;
|
||||
}
|
||||
x -= z / getXDerivate(x);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
private float getXDerivate(float t) {
|
||||
return c.x + t * (2 * b.x + 3 * a.x * t);
|
||||
}
|
||||
|
||||
private float getBezierCoordinateX(float time) {
|
||||
c.x = 3 * start.x;
|
||||
b.x = 3 * (end.x - start.x) - c.x;
|
||||
a.x = 1 - c.x - b.x;
|
||||
return time * (c.x + time * (b.x + time * a.x));
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package awais.instagrabber.animations;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.view.View;
|
||||
|
||||
// https://medium.com/better-programming/animated-fab-button-with-more-options-2dcf7118fff6
|
||||
|
||||
public class FabAnimation {
|
||||
public static boolean rotateFab(final View v, boolean rotate) {
|
||||
v.animate().setDuration(200)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
}
|
||||
})
|
||||
.rotation(rotate ? 135f : 0f);
|
||||
return rotate;
|
||||
}
|
||||
|
||||
public static void showIn(final View v) {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
v.setAlpha(0f);
|
||||
v.setTranslationY(v.getHeight());
|
||||
v.animate()
|
||||
.setDuration(200)
|
||||
.translationY(0)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
}
|
||||
})
|
||||
.alpha(1f)
|
||||
.start();
|
||||
}
|
||||
|
||||
public static void showOut(final View v) {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
v.setAlpha(1f);
|
||||
v.setTranslationY(0);
|
||||
v.animate()
|
||||
.setDuration(200)
|
||||
.translationY(v.getHeight())
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
v.setVisibility(View.GONE);
|
||||
super.onAnimationEnd(animation);
|
||||
}
|
||||
}).alpha(0f)
|
||||
.start();
|
||||
}
|
||||
|
||||
public static void init(final View v) {
|
||||
v.setVisibility(View.GONE);
|
||||
v.setTranslationY(v.getHeight());
|
||||
v.setAlpha(0f);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package awais.instagrabber.animations;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
/**
|
||||
* A {@link ViewOutlineProvider} that has helper functions to create reveal animations.
|
||||
* This class should be extended so that subclasses can define the reveal shape as the
|
||||
* animation progresses from 0 to 1.
|
||||
*/
|
||||
public abstract class RevealOutlineAnimation extends ViewOutlineProvider {
|
||||
protected Rect mOutline;
|
||||
protected float mOutlineRadius;
|
||||
|
||||
public RevealOutlineAnimation() {
|
||||
mOutline = new Rect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether elevation should be removed for the duration of the reveal animation.
|
||||
*/
|
||||
abstract boolean shouldRemoveElevationDuringAnimation();
|
||||
|
||||
/**
|
||||
* Sets the progress, from 0 to 1, of the reveal animation.
|
||||
*/
|
||||
abstract void setProgress(float progress);
|
||||
|
||||
public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed) {
|
||||
ValueAnimator va =
|
||||
isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
|
||||
final float elevation = revealView.getElevation();
|
||||
|
||||
va.addListener(new AnimatorListenerAdapter() {
|
||||
private boolean mIsClippedToOutline;
|
||||
private ViewOutlineProvider mOldOutlineProvider;
|
||||
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mIsClippedToOutline = revealView.getClipToOutline();
|
||||
mOldOutlineProvider = revealView.getOutlineProvider();
|
||||
|
||||
revealView.setOutlineProvider(RevealOutlineAnimation.this);
|
||||
revealView.setClipToOutline(true);
|
||||
if (shouldRemoveElevationDuringAnimation()) {
|
||||
revealView.setTranslationZ(-elevation);
|
||||
}
|
||||
}
|
||||
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
revealView.setOutlineProvider(mOldOutlineProvider);
|
||||
revealView.setClipToOutline(mIsClippedToOutline);
|
||||
if (shouldRemoveElevationDuringAnimation()) {
|
||||
revealView.setTranslationZ(0);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
va.addUpdateListener(v -> {
|
||||
float progress = (Float) v.getAnimatedValue();
|
||||
setProgress(progress);
|
||||
revealView.invalidateOutline();
|
||||
});
|
||||
return va;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getOutline(View v, Outline outline) {
|
||||
outline.setRoundRect(mOutline, mOutlineRadius);
|
||||
}
|
||||
|
||||
public float getRadius() {
|
||||
return mOutlineRadius;
|
||||
}
|
||||
|
||||
public void getOutline(Rect out) {
|
||||
out.set(mOutline);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package awais.instagrabber.animations;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
/**
|
||||
* A {@link RevealOutlineAnimation} that provides an outline that interpolates between two radii
|
||||
* and two {@link Rect}s.
|
||||
* <p>
|
||||
* An example usage of this provider is an outline that starts out as a circle and ends
|
||||
* as a rounded rectangle.
|
||||
*/
|
||||
public class RoundedRectRevealOutlineProvider extends RevealOutlineAnimation {
|
||||
private final float mStartRadius;
|
||||
private final float mEndRadius;
|
||||
|
||||
private final Rect mStartRect;
|
||||
private final Rect mEndRect;
|
||||
|
||||
public RoundedRectRevealOutlineProvider(float startRadius, float endRadius, Rect startRect, Rect endRect) {
|
||||
mStartRadius = startRadius;
|
||||
mEndRadius = endRadius;
|
||||
mStartRect = startRect;
|
||||
mEndRect = endRect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRemoveElevationDuringAnimation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(float progress) {
|
||||
mOutlineRadius = (1 - progress) * mStartRadius + progress * mEndRadius;
|
||||
|
||||
mOutline.left = (int) ((1 - progress) * mStartRect.left + progress * mEndRect.left);
|
||||
mOutline.top = (int) ((1 - progress) * mStartRect.top + progress * mEndRect.top);
|
||||
mOutline.right = (int) ((1 - progress) * mStartRect.right + progress * mEndRect.right);
|
||||
mOutline.bottom = (int) ((1 - progress) * mStartRect.bottom + progress * mEndRect.bottom);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package awais.instagrabber.animations;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
|
||||
public class ScaleAnimation {
|
||||
|
||||
private final View view;
|
||||
|
||||
public ScaleAnimation(View view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
|
||||
public void start() {
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 2.0f);
|
||||
|
||||
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 2.0f);
|
||||
set.setDuration(150);
|
||||
set.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
set.playTogether(scaleY, scaleX);
|
||||
set.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
|
||||
// scaleY.setDuration(250);
|
||||
// scaleY.setInterpolator(new DecelerateInterpolator());
|
||||
|
||||
|
||||
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
|
||||
// scaleX.setDuration(250);
|
||||
// scaleX.setInterpolator(new DecelerateInterpolator());
|
||||
|
||||
|
||||
set.setDuration(150);
|
||||
set.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
set.playTogether(scaleY, scaleX);
|
||||
set.start();
|
||||
}
|
||||
}
|
@ -17,13 +17,14 @@ import java.util.List;
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.CommentModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.repositories.responses.FriendshipStatus;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awaisomereport.LogCollector;
|
||||
//import awaisomereport.LogCollector;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentModel>> {
|
||||
private static final String TAG = "CommentsFetcher";
|
||||
@ -106,44 +107,34 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentMod
|
||||
|
||||
if (childComment != null) {
|
||||
final JSONObject owner = childComment.getJSONObject("owner");
|
||||
final ProfileModel profileModel = new ProfileModel(false,
|
||||
false,
|
||||
false,
|
||||
owner.getString(Constants.EXTRAS_ID),
|
||||
owner.getString(Constants.EXTRAS_USERNAME),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
owner.getString("profile_pic_url"),
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
|
||||
final User user = new User(
|
||||
owner.optLong(Constants.EXTRAS_ID, 0),
|
||||
owner.getString(Constants.EXTRAS_USERNAME),
|
||||
null,
|
||||
false,
|
||||
owner.getString("profile_pic_url"),
|
||||
null,
|
||||
new FriendshipStatus(false, false, false, false, false, false, false, false, false, false),
|
||||
false, false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, null,
|
||||
null, null, null);
|
||||
final JSONObject likedBy = childComment.optJSONObject("edge_liked_by");
|
||||
|
||||
commentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID),
|
||||
childComment.getString("text"),
|
||||
childComment.getLong("created_at"),
|
||||
likedBy != null ? likedBy.optLong("count", 0) : 0,
|
||||
childComment.getBoolean("viewer_has_liked"),
|
||||
profileModel));
|
||||
user));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e,
|
||||
LogCollector.LogFile.ASYNC_COMMENTS_FETCHER,
|
||||
"getChildComments",
|
||||
new Pair<>("commentModels.size", commentModels.size()));
|
||||
// if (logCollector != null)
|
||||
// logCollector.appendException(e,
|
||||
// LogCollector.LogFile.ASYNC_COMMENTS_FETCHER,
|
||||
// "getChildComments",
|
||||
// new Pair<>("commentModels.size", commentModels.size()));
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", e);
|
||||
if (fetchListener != null) fetchListener.onFailure(e);
|
||||
break;
|
||||
@ -156,138 +147,122 @@ public final class CommentsFetcher extends AsyncTask<Void, Void, List<CommentMod
|
||||
@NonNull
|
||||
private synchronized List<CommentModel> getParentComments() {
|
||||
final List<CommentModel> commentModels = new ArrayList<>();
|
||||
final String url = "https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables=" +
|
||||
"{\"shortcode\":\"" + shortCode + "\",\"first\":50,\"after\":\"" + endCursor.replace("\"", "\\\"") + "\"}";
|
||||
final String url = "https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables=" +
|
||||
"{\"shortcode\":\"" + shortCode + "\",\"first\":50,\"after\":\"" + endCursor.replace("\"", "\\\"") + "\"}";
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setUseCaches(false);
|
||||
conn.connect();
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setUseCaches(false);
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) return null;
|
||||
else {
|
||||
final JSONObject parentComments = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject("shortcode_media")
|
||||
.getJSONObject(
|
||||
"edge_media_to_parent_comment");
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) return null;
|
||||
else {
|
||||
final JSONObject parentComments = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("data")
|
||||
.getJSONObject("shortcode_media")
|
||||
.getJSONObject(
|
||||
"edge_media_to_parent_comment");
|
||||
|
||||
final JSONObject pageInfo = parentComments.getJSONObject("page_info");
|
||||
final String foundEndCursor = pageInfo.optString("end_cursor");
|
||||
final boolean hasNextPage = pageInfo.optBoolean("has_next_page", !TextUtils.isEmpty(foundEndCursor));
|
||||
final JSONObject pageInfo = parentComments.getJSONObject("page_info");
|
||||
final String foundEndCursor = pageInfo.optString("end_cursor");
|
||||
final boolean hasNextPage = pageInfo.optBoolean("has_next_page", !TextUtils.isEmpty(foundEndCursor));
|
||||
|
||||
// final boolean containsToken = endCursor.contains("bifilter_token");
|
||||
// if (!Utils.isEmpty(endCursor) && (containsToken || endCursor.contains("cached_comments_cursor"))) {
|
||||
// final JSONObject endCursorObject = new JSONObject(endCursor);
|
||||
// endCursor = endCursorObject.optString("cached_comments_cursor");
|
||||
//
|
||||
// if (!Utils.isEmpty(endCursor))
|
||||
// endCursor = "{\\\"cached_comments_cursor\\\": \\\"" + endCursor + "\\\", ";
|
||||
// else
|
||||
// endCursor = "{";
|
||||
//
|
||||
// endCursor = endCursor + "\\\"bifilter_token\\\": \\\"" + endCursorObject.getString("bifilter_token") + "\\\"}";
|
||||
// }
|
||||
// else if (containsToken) endCursor = null;
|
||||
// final boolean containsToken = endCursor.contains("bifilter_token");
|
||||
// if (!Utils.isEmpty(endCursor) && (containsToken || endCursor.contains("cached_comments_cursor"))) {
|
||||
// final JSONObject endCursorObject = new JSONObject(endCursor);
|
||||
// endCursor = endCursorObject.optString("cached_comments_cursor");
|
||||
//
|
||||
// if (!Utils.isEmpty(endCursor))
|
||||
// endCursor = "{\\\"cached_comments_cursor\\\": \\\"" + endCursor + "\\\", ";
|
||||
// else
|
||||
// endCursor = "{";
|
||||
//
|
||||
// endCursor = endCursor + "\\\"bifilter_token\\\": \\\"" + endCursorObject.getString("bifilter_token") + "\\\"}";
|
||||
// }
|
||||
// else if (containsToken) endCursor = null;
|
||||
|
||||
final JSONArray comments = parentComments.getJSONArray("edges");
|
||||
final int commentsLen = comments.length();
|
||||
for (int i = 0; i < commentsLen; ++i) {
|
||||
final JSONObject comment = comments.getJSONObject(i).getJSONObject("node");
|
||||
final JSONArray comments = parentComments.getJSONArray("edges");
|
||||
final int commentsLen = comments.length();
|
||||
for (int i = 0; i < commentsLen; ++i) {
|
||||
final JSONObject comment = comments.getJSONObject(i).getJSONObject("node");
|
||||
|
||||
final JSONObject owner = comment.getJSONObject("owner");
|
||||
final ProfileModel profileModel = new ProfileModel(false,
|
||||
false,
|
||||
owner.optBoolean("is_verified"),
|
||||
owner.getString(Constants.EXTRAS_ID),
|
||||
owner.getString(Constants.EXTRAS_USERNAME),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
owner.getString("profile_pic_url"),
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
final JSONObject owner = comment.getJSONObject("owner");
|
||||
final User user = new User(
|
||||
owner.optLong(Constants.EXTRAS_ID, 0),
|
||||
owner.getString(Constants.EXTRAS_USERNAME),
|
||||
null,
|
||||
false,
|
||||
owner.getString("profile_pic_url"),
|
||||
null,
|
||||
new FriendshipStatus(false, false, false, false, false, false, false, false, false, false),
|
||||
owner.optBoolean("is_verified"),
|
||||
false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0, null, null, null, null,
|
||||
null, null);
|
||||
final JSONObject likedBy = comment.optJSONObject("edge_liked_by");
|
||||
final String commentId = comment.getString(Constants.EXTRAS_ID);
|
||||
final CommentModel commentModel = new CommentModel(commentId,
|
||||
comment.getString("text"),
|
||||
comment.getLong("created_at"),
|
||||
likedBy != null ? likedBy.optLong("count", 0) : 0,
|
||||
comment.getBoolean("viewer_has_liked"),
|
||||
user);
|
||||
if (i == 0 && !foundEndCursor.contains("tao_cursor"))
|
||||
commentModel.setPageCursor(hasNextPage, TextUtils.isEmpty(foundEndCursor) ? null : foundEndCursor);
|
||||
JSONObject tempJsonObject;
|
||||
final JSONArray childCommentsArray;
|
||||
final int childCommentsLen;
|
||||
if ((tempJsonObject = comment.optJSONObject("edge_threaded_comments")) != null &&
|
||||
(childCommentsArray = tempJsonObject.optJSONArray("edges")) != null
|
||||
&& (childCommentsLen = childCommentsArray.length()) > 0) {
|
||||
|
||||
final JSONObject likedBy = comment.optJSONObject("edge_liked_by");
|
||||
final String commentId = comment.getString(Constants.EXTRAS_ID);
|
||||
final CommentModel commentModel = new CommentModel(commentId,
|
||||
comment.getString("text"),
|
||||
comment.getLong("created_at"),
|
||||
likedBy != null ? likedBy.optLong("count", 0) : 0,
|
||||
comment.getBoolean("viewer_has_liked"),
|
||||
profileModel);
|
||||
if (i == 0 && !foundEndCursor.contains("tao_cursor"))
|
||||
commentModel.setPageCursor(hasNextPage, TextUtils.isEmpty(foundEndCursor) ? null : foundEndCursor);
|
||||
JSONObject tempJsonObject;
|
||||
final JSONArray childCommentsArray;
|
||||
final int childCommentsLen;
|
||||
if ((tempJsonObject = comment.optJSONObject("edge_threaded_comments")) != null &&
|
||||
(childCommentsArray = tempJsonObject.optJSONArray("edges")) != null
|
||||
&& (childCommentsLen = childCommentsArray.length()) > 0) {
|
||||
|
||||
final String childEndCursor;
|
||||
final boolean childHasNextPage;
|
||||
if ((tempJsonObject = tempJsonObject.optJSONObject("page_info")) != null) {
|
||||
childEndCursor = tempJsonObject.optString("end_cursor");
|
||||
childHasNextPage = tempJsonObject.optBoolean("has_next_page", !TextUtils.isEmpty(childEndCursor));
|
||||
} else {
|
||||
childEndCursor = null;
|
||||
childHasNextPage = false;
|
||||
}
|
||||
|
||||
final List<CommentModel> childCommentModels = new ArrayList<>();
|
||||
for (int j = 0; j < childCommentsLen; ++j) {
|
||||
final JSONObject childComment = childCommentsArray.getJSONObject(j).getJSONObject("node");
|
||||
|
||||
tempJsonObject = childComment.getJSONObject("owner");
|
||||
final ProfileModel childProfileModel = new ProfileModel(false,
|
||||
false,
|
||||
tempJsonObject.optBoolean("is_verified"),
|
||||
tempJsonObject.getString(Constants.EXTRAS_ID),
|
||||
tempJsonObject.getString(Constants.EXTRAS_USERNAME),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
tempJsonObject.getString("profile_pic_url"),
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
|
||||
tempJsonObject = childComment.optJSONObject("edge_liked_by");
|
||||
childCommentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID),
|
||||
childComment.getString("text"),
|
||||
childComment.getLong("created_at"),
|
||||
tempJsonObject != null ? tempJsonObject.optLong("count", 0) : 0,
|
||||
childComment.getBoolean("viewer_has_liked"),
|
||||
childProfileModel));
|
||||
}
|
||||
childCommentModels.get(childCommentsLen - 1).setPageCursor(childHasNextPage, childEndCursor);
|
||||
commentModel.setChildCommentModels(childCommentModels);
|
||||
final String childEndCursor;
|
||||
final boolean childHasNextPage;
|
||||
if ((tempJsonObject = tempJsonObject.optJSONObject("page_info")) != null) {
|
||||
childEndCursor = tempJsonObject.optString("end_cursor");
|
||||
childHasNextPage = tempJsonObject.optBoolean("has_next_page", !TextUtils.isEmpty(childEndCursor));
|
||||
} else {
|
||||
childEndCursor = null;
|
||||
childHasNextPage = false;
|
||||
}
|
||||
commentModels.add(commentModel);
|
||||
}
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
if (logCollector != null)
|
||||
logCollector.appendException(e, LogCollector.LogFile.ASYNC_COMMENTS_FETCHER, "getParentComments",
|
||||
new Pair<>("commentModelsList.size", commentModels.size()));
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (fetchListener != null) fetchListener.onFailure(e);
|
||||
return null;
|
||||
final List<CommentModel> childCommentModels = new ArrayList<>();
|
||||
for (int j = 0; j < childCommentsLen; ++j) {
|
||||
final JSONObject childComment = childCommentsArray.getJSONObject(j).getJSONObject("node");
|
||||
|
||||
tempJsonObject = childComment.getJSONObject("owner");
|
||||
final User childUser = new User(
|
||||
tempJsonObject.optLong(Constants.EXTRAS_ID, 0),
|
||||
tempJsonObject.getString(Constants.EXTRAS_USERNAME),
|
||||
null,
|
||||
false,
|
||||
tempJsonObject.getString("profile_pic_url"),
|
||||
null,
|
||||
new FriendshipStatus(false, false, false, false, false, false, false, false, false, false),
|
||||
tempJsonObject.optBoolean("is_verified"), false, false, false, false, null, null, 0, 0, 0, 0, null, null, 0,
|
||||
null, null, null, null, null, null);
|
||||
|
||||
tempJsonObject = childComment.optJSONObject("edge_liked_by");
|
||||
childCommentModels.add(new CommentModel(childComment.getString(Constants.EXTRAS_ID),
|
||||
childComment.getString("text"),
|
||||
childComment.getLong("created_at"),
|
||||
tempJsonObject != null ? tempJsonObject.optLong("count", 0) : 0,
|
||||
childComment.getBoolean("viewer_has_liked"),
|
||||
childUser));
|
||||
}
|
||||
childCommentModels.get(childCommentsLen - 1).setPageCursor(childHasNextPage, childEndCursor);
|
||||
commentModel.setChildCommentModels(childCommentModels);
|
||||
}
|
||||
commentModels.add(commentModel);
|
||||
}
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
// if (logCollector != null)
|
||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_COMMENTS_FETCHER, "getParentComments",
|
||||
// new Pair<>("commentModelsList.size", commentModels.size()));
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
if (fetchListener != null) fetchListener.onFailure(e);
|
||||
return null;
|
||||
}
|
||||
return commentModels;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.webservices.DirectMessagesService;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class CreateThreadAction extends AsyncTask<Void, Void, Void> {
|
||||
private static final String TAG = "CommentAction";
|
||||
|
||||
private final String cookie;
|
||||
private final long userId;
|
||||
private final OnTaskCompleteListener onTaskCompleteListener;
|
||||
private final DirectMessagesService directMessagesService;
|
||||
|
||||
public CreateThreadAction(final String cookie, final long userId, final OnTaskCompleteListener onTaskCompleteListener) {
|
||||
this.cookie = cookie;
|
||||
this.userId = userId;
|
||||
this.onTaskCompleteListener = onTaskCompleteListener;
|
||||
directMessagesService = DirectMessagesService.getInstance(CookieUtils.getCsrfTokenFromCookie(cookie),
|
||||
CookieUtils.getUserIdFromCookie(cookie),
|
||||
Utils.settingsHelper.getString(Constants.DEVICE_UUID));
|
||||
}
|
||||
|
||||
protected Void doInBackground(Void... lmao) {
|
||||
final Call<DirectThread> createThreadRequest = directMessagesService.createThread(Collections.singletonList(userId), null);
|
||||
createThreadRequest.enqueue(new Callback<DirectThread>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<DirectThread> call, @NonNull final Response<DirectThread> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.errorBody() != null) {
|
||||
try {
|
||||
final String string = response.errorBody().string();
|
||||
final String msg = String.format(Locale.US,
|
||||
"onResponse: url: %s, responseCode: %d, errorBody: %s",
|
||||
call.request().url().toString(),
|
||||
response.code(),
|
||||
string);
|
||||
Log.e(TAG, msg);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "onResponse: ", e);
|
||||
}
|
||||
}
|
||||
Log.e(TAG, "onResponse: request was not successful and response error body was null");
|
||||
}
|
||||
onTaskCompleteListener.onTaskComplete(response.body());
|
||||
if (response.body() == null) {
|
||||
Log.e(TAG, "onResponse: thread is null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<DirectThread> call, @NonNull final Throwable t) {
|
||||
onTaskCompleteListener.onTaskComplete(null);
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void onPostExecute() {
|
||||
// }
|
||||
|
||||
public interface OnTaskCompleteListener {
|
||||
void onTaskComplete(final DirectThread thread);
|
||||
}
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import awais.instagrabber.customviews.helpers.PostFetcher;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.discover.TopicalExploreFeedResponse;
|
||||
import awais.instagrabber.repositories.responses.WrappedMedia;
|
||||
import awais.instagrabber.webservices.DiscoverService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
|
||||
@ -20,18 +25,28 @@ public class DiscoverPostFetchService implements PostFetcher.PostFetchService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(final FetchListener<List<FeedModel>> fetchListener) {
|
||||
discoverService.topicalExplore(topicalExploreRequest, new ServiceCallback<DiscoverService.TopicalExploreResponse>() {
|
||||
public void fetch(final FetchListener<List<Media>> fetchListener) {
|
||||
discoverService.topicalExplore(topicalExploreRequest, new ServiceCallback<TopicalExploreFeedResponse>() {
|
||||
@Override
|
||||
public void onSuccess(final DiscoverService.TopicalExploreResponse result) {
|
||||
public void onSuccess(final TopicalExploreFeedResponse result) {
|
||||
if (result == null) {
|
||||
onFailure(new RuntimeException("result is null"));
|
||||
return;
|
||||
}
|
||||
moreAvailable = result.isMoreAvailable();
|
||||
topicalExploreRequest.setMaxId(result.getNextMaxId());
|
||||
final List<WrappedMedia> items = result.getItems();
|
||||
final List<Media> posts;
|
||||
if (items == null) {
|
||||
posts = Collections.emptyList();
|
||||
} else {
|
||||
posts = items.stream()
|
||||
.map(WrappedMedia::getMedia)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
if (fetchListener != null) {
|
||||
fetchListener.onResult(result.getItems());
|
||||
fetchListener.onResult(posts);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +61,7 @@ public class DiscoverPostFetchService implements PostFetcher.PostFetchService {
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
topicalExploreRequest.setMaxId(-1);
|
||||
topicalExploreRequest.setMaxId(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user