Merge branch 'master' into retrofit-intercept-errors
This commit is contained in:
commit
6965fbdc9a
@ -42,15 +42,6 @@
|
||||
"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",
|
||||
@ -61,10 +52,10 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AwaisKing",
|
||||
"name": "AWAiS",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/5278488",
|
||||
"profile": "http://rerolledgeek.blogspot.com/",
|
||||
"login": "Zopieux",
|
||||
"name": "Alexandre Macabies",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/81353?v=4",
|
||||
"profile": "https://github.com/Zopieux",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
@ -119,16 +110,6 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "e-edgren",
|
||||
"name": "Airikr",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/53869451",
|
||||
"profile": "https://airikr.me/",
|
||||
"contributions": [
|
||||
"ideas",
|
||||
"question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Akrai",
|
||||
"name": "Akrai",
|
||||
@ -274,6 +255,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Pyrobauve",
|
||||
"name": "Pyrobauve",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/48654473?v=4",
|
||||
"profile": "https://github.com/Pyrobauve",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "RAMAR-RAR",
|
||||
"name": "RAMAR-RAR",
|
||||
@ -319,6 +309,15 @@
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Sitavi",
|
||||
"name": "Sitavi",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/80586127?v=4",
|
||||
"profile": "https://github.com/Sitavi",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Still34",
|
||||
"name": "Still Hsu",
|
||||
|
67
.github/workflows/github_nightly_release.yml
vendored
Normal file
67
.github/workflows/github_nightly_release.yml
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
name: Github nightly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# * is a special character in YAML so you have to quote this string
|
||||
- cron: '27 10 * * *' # Everyday at 10:27:00
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Build Github unsigned apk
|
||||
run: ./gradlew assembleGithubRelease --stacktrace --project-prop pre
|
||||
|
||||
- name: Sign APK
|
||||
uses: r0adkll/sign-android-release@v1
|
||||
# ID used to access action output
|
||||
id: sign_app
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/github/release
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
|
||||
- name: Get current date and time
|
||||
id: date
|
||||
run: echo "::set-output name=date::$(date +'%Y%m%d_%H%M%S')"
|
||||
|
||||
# Create artifact
|
||||
- name: Create apk artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: barinsta_nightly_${{ steps.date.outputs.date }}
|
||||
path: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
|
||||
# Send success notification
|
||||
- name: Send success Telegram notification
|
||||
if: ${{ success() }}
|
||||
uses: appleboy/telegram-action@master
|
||||
with:
|
||||
to: ${{ secrets.TELEGRAM_BUILDS_CHANNEL_TO }}
|
||||
token: ${{ secrets.TELEGRAM_BUILDS_BOT_TOKEN }}
|
||||
message: "${{ github.workflow }} ${{ github.job }} #${{ github.run_number }} completed successfully.\nhttps://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
||||
document: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
|
||||
# Send failure notification
|
||||
- name: Send failure Telegram notification
|
||||
if: ${{ failure() }}
|
||||
uses: appleboy/telegram-action@master
|
||||
with:
|
||||
to: ${{ secrets.TELEGRAM_BUILDS_CHANNEL_TO }}
|
||||
token: ${{ secrets.TELEGRAM_BUILDS_BOT_TOKEN }}
|
||||
message: "${{ github.workflow }} ${{ github.job }} #${{ github.run_number }} failed.\nhttps://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
68
.github/workflows/github_pre_release.yml
vendored
Normal file
68
.github/workflows/github_pre_release.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: Github pre-release
|
||||
|
||||
on: workflow_dispatch
|
||||
# push:
|
||||
# branches: [ master ]
|
||||
# pull_request:
|
||||
# branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Build Github unsigned pre-release apk
|
||||
run: ./gradlew assembleGithubRelease --stacktrace --project-prop pre
|
||||
|
||||
- name: Sign APK
|
||||
uses: r0adkll/sign-android-release@v1
|
||||
# ID used to access action output
|
||||
id: sign_app
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/github/release
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
|
||||
- name: Get current date and time
|
||||
id: date
|
||||
run: echo "::set-output name=date::$(date +'%Y%m%d_%H%M%S')"
|
||||
|
||||
# Create artifact
|
||||
- name: Create apk artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: barinsta_pre-release_${{ steps.date.outputs.date }}
|
||||
path: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
|
||||
# Send success notification
|
||||
- name: Send success Telegram notification
|
||||
if: ${{ success() }}
|
||||
uses: appleboy/telegram-action@master
|
||||
with:
|
||||
to: ${{ secrets.TELEGRAM_BUILDS_CHANNEL_TO }}
|
||||
token: ${{ secrets.TELEGRAM_BUILDS_BOT_TOKEN }}
|
||||
message: "${{ github.workflow }} ${{ github.job }} #${{ github.run_number }} completed successfully.\nURL: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
||||
document: ${{steps.sign_app.outputs.signedReleaseFile}}
|
||||
|
||||
# Send failure notification
|
||||
- name: Send failure Telegram notification
|
||||
if: ${{ failure() }}
|
||||
uses: appleboy/telegram-action@master
|
||||
with:
|
||||
to: ${{ secrets.TELEGRAM_BUILDS_CHANNEL_TO }}
|
||||
token: ${{ secrets.TELEGRAM_BUILDS_BOT_TOKEN }}
|
||||
message: "${{ github.workflow }} ${{ github.job }} #${{ github.run_number }} failed.\nURL: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
18
.github/workflows/label-bugs.yml
vendored
Normal file
18
.github/workflows/label-bugs.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Label bugs
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
add-labels:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.body, 'New Trace collected:') == true
|
||||
steps:
|
||||
- name: Add labels
|
||||
uses: actions-cool/issues-helper@v2.2.1
|
||||
with:
|
||||
actions: 'add-labels'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
labels: 'bug'
|
18
.github/workflows/label-duplicates.yml
vendored
Normal file
18
.github/workflows/label-duplicates.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Label duplicates
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
add-labels:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.comment.body, 'Duplicate of') == true
|
||||
steps:
|
||||
- name: Add labels
|
||||
uses: actions-cool/issues-helper@v2.2.1
|
||||
with:
|
||||
actions: 'add-labels'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
labels: 'duplicate'
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -17,3 +17,6 @@
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
app/release
|
||||
/sentry.properties
|
||||
/app/fdroid/
|
||||
/app/github/
|
||||
|
@ -1 +1 @@
|
||||
InstaGrabber
|
||||
Barinsta
|
28
README.md
28
README.md
@ -57,46 +57,46 @@ 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://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://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>
|
||||
</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://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>
|
||||
</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>
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
<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://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>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
<td align="center"><a href="https://github.com/Pyrobauve"><img src="https://avatars.githubusercontent.com/u/48654473?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pyrobauve</b></sub></a><br /><a href="https://crowdin.com/project/instagrabber" title="Translation">🌍</a></td>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
<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://github.com/Sitavi"><img src="https://avatars.githubusercontent.com/u/80586127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sitavi</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>
|
||||
|
@ -1,5 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: "androidx.navigation.safeargs"
|
||||
apply from: 'sentry.gradle'
|
||||
|
||||
def getGitHash = { ->
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine 'git', 'rev-parse', '--short', 'HEAD'
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
@ -48,8 +58,41 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "repo"
|
||||
|
||||
productFlavors {
|
||||
github {
|
||||
dimension "repo"
|
||||
// versionNameSuffix "-github" // appended in assemble task
|
||||
buildConfigField("String", "dsn", SENTRY_DSN)
|
||||
}
|
||||
|
||||
fdroid {
|
||||
dimension "repo"
|
||||
versionNameSuffix "-fdroid"
|
||||
}
|
||||
}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
if (variant.flavorName != "github") return
|
||||
variant.outputs.all { output ->
|
||||
def builtType = variant.buildType.name
|
||||
def versionName = variant.versionName
|
||||
// def versionCode = variant.versionCode
|
||||
def flavor = variant.flavorName
|
||||
|
||||
def suffix = "${versionName}-${flavor}_${builtType}" // eg. 19.1.0-github_debug or release
|
||||
if (builtType.toString() == 'release' && project.hasProperty("pre")) {
|
||||
// append latest commit short hash for pre-release
|
||||
suffix = "${versionName}.${getGitHash()}-${flavor}" // eg. 19.1.0.b123456-github
|
||||
}
|
||||
|
||||
output.versionNameOverride = suffix
|
||||
outputFileName = "barinsta_${suffix}.apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
|
||||
@ -70,7 +113,7 @@ dependencies {
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$appcompat_version"
|
||||
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-beta02"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.0-rc01"
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
implementation "androidx.navigation:navigation-fragment:$nav_version"
|
||||
@ -81,7 +124,7 @@ dependencies {
|
||||
implementation 'androidx.palette:palette:1.0.0'
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
|
||||
implementation 'com.google.guava:guava:27.1-jre'
|
||||
implementation 'com.google.guava:guava:27.0.1-android'
|
||||
|
||||
// Room
|
||||
def room_version = "2.2.6"
|
||||
@ -90,7 +133,7 @@ dependencies {
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
|
||||
// CameraX
|
||||
def camerax_version = "1.1.0-alpha02"
|
||||
def camerax_version = "1.1.0-alpha03"
|
||||
implementation "androidx.camera:camera-camera2:$camerax_version"
|
||||
implementation "androidx.camera:camera-lifecycle:$camerax_version"
|
||||
implementation "androidx.camera:camera-view:1.0.0-alpha22"
|
||||
@ -114,8 +157,9 @@ dependencies {
|
||||
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.6'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
|
||||
|
||||
githubImplementation 'io.sentry:sentry-android:4.3.0'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
|
||||
}
|
||||
|
13
app/sentry.gradle
Normal file
13
app/sentry.gradle
Normal file
@ -0,0 +1,13 @@
|
||||
def dsnKey = 'DSN'
|
||||
def defaultDsn = '\"\"'
|
||||
|
||||
final Properties properties = new Properties()
|
||||
File propertiesFile = rootProject.file('sentry.properties')
|
||||
if (!propertiesFile.exists()) {
|
||||
propertiesFile.createNewFile()
|
||||
}
|
||||
properties.load(new FileInputStream(propertiesFile))
|
||||
|
||||
ext{
|
||||
SENTRY_DSN = properties.getProperty(dsnKey, defaultDsn)
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package awais.instagrabber.fragments.settings;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.fragments.settings.IFlavorSettings;
|
||||
import awais.instagrabber.fragments.settings.SettingCategory;
|
||||
|
||||
public final class FlavorSettings implements IFlavorSettings {
|
||||
|
||||
private static FlavorSettings instance;
|
||||
|
||||
private FlavorSettings() {
|
||||
}
|
||||
|
||||
public static FlavorSettings getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FlavorSettings();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Preference> getPreferences(@NonNull final Context context,
|
||||
@NonNull final FragmentManager fragmentManager,
|
||||
@NonNull final SettingCategory settingCategory) {
|
||||
// switch (settingCategory) {
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
56
app/src/fdroid/java/awaisomereport/CrashHandler.java
Normal file
56
app/src/fdroid/java/awaisomereport/CrashHandler.java
Normal file
@ -0,0 +1,56 @@
|
||||
package awaisomereport;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class CrashHandler implements ICrashHandler {
|
||||
private static final String TAG = CrashHandler.class.getSimpleName();
|
||||
|
||||
private final Application application;
|
||||
|
||||
public CrashHandler(@NonNull final Application application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(@NonNull final Thread t,
|
||||
@NonNull final Throwable exception,
|
||||
@NonNull final Thread.UncaughtExceptionHandler defaultEH) {
|
||||
CrashReporterHelper.startErrorReporterActivity(application, exception);
|
||||
// zipLogs();
|
||||
defaultEH.uncaughtException(t, exception);
|
||||
}
|
||||
|
||||
// public synchronized CrashReporter zipLogs() {
|
||||
// final File logDir = Utils.logCollector != null ? Utils.logCollector.getLogDir() :
|
||||
// new File(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? application.getDataDir() : application.getFilesDir(), "crashlogs");
|
||||
//
|
||||
// try (final FileOutputStream fos = new FileOutputStream(crashLogsZip);
|
||||
// final ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||
//
|
||||
// final File[] files = logDir.listFiles();
|
||||
//
|
||||
// if (files != null) {
|
||||
// zos.setLevel(5);
|
||||
// byte[] buffer;
|
||||
// for (final File file : files) {
|
||||
// if (file != null && file.length() > 0) {
|
||||
// buffer = new byte[1024];
|
||||
// try (final FileInputStream fis = new FileInputStream(file)) {
|
||||
// zos.putNextEntry(new ZipEntry(file.getName()));
|
||||
// int length;
|
||||
// while ((length = fis.read(buffer)) > 0) zos.write(buffer, 0, length);
|
||||
// zos.closeEntry();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } catch (final Exception e) {
|
||||
// if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
// }
|
||||
//
|
||||
// return this;
|
||||
// }
|
||||
}
|
10
app/src/github/AndroidManifest.xml
Normal file
10
app/src/github/AndroidManifest.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="awais.instagrabber">
|
||||
|
||||
<application>
|
||||
<meta-data
|
||||
android:name="io.sentry.auto-init"
|
||||
android:value="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,83 @@
|
||||
package awais.instagrabber.fragments.settings;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.dialogs.ConfirmDialogFragment;
|
||||
|
||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class FlavorSettings implements IFlavorSettings {
|
||||
|
||||
private static FlavorSettings instance;
|
||||
|
||||
private FlavorSettings() {
|
||||
}
|
||||
|
||||
public static FlavorSettings getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FlavorSettings();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Preference> getPreferences(@NonNull final Context context,
|
||||
@NonNull final FragmentManager fragmentManager,
|
||||
@NonNull final SettingCategory settingCategory) {
|
||||
switch (settingCategory) {
|
||||
case GENERAL:
|
||||
return getGeneralPrefs(context, fragmentManager);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<Preference> getGeneralPrefs(@NonNull final Context context,
|
||||
@NonNull final FragmentManager fragmentManager) {
|
||||
return ImmutableList.of(
|
||||
getSentryPreference(context, fragmentManager)
|
||||
);
|
||||
}
|
||||
|
||||
private Preference getSentryPreference(@NonNull final Context context,
|
||||
@NonNull final FragmentManager fragmentManager) {
|
||||
if (!settingsHelper.hasPreference(PREF_ENABLE_SENTRY)) {
|
||||
// disabled by default
|
||||
settingsHelper.putBoolean(PREF_ENABLE_SENTRY, false);
|
||||
}
|
||||
return PreferenceHelper.getSwitchPreference(
|
||||
context,
|
||||
PREF_ENABLE_SENTRY,
|
||||
R.string.enable_sentry,
|
||||
R.string.sentry_summary,
|
||||
false,
|
||||
(preference, newValue) -> {
|
||||
if (!(newValue instanceof Boolean)) return true;
|
||||
final boolean enabled = (Boolean) newValue;
|
||||
if (enabled) {
|
||||
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
|
||||
111,
|
||||
0,
|
||||
R.string.sentry_start_next_launch,
|
||||
R.string.ok,
|
||||
0,
|
||||
0);
|
||||
dialogFragment.show(fragmentManager, "sentry_dialog");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
59
app/src/github/java/awaisomereport/CrashHandler.java
Normal file
59
app/src/github/java/awaisomereport/CrashHandler.java
Normal file
@ -0,0 +1,59 @@
|
||||
package awaisomereport;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.fragments.settings.PreferenceKeys;
|
||||
import io.sentry.SentryLevel;
|
||||
import io.sentry.android.core.SentryAndroid;
|
||||
import io.sentry.protocol.Contexts;
|
||||
import io.sentry.protocol.Device;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class CrashHandler implements ICrashHandler {
|
||||
private static final String TAG = CrashHandler.class.getSimpleName();
|
||||
|
||||
private final Application application;
|
||||
private final boolean enabled;
|
||||
|
||||
public CrashHandler(@NonNull final Application application) {
|
||||
this.application = application;
|
||||
if (!settingsHelper.hasPreference(PreferenceKeys.PREF_ENABLE_SENTRY)) {
|
||||
// disabled by default (change to true if we need enabled by default)
|
||||
enabled = false;
|
||||
} else {
|
||||
enabled = settingsHelper.getBoolean(PreferenceKeys.PREF_ENABLE_SENTRY);
|
||||
}
|
||||
if (!enabled) return;
|
||||
SentryAndroid.init(application, options -> {
|
||||
options.setDsn(BuildConfig.dsn);
|
||||
options.setDiagnosticLevel(SentryLevel.ERROR);
|
||||
options.setBeforeSend((event, hint) -> {
|
||||
// Removing unneeded info from event
|
||||
final Contexts contexts = event.getContexts();
|
||||
final Device device = contexts.getDevice();
|
||||
device.setName(null);
|
||||
device.setTimezone(null);
|
||||
device.setCharging(null);
|
||||
device.setBootTime(null);
|
||||
device.setFreeStorage(null);
|
||||
device.setBatteryTemperature(null);
|
||||
return event;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(@NonNull final Thread t,
|
||||
@NonNull final Throwable exception,
|
||||
@NonNull final Thread.UncaughtExceptionHandler defaultEH) {
|
||||
// When enabled, Sentry auto captures unhandled exceptions
|
||||
if (!enabled) {
|
||||
CrashReporterHelper.startErrorReporterActivity(application, exception);
|
||||
}
|
||||
defaultEH.uncaughtException(t, exception);
|
||||
}
|
||||
}
|
6
app/src/github/res/values/strings.xml
Normal file
6
app/src/github/res/values/strings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="enable_sentry">Enable Sentry</string>
|
||||
<string name="sentry_summary">Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io</string>
|
||||
<string name="sentry_start_next_launch">Sentry will start on next launch</string>
|
||||
</resources>
|
@ -35,16 +35,16 @@ public final class InstaGrabberApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// final Set<RequestListener> requestListeners = new HashSet<>();
|
||||
// requestListeners.add(new RequestLoggingListener());
|
||||
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
||||
.newBuilder(this)
|
||||
// .setMainDiskCacheConfig(diskCacheConfig)
|
||||
// .setRequestListeners(requestListeners)
|
||||
.setDownsampleEnabled(true)
|
||||
.build();
|
||||
Fresco.initialize(this, imagePipelineConfig);
|
||||
// FLog.setMinimumLoggingLevel(FLog.VERBOSE);
|
||||
CookieHandler.setDefault(NET_COOKIE_MANAGER);
|
||||
|
||||
if (settingsHelper == null) {
|
||||
settingsHelper = new SettingsHelper(this);
|
||||
}
|
||||
|
||||
if (!BuildConfig.DEBUG) {
|
||||
CrashReporter.get(this).start();
|
||||
}
|
||||
// logCollector = new LogCollector(this);
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
try {
|
||||
@ -56,13 +56,16 @@ public final class InstaGrabberApplication extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
if (!BuildConfig.DEBUG) CrashReporter.get(this).start();
|
||||
// logCollector = new LogCollector(this);
|
||||
|
||||
CookieHandler.setDefault(NET_COOKIE_MANAGER);
|
||||
|
||||
if (settingsHelper == null)
|
||||
settingsHelper = new SettingsHelper(this);
|
||||
// final Set<RequestListener> requestListeners = new HashSet<>();
|
||||
// requestListeners.add(new RequestLoggingListener());
|
||||
final ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
|
||||
.newBuilder(this)
|
||||
// .setMainDiskCacheConfig(diskCacheConfig)
|
||||
// .setRequestListeners(requestListeners)
|
||||
.setDownsampleEnabled(true)
|
||||
.build();
|
||||
Fresco.initialize(this, imagePipelineConfig);
|
||||
// FLog.setMinimumLoggingLevel(FLog.VERBOSE);
|
||||
|
||||
if (applicationHandler == null) {
|
||||
applicationHandler = new Handler(getApplicationContext().getMainLooper());
|
||||
|
@ -11,7 +11,6 @@ import android.content.ServiceConnection;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -57,21 +56,21 @@ import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.repositories.responses.search.SearchItem;
|
||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
||||
import awais.instagrabber.services.ActivityCheckerService;
|
||||
import awais.instagrabber.services.DMSyncAlarmReceiver;
|
||||
import awais.instagrabber.utils.AppExecutors;
|
||||
@ -84,6 +83,10 @@ import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.utils.emoji.EmojiParser;
|
||||
import awais.instagrabber.viewmodels.AppStateViewModel;
|
||||
import awais.instagrabber.webservices.RetrofitFactory;
|
||||
import awais.instagrabber.webservices.SearchService;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -106,6 +109,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
private SuggestionsAdapter suggestionAdapter;
|
||||
private AutoCompleteTextView searchAutoComplete;
|
||||
private SearchView searchView;
|
||||
private SearchService searchService;
|
||||
private boolean showSearch = true;
|
||||
private Handler suggestionsFetchHandler;
|
||||
private int firstFragmentGraphIndex;
|
||||
@ -173,10 +177,11 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
||||
// Initialise the internal map
|
||||
AppExecutors.getInstance().tasksThread().execute(() -> {
|
||||
EmojiParser.getInstance();
|
||||
EmojiParser.setup(this);
|
||||
EmojiVariantManager.getInstance();
|
||||
});
|
||||
initEmojiCompat();
|
||||
searchService = SearchService.getInstance();
|
||||
// initDmService();
|
||||
}
|
||||
|
||||
@ -313,7 +318,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
final Bundle bundle = new Bundle();
|
||||
switch (type) {
|
||||
case TYPE_LOCATION:
|
||||
bundle.putString("locationId", query);
|
||||
bundle.putLong("locationId", Long.valueOf(query));
|
||||
navController.navigate(R.id.action_global_locationFragment, bundle);
|
||||
break;
|
||||
case TYPE_HASHTAG:
|
||||
@ -341,51 +346,84 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
private boolean searchUser;
|
||||
private boolean searchHash;
|
||||
private AsyncTask<?, ?, ?> prevSuggestionAsync;
|
||||
private Call<SearchResponse> prevSuggestionAsync;
|
||||
private final String[] COLUMNS = {
|
||||
BaseColumns._ID,
|
||||
Constants.EXTRAS_USERNAME,
|
||||
Constants.EXTRAS_NAME,
|
||||
Constants.EXTRAS_TYPE,
|
||||
"query",
|
||||
"pfp",
|
||||
"verified"
|
||||
};
|
||||
private String currentSearchQuery;
|
||||
|
||||
private final FetchListener<SuggestionModel[]> fetchListener = new FetchListener<SuggestionModel[]>() {
|
||||
private final Callback<SearchResponse> cb = new Callback<SearchResponse>() {
|
||||
@Override
|
||||
public void doBefore() {
|
||||
suggestionAdapter.changeCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(final SuggestionModel[] result) {
|
||||
public void onResponse(@NonNull final Call<SearchResponse> call,
|
||||
@NonNull final Response<SearchResponse> response) {
|
||||
final MatrixCursor cursor;
|
||||
if (result == null) cursor = null;
|
||||
final SearchResponse body = response.body();
|
||||
if (body == null) {
|
||||
cursor = null;
|
||||
return;
|
||||
}
|
||||
final List<SearchItem> result = new ArrayList<SearchItem>();
|
||||
if (isLoggedIn) {
|
||||
if (body.getList() != null) result.addAll(searchHash ? body.getList()
|
||||
.stream()
|
||||
.filter(i -> i.getUser() == null)
|
||||
.collect(Collectors.toList()) : body.getList());
|
||||
}
|
||||
else {
|
||||
if (body.getUsers() != null && !searchHash) result.addAll(body.getUsers());
|
||||
if (body.getHashtags() != null) result.addAll(body.getHashtags());
|
||||
if (body.getPlaces() != null) result.addAll(body.getPlaces());
|
||||
}
|
||||
cursor = new MatrixCursor(COLUMNS, 0);
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
final SuggestionModel suggestionModel = result[i];
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
final SearchItem suggestionModel = result.get(i);
|
||||
if (suggestionModel != null) {
|
||||
final SuggestionType suggestionType = suggestionModel.getSuggestionType();
|
||||
final Object[] objects = {
|
||||
i,
|
||||
suggestionType == SuggestionType.TYPE_LOCATION ? suggestionModel.getName() : suggestionModel.getUsername(),
|
||||
suggestionType == SuggestionType.TYPE_LOCATION ? suggestionModel.getUsername() : suggestionModel.getName(),
|
||||
suggestionType,
|
||||
suggestionModel.getProfilePic(),
|
||||
suggestionModel.isVerified()};
|
||||
if (!searchHash && !searchUser) cursor.addRow(objects);
|
||||
else {
|
||||
final boolean isCurrHash = suggestionType == SuggestionType.TYPE_HASHTAG;
|
||||
if (searchHash && isCurrHash || !searchHash && !isCurrHash)
|
||||
Object[] objects = null;
|
||||
if (suggestionModel.getUser() != null)
|
||||
objects = new Object[]{
|
||||
suggestionModel.getPosition(),
|
||||
suggestionModel.getUser().getUsername(),
|
||||
suggestionModel.getUser().getFullName(),
|
||||
SuggestionType.TYPE_USER,
|
||||
suggestionModel.getUser().getUsername(),
|
||||
suggestionModel.getUser().getProfilePicUrl(),
|
||||
suggestionModel.getUser().isVerified()};
|
||||
else if (suggestionModel.getHashtag() != null)
|
||||
objects = new Object[]{
|
||||
suggestionModel.getPosition(),
|
||||
suggestionModel.getHashtag().getName(),
|
||||
suggestionModel.getHashtag().getSubtitle(),
|
||||
SuggestionType.TYPE_HASHTAG,
|
||||
suggestionModel.getHashtag().getName(),
|
||||
"res:/" + R.drawable.ic_hashtag,
|
||||
false};
|
||||
else if (suggestionModel.getPlace() != null)
|
||||
objects = new Object[]{
|
||||
suggestionModel.getPosition(),
|
||||
suggestionModel.getPlace().getTitle(),
|
||||
suggestionModel.getPlace().getSubtitle(),
|
||||
SuggestionType.TYPE_LOCATION,
|
||||
suggestionModel.getPlace().getLocation().getPk(),
|
||||
"res:/" + R.drawable.ic_location,
|
||||
false};
|
||||
cursor.addRow(objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
suggestionAdapter.changeCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<SearchResponse> call,
|
||||
Throwable t) {
|
||||
if (!call.isCanceled() && t != null)
|
||||
Log.e(TAG, "Exception on search:", t);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable runnable = () -> {
|
||||
@ -404,17 +442,19 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
if (searchAutoComplete != null) {
|
||||
searchAutoComplete.setThreshold(1);
|
||||
}
|
||||
prevSuggestionAsync = new SuggestionsFetcher(fetchListener).executeOnExecutor(
|
||||
AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
prevSuggestionAsync = searchService.search(isLoggedIn,
|
||||
searchUser || searchHash ? currentSearchQuery.substring(1)
|
||||
: currentSearchQuery);
|
||||
: currentSearchQuery,
|
||||
searchUser ? "user" : (searchHash ? "hashtag" : "blended"));
|
||||
suggestionAdapter.changeCursor(null);
|
||||
prevSuggestionAsync.enqueue(cb);
|
||||
}
|
||||
};
|
||||
|
||||
private void cancelSuggestionsAsync() {
|
||||
if (prevSuggestionAsync != null)
|
||||
try {
|
||||
prevSuggestionAsync.cancel(true);
|
||||
prevSuggestionAsync.cancel();
|
||||
} catch (final Exception ignored) {}
|
||||
}
|
||||
|
||||
@ -706,7 +746,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
|
||||
final NavController navController = currentNavControllerLiveData.getValue();
|
||||
if (navController == null) return;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString("locationId", locationId);
|
||||
bundle.putLong("locationId", Long.valueOf(locationId));
|
||||
navController.navigate(R.id.action_global_locationFragment, bundle);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ import java.util.stream.Collectors;
|
||||
import awais.instagrabber.adapters.viewholder.NotificationViewHolder;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
|
||||
public final class NotificationsAdapter extends ListAdapter<Notification, NotificationViewHolder> {
|
||||
private final OnNotificationClickListener notificationClickListener;
|
||||
|
@ -35,12 +35,12 @@ public final class SuggestionsAdapter extends CursorAdapter {
|
||||
|
||||
@Override
|
||||
public void bindView(@NonNull final View view, final Context context, @NonNull final Cursor cursor) {
|
||||
// i, username, fullname, type, picUrl, verified
|
||||
// 0, 1 , 2 , 3 , 4 , 5
|
||||
// i, username, fullname, type, query, picUrl, verified
|
||||
// 0, 1 , 2 , 3 , 4 , 5 , 6
|
||||
final String fullName = cursor.getString(2);
|
||||
String username = cursor.getString(1);
|
||||
String picUrl = cursor.getString(4);
|
||||
final boolean verified = cursor.getString(5).charAt(0) == 't';
|
||||
String picUrl = cursor.getString(5);
|
||||
final boolean verified = cursor.getString(6).charAt(0) == 't';
|
||||
|
||||
final String type = cursor.getString(3);
|
||||
SuggestionType suggestionType = null;
|
||||
@ -50,22 +50,14 @@ public final class SuggestionsAdapter extends CursorAdapter {
|
||||
Log.e(TAG, "Unknown suggestion type: " + type, e);
|
||||
}
|
||||
if (suggestionType == null) return;
|
||||
final String query;
|
||||
String query = cursor.getString(4);
|
||||
switch (suggestionType) {
|
||||
case TYPE_USER:
|
||||
username = '@' + username;
|
||||
query = username;
|
||||
break;
|
||||
case TYPE_HASHTAG:
|
||||
username = '#' + username;
|
||||
query = username;
|
||||
break;
|
||||
case TYPE_LOCATION:
|
||||
query = fullName;
|
||||
picUrl = "res:/" + R.drawable.ic_location;
|
||||
break;
|
||||
default:
|
||||
return; // will never come here
|
||||
}
|
||||
|
||||
if (onSuggestionClickListener != null) {
|
||||
@ -75,12 +67,8 @@ public final class SuggestionsAdapter extends CursorAdapter {
|
||||
final ItemSuggestionBinding binding = ItemSuggestionBinding.bind(view);
|
||||
binding.isVerified.setVisibility(verified ? View.VISIBLE : View.GONE);
|
||||
binding.tvUsername.setText(username);
|
||||
if (suggestionType.equals(SuggestionType.TYPE_LOCATION)) {
|
||||
binding.tvFullName.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.tvFullName.setVisibility(View.VISIBLE);
|
||||
binding.tvFullName.setText(fullName);
|
||||
}
|
||||
binding.ivProfilePic.setImageURI(picUrl);
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,8 @@ import awais.instagrabber.R;
|
||||
import awais.instagrabber.adapters.NotificationsAdapter.OnNotificationClickListener;
|
||||
import awais.instagrabber.databinding.ItemNotificationBinding;
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
import awais.instagrabber.repositories.responses.NotificationArgs;
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
||||
|
||||
public final class NotificationViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ItemNotificationBinding binding;
|
||||
|
@ -18,7 +18,6 @@ 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;
|
||||
@ -97,7 +96,13 @@ public class DirectItemProfileViewHolder extends DirectItemViewHolder {
|
||||
if (profile == null) return;
|
||||
binding.profilePic.setImageURI(profile.getProfilePicUrl());
|
||||
binding.username.setText(profile.getUsername());
|
||||
binding.fullName.setText(profile.getFullName());
|
||||
final String fullName = profile.getFullName();
|
||||
if (!TextUtils.isEmpty(fullName)) {
|
||||
binding.fullName.setVisibility(View.VISIBLE);
|
||||
binding.fullName.setText(fullName);
|
||||
} else {
|
||||
binding.fullName.setVisibility(View.GONE);
|
||||
}
|
||||
binding.isVerified.setVisibility(profile.isVerified() ? View.VISIBLE : View.GONE);
|
||||
itemView.setOnClickListener(v -> openProfile(profile.getUsername()));
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import awais.instagrabber.repositories.responses.directmessages.DirectItemVisual
|
||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||
import awais.instagrabber.utils.NumberUtils;
|
||||
import awais.instagrabber.utils.ResponseBodyUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
||||
public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder {
|
||||
|
||||
@ -48,7 +49,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder {
|
||||
if (media == null) return;
|
||||
setExpiryInfo(visualMedia);
|
||||
setPreview(visualMedia, messageDirection);
|
||||
final boolean expired = media.getPk() == null;
|
||||
final boolean expired = TextUtils.isEmpty(media.getId());
|
||||
if (expired) return;
|
||||
itemView.setOnClickListener(v -> openMedia(media));
|
||||
/*final boolean isExpired = visualMedia == null || (mediaModel = visualMedia.getMedia()) == null ||
|
||||
@ -118,7 +119,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder {
|
||||
final RavenMediaViewMode viewMode = visualMedia.getViewMode();
|
||||
if (viewMode != RavenMediaViewMode.PERMANENT) {
|
||||
final MediaItemType mediaType = media.getMediaType();
|
||||
final boolean expired = media.getPk() == null;
|
||||
final boolean expired = TextUtils.isEmpty(media.getId());
|
||||
final int info;
|
||||
switch (mediaType) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
@ -153,7 +154,7 @@ public class DirectItemRavenMediaViewHolder extends DirectItemViewHolder {
|
||||
private void setPreview(final DirectItemVisualMedia visualMedia,
|
||||
final MessageDirection messageDirection) {
|
||||
final Media media = visualMedia.getMedia();
|
||||
final boolean expired = media.getPk() == null;
|
||||
final boolean expired = TextUtils.isEmpty(media.getId());
|
||||
if (expired) {
|
||||
binding.preview.setVisibility(View.GONE);
|
||||
binding.typeIcon.setVisibility(View.GONE);
|
||||
|
@ -1,81 +0,0 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
//import awaisomereport.LogCollector;
|
||||
|
||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class LocationFetcher extends AsyncTask<Void, Void, LocationModel> {
|
||||
private static final String TAG = "LocationFetcher";
|
||||
|
||||
private final FetchListener<LocationModel> fetchListener;
|
||||
private final long id;
|
||||
|
||||
public LocationFetcher(final long id, final FetchListener<LocationModel> fetchListener) {
|
||||
// idSlug = id + "/" + slug UPDATE: slug can be ignored tbh
|
||||
this.id = id;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected LocationModel doInBackground(final Void... voids) {
|
||||
LocationModel result = null;
|
||||
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/explore/locations/" + id + "/?__a=1")
|
||||
.openConnection();
|
||||
conn.setUseCaches(true);
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject location = new JSONObject(NetworkUtils.readFromConnection(conn)).getJSONObject("graphql")
|
||||
.getJSONObject(Constants.EXTRAS_LOCATION);
|
||||
|
||||
final JSONObject timelineMedia = location.getJSONObject("edge_location_to_media");
|
||||
// if (timelineMedia.has("edges")) {
|
||||
// final JSONArray edges = timelineMedia.getJSONArray("edges");
|
||||
// }
|
||||
result = new LocationModel(
|
||||
location.getLong(Constants.EXTRAS_ID),
|
||||
location.getString("name"),
|
||||
location.getString("blurb"),
|
||||
location.getString("website"),
|
||||
location.getString("profile_pic_url"),
|
||||
timelineMedia.getLong("count"),
|
||||
BigDecimal.valueOf(location.optDouble("lat", 0d)).toString(),
|
||||
BigDecimal.valueOf(location.optDouble("lng", 0d)).toString()
|
||||
);
|
||||
}
|
||||
|
||||
conn.disconnect();
|
||||
} catch (final Exception e) {
|
||||
// if (logCollector != null)
|
||||
// logCollector.appendException(e, LogCollector.LogFile.ASYNC_LOCATION_FETCHER, "doInBackground");
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final LocationModel result) {
|
||||
if (fetchListener != null) fetchListener.onResult(result);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import java.util.List;
|
||||
|
||||
import awais.instagrabber.customviews.helpers.PostFetcher;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||
import awais.instagrabber.webservices.GraphQLService;
|
||||
@ -14,12 +14,12 @@ import awais.instagrabber.webservices.ServiceCallback;
|
||||
public class LocationPostFetchService implements PostFetcher.PostFetchService {
|
||||
private final LocationService locationService;
|
||||
private final GraphQLService graphQLService;
|
||||
private final LocationModel locationModel;
|
||||
private final Location locationModel;
|
||||
private String nextMaxId;
|
||||
private boolean moreAvailable;
|
||||
private final boolean isLoggedIn;
|
||||
|
||||
public LocationPostFetchService(final LocationModel locationModel, final boolean isLoggedIn) {
|
||||
public LocationPostFetchService(final Location locationModel, final boolean isLoggedIn) {
|
||||
this.locationModel = locationModel;
|
||||
this.isLoggedIn = isLoggedIn;
|
||||
locationService = isLoggedIn ? LocationService.getInstance() : null;
|
||||
@ -47,8 +47,8 @@ public class LocationPostFetchService implements PostFetcher.PostFetchService {
|
||||
}
|
||||
}
|
||||
};
|
||||
if (isLoggedIn) locationService.fetchPosts(locationModel.getId(), nextMaxId, cb);
|
||||
else graphQLService.fetchLocationPosts(locationModel.getId(), nextMaxId, cb);
|
||||
if (isLoggedIn) locationService.fetchPosts(locationModel.getPk(), nextMaxId, cb);
|
||||
else graphQLService.fetchLocationPosts(locationModel.getPk(), nextMaxId, cb);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,113 +0,0 @@
|
||||
package awais.instagrabber.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.SuggestionModel;
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.NetworkUtils;
|
||||
import awais.instagrabber.utils.UrlEncoder;
|
||||
|
||||
public final class SuggestionsFetcher extends AsyncTask<String, String, SuggestionModel[]> {
|
||||
private final FetchListener<SuggestionModel[]> fetchListener;
|
||||
|
||||
public SuggestionsFetcher(final FetchListener<SuggestionModel[]> fetchListener) {
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
if (fetchListener != null) fetchListener.doBefore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SuggestionModel[] doInBackground(final String... params) {
|
||||
SuggestionModel[] result = null;
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/web/search/topsearch/?context=blended&count=50&query="
|
||||
+ UrlEncoder.encodeUrl(params[0])).openConnection();
|
||||
conn.setUseCaches(false);
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
final JSONObject jsonObject = new JSONObject(NetworkUtils.readFromConnection(conn));
|
||||
conn.disconnect();
|
||||
|
||||
final JSONArray usersArray = jsonObject.getJSONArray("users");
|
||||
final JSONArray hashtagsArray = jsonObject.getJSONArray("hashtags");
|
||||
final JSONArray placesArray = jsonObject.getJSONArray("places");
|
||||
|
||||
final int usersLen = usersArray.length();
|
||||
final int hashtagsLen = hashtagsArray.length();
|
||||
final int placesLen = placesArray.length();
|
||||
|
||||
final ArrayList<SuggestionModel> suggestionModels = new ArrayList<>(usersLen + hashtagsLen);
|
||||
for (int i = 0; i < hashtagsLen; i++) {
|
||||
final JSONObject hashtagsArrayJSONObject = hashtagsArray.getJSONObject(i);
|
||||
|
||||
final JSONObject hashtag = hashtagsArrayJSONObject.getJSONObject("hashtag");
|
||||
|
||||
suggestionModels.add(new SuggestionModel(false,
|
||||
hashtag.getString(Constants.EXTRAS_NAME),
|
||||
null,
|
||||
hashtag.optString("profile_pic_url", Constants.DEFAULT_HASH_TAG_PIC),
|
||||
SuggestionType.TYPE_HASHTAG,
|
||||
hashtagsArrayJSONObject.optInt("position", suggestionModels.size() - 1)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < placesLen; i++) {
|
||||
final JSONObject placesArrayJSONObject = placesArray.getJSONObject(i);
|
||||
|
||||
final JSONObject place = placesArrayJSONObject.getJSONObject("place");
|
||||
|
||||
// name
|
||||
suggestionModels.add(new SuggestionModel(false,
|
||||
place.getJSONObject("location").getString("pk"), // +"/"+place.getString("slug"),
|
||||
place.getString("title"),
|
||||
place.optString("profile_pic_url"),
|
||||
SuggestionType.TYPE_LOCATION,
|
||||
placesArrayJSONObject.optInt("position", suggestionModels.size() - 1)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < usersLen; i++) {
|
||||
final JSONObject usersArrayJSONObject = usersArray.getJSONObject(i);
|
||||
|
||||
final JSONObject user = usersArrayJSONObject.getJSONObject(Constants.EXTRAS_USER);
|
||||
|
||||
suggestionModels.add(new SuggestionModel(user.getBoolean("is_verified"),
|
||||
user.getString(Constants.EXTRAS_USERNAME),
|
||||
user.getString("full_name"),
|
||||
user.getString("profile_pic_url"),
|
||||
SuggestionType.TYPE_USER,
|
||||
usersArrayJSONObject.optInt("position", suggestionModels.size() - 1)));
|
||||
}
|
||||
|
||||
suggestionModels.trimToSize();
|
||||
|
||||
Collections.sort(suggestionModels);
|
||||
|
||||
result = suggestionModels.toArray(new SuggestionModel[0]);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
if (BuildConfig.DEBUG && !(e instanceof InterruptedIOException)) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final SuggestionModel[] result) {
|
||||
if (fetchListener != null) fetchListener.onResult(result);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package awais.instagrabber.customviews.masoudss_waveform;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
@ -50,8 +51,21 @@ public final class WaveformSeekBar extends View {
|
||||
|
||||
public WaveformSeekBar(final Context context, @Nullable final AttributeSet attrs, final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
this.waveBackgroundColor = context.getResources().getColor(R.color.white);
|
||||
this.waveProgressColor = context.getResources().getColor(R.color.blue_800);
|
||||
final TypedArray a = context.getTheme().obtainStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.WaveformSeekBar,
|
||||
0,
|
||||
0);
|
||||
final int backgroundColor;
|
||||
final int progressColor;
|
||||
try {
|
||||
backgroundColor = a.getResourceId(R.styleable.WaveformSeekBar_waveformBackgroundColor, R.color.white);
|
||||
progressColor = a.getResourceId(R.styleable.WaveformSeekBar_waveformProgressColor, R.color.blue_800);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
this.waveBackgroundColor = context.getResources().getColor(backgroundColor);
|
||||
this.waveProgressColor = context.getResources().getColor(progressColor);
|
||||
}
|
||||
|
||||
private float getSampleMax() {
|
||||
|
@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
@ -17,6 +18,9 @@ public class ConfirmDialogFragment extends DialogFragment {
|
||||
private Context context;
|
||||
private ConfirmDialogFragmentCallback callback;
|
||||
|
||||
private final int defaultPositiveButtonText = R.string.ok;
|
||||
// private final int defaultNegativeButtonText = R.string.cancel;
|
||||
|
||||
@NonNull
|
||||
public static ConfirmDialogFragment newInstance(final int requestCode,
|
||||
@StringRes final int title,
|
||||
@ -26,11 +30,21 @@ public class ConfirmDialogFragment extends DialogFragment {
|
||||
@StringRes final int neutralText) {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("requestCode", requestCode);
|
||||
if (title != 0) {
|
||||
args.putInt("title", title);
|
||||
}
|
||||
if (message != 0) {
|
||||
args.putInt("message", message);
|
||||
}
|
||||
if (positiveText != 0) {
|
||||
args.putInt("positive", positiveText);
|
||||
}
|
||||
if (negativeText != 0) {
|
||||
args.putInt("negative", negativeText);
|
||||
}
|
||||
if (neutralText != 0) {
|
||||
args.putInt("neutral", neutralText);
|
||||
}
|
||||
ConfirmDialogFragment fragment = new ConfirmDialogFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
@ -41,10 +55,9 @@ public class ConfirmDialogFragment extends DialogFragment {
|
||||
@Override
|
||||
public void onAttach(@NonNull final Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
callback = (ConfirmDialogFragmentCallback) getParentFragment();
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException("Calling fragment must implement ConfirmDialogFragmentCallback interface");
|
||||
final Fragment parentFragment = getParentFragment();
|
||||
if (parentFragment instanceof ConfirmDialogFragmentCallback) {
|
||||
callback = (ConfirmDialogFragmentCallback) parentFragment;
|
||||
}
|
||||
this.context = context;
|
||||
}
|
||||
@ -53,38 +66,42 @@ public class ConfirmDialogFragment extends DialogFragment {
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
||||
final Bundle arguments = getArguments();
|
||||
int title = -1;
|
||||
int message = -1;
|
||||
int positiveButtonText = R.string.ok;
|
||||
int negativeButtonText = R.string.cancel;
|
||||
int neutralButtonText = -1;
|
||||
int title = 0;
|
||||
int message = 0;
|
||||
int neutralButtonText = 0;
|
||||
int negativeButtonText = 0;
|
||||
|
||||
final int positiveButtonText;
|
||||
final int requestCode;
|
||||
if (arguments != null) {
|
||||
title = arguments.getInt("title", -1);
|
||||
message = arguments.getInt("message", -1);
|
||||
positiveButtonText = arguments.getInt("positive", R.string.ok);
|
||||
negativeButtonText = arguments.getInt("negative", R.string.cancel);
|
||||
neutralButtonText = arguments.getInt("neutral", -1);
|
||||
title = arguments.getInt("title", 0);
|
||||
message = arguments.getInt("message", 0);
|
||||
positiveButtonText = arguments.getInt("positive", defaultPositiveButtonText);
|
||||
negativeButtonText = arguments.getInt("negative", 0);
|
||||
neutralButtonText = arguments.getInt("neutral", 0);
|
||||
requestCode = arguments.getInt("requestCode", 0);
|
||||
} else {
|
||||
requestCode = 0;
|
||||
positiveButtonText = defaultPositiveButtonText;
|
||||
}
|
||||
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context)
|
||||
.setPositiveButton(positiveButtonText, (d, w) -> {
|
||||
if (callback == null) return;
|
||||
callback.onPositiveButtonClicked(requestCode);
|
||||
})
|
||||
.setNegativeButton(negativeButtonText, (dialog, which) -> {
|
||||
});
|
||||
if (title != 0) {
|
||||
builder.setTitle(title);
|
||||
}
|
||||
if (message != 0) {
|
||||
builder.setMessage(message);
|
||||
}
|
||||
if (negativeButtonText != 0) {
|
||||
builder.setNegativeButton(negativeButtonText, (dialog, which) -> {
|
||||
if (callback == null) return;
|
||||
callback.onNegativeButtonClicked(requestCode);
|
||||
});
|
||||
if (title > 0) {
|
||||
builder.setTitle(title);
|
||||
}
|
||||
if (message > 0) {
|
||||
builder.setMessage(message);
|
||||
}
|
||||
if (neutralButtonText > 0) {
|
||||
if (neutralButtonText != 0) {
|
||||
builder.setNeutralButton(neutralButtonText, (dialog, which) -> {
|
||||
if (callback == null) return;
|
||||
callback.onNeutralButtonClicked(requestCode);
|
||||
|
@ -292,7 +292,7 @@ public class CollectionPostsFragment extends Fragment implements SwipeRefreshLay
|
||||
else if (item.getItemId() == R.id.delete) {
|
||||
final Context context = getContext();
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.edit_collection)
|
||||
.setTitle(R.string.delete_collection)
|
||||
.setMessage(R.string.delete_collection_note)
|
||||
.setPositiveButton(R.string.confirm, (d, w) -> {
|
||||
collectionService.deleteCollection(
|
||||
|
@ -2,7 +2,6 @@ package awais.instagrabber.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@ -57,7 +56,6 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
|
||||
private FollowAdapter adapter;
|
||||
private View.OnClickListener clickListener;
|
||||
private FragmentFollowersViewerBinding binding;
|
||||
private AsyncTask<Void, Void, FollowModel[]> currentlyExecuting;
|
||||
private SwipeRefreshLayout root;
|
||||
private FriendshipService friendshipService;
|
||||
private AppCompatActivity fragmentActivity;
|
||||
|
@ -3,7 +3,6 @@ package awais.instagrabber.fragments;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.SpannableStringBuilder;
|
||||
@ -95,7 +94,6 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
private Hashtag hashtagModel = null;
|
||||
private ActionMode actionMode;
|
||||
private StoriesService storiesService;
|
||||
private AsyncTask<?, ?, ?> currentlyExecuting;
|
||||
private boolean isLoggedIn;
|
||||
private TagsService tagsService;
|
||||
private GraphQLService graphQLService;
|
||||
@ -474,7 +472,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
hashtag,
|
||||
FavoriteType.HASHTAG,
|
||||
hashtagModel.getName(),
|
||||
hashtagModel.getProfilePicUrl(),
|
||||
"res:/" + R.drawable.ic_hashtag,
|
||||
result.getDateAdded()
|
||||
), new RepositoryCallback<Void>() {
|
||||
@Override
|
||||
@ -518,7 +516,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
hashtag,
|
||||
FavoriteType.HASHTAG,
|
||||
hashtagModel.getName(),
|
||||
hashtagModel.getProfilePicUrl(),
|
||||
"res:/" + R.drawable.ic_hashtag,
|
||||
new Date()
|
||||
), new RepositoryCallback<Void>() {
|
||||
@Override
|
||||
@ -533,7 +531,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
});
|
||||
}
|
||||
}));
|
||||
hashtagDetailsBinding.mainHashtagImage.setImageURI(hashtagModel.getProfilePicUrl());
|
||||
hashtagDetailsBinding.mainHashtagImage.setImageURI("res:/" + R.drawable.ic_hashtag);
|
||||
final String postCount = String.valueOf(hashtagModel.getMediaCount());
|
||||
final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline,
|
||||
hashtagModel.getMediaCount() > 2000000000L
|
||||
|
@ -3,14 +3,9 @@ package awais.instagrabber.fragments;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.RelativeSizeSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
@ -45,7 +40,6 @@ import java.util.Set;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.activities.MainActivity;
|
||||
import awais.instagrabber.adapters.FeedAdapterV2;
|
||||
import awais.instagrabber.asyncs.LocationFetcher;
|
||||
import awais.instagrabber.asyncs.LocationPostFetchService;
|
||||
import awais.instagrabber.asyncs.PostFetcher;
|
||||
import awais.instagrabber.customviews.PrimaryActionModeCallback;
|
||||
@ -56,23 +50,24 @@ import awais.instagrabber.db.entities.Favorite;
|
||||
import awais.instagrabber.db.repositories.FavoriteRepository;
|
||||
import awais.instagrabber.db.repositories.RepositoryCallback;
|
||||
import awais.instagrabber.dialogs.PostsLayoutPreferencesDialogFragment;
|
||||
import awais.instagrabber.models.LocationModel;
|
||||
import awais.instagrabber.models.PostsLayoutPreferences;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.enums.FavoriteType;
|
||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.DownloadUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awais.instagrabber.webservices.GraphQLService;
|
||||
import awais.instagrabber.webservices.LocationService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
import awais.instagrabber.webservices.StoriesService;
|
||||
//import awaisomereport.LogCollector;
|
||||
|
||||
import static androidx.core.content.PermissionChecker.checkSelfPermission;
|
||||
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
|
||||
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
|
||||
//import static awais.instagrabber.utils.Utils.logCollector;
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
@ -89,10 +84,11 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
private boolean hasStories = false;
|
||||
private boolean opening = false;
|
||||
private long locationId;
|
||||
private LocationModel locationModel;
|
||||
private Location locationModel;
|
||||
private ActionMode actionMode;
|
||||
private StoriesService storiesService;
|
||||
private AsyncTask<?, ?, ?> currentlyExecuting;
|
||||
private GraphQLService graphQLService;
|
||||
private LocationService locationService;
|
||||
private boolean isLoggedIn;
|
||||
private boolean storiesFetching;
|
||||
private Set<Media> selectedFeedModels;
|
||||
@ -265,12 +261,29 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
}
|
||||
}
|
||||
};
|
||||
private final ServiceCallback<Location> cb = new ServiceCallback<Location>() {
|
||||
@Override
|
||||
public void onSuccess(final Location result) {
|
||||
locationModel = result;
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
setupLocationDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(final Throwable t) {
|
||||
setupLocationDetails();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
fragmentActivity = (MainActivity) requireActivity();
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
||||
locationService = isLoggedIn ? LocationService.getInstance() : null;
|
||||
storiesService = StoriesService.getInstance(null, 0L, null);
|
||||
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@ -354,8 +367,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
|
||||
private void init() {
|
||||
if (getArguments() == null) return;
|
||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
|
||||
final LocationFragmentArgs fragmentArgs = LocationFragmentArgs.fromBundle(getArguments());
|
||||
locationId = fragmentArgs.getLocationId();
|
||||
locationDetailsBinding.favChip.setVisibility(View.GONE);
|
||||
@ -377,42 +388,38 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
}
|
||||
|
||||
private void fetchLocationModel() {
|
||||
stopCurrentExecutor();
|
||||
binding.swipeRefreshLayout.setRefreshing(true);
|
||||
currentlyExecuting = new LocationFetcher(locationId, result -> {
|
||||
locationModel = result;
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
if (locationModel == null) {
|
||||
final Context context = getContext();
|
||||
if (context == null) return;
|
||||
Toast.makeText(context, R.string.error_loading_location, Toast.LENGTH_SHORT).show();
|
||||
binding.swipeRefreshLayout.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
setTitle();
|
||||
setupLocationDetails();
|
||||
setupPosts();
|
||||
fetchStories();
|
||||
// fetchPosts();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
if (isLoggedIn) locationService.fetch(locationId, cb);
|
||||
else graphQLService.fetchLocation(locationId, cb);
|
||||
}
|
||||
|
||||
private void setupLocationDetails() {
|
||||
final long locationId = locationModel.getId();
|
||||
if (locationModel == null) {
|
||||
try {
|
||||
Toast.makeText(getContext(), R.string.error_loading_location, Toast.LENGTH_SHORT).show();
|
||||
binding.swipeRefreshLayout.setEnabled(false);
|
||||
}
|
||||
catch (Exception ignored) {}
|
||||
return;
|
||||
}
|
||||
setTitle();
|
||||
setupPosts();
|
||||
fetchStories();
|
||||
final long locationId = locationModel.getPk();
|
||||
// binding.swipeRefreshLayout.setRefreshing(true);
|
||||
locationDetailsBinding.mainLocationImage.setImageURI(locationModel.getSdProfilePic());
|
||||
final String postCount = String.valueOf(locationModel.getPostCount());
|
||||
final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline,
|
||||
locationModel.getPostCount() > 2000000000L
|
||||
? 2000000000
|
||||
: locationModel.getPostCount().intValue(),
|
||||
postCount));
|
||||
span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
|
||||
span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
|
||||
locationDetailsBinding.mainLocPostCount.setText(span);
|
||||
locationDetailsBinding.mainLocPostCount.setVisibility(View.VISIBLE);
|
||||
locationDetailsBinding.mainLocationImage.setImageURI("res:/" + R.drawable.ic_location);
|
||||
// final String postCount = String.valueOf(locationModel.getCount());
|
||||
// final SpannableStringBuilder span = new SpannableStringBuilder(getResources().getQuantityString(R.plurals.main_posts_count_inline,
|
||||
// locationModel.getPostCount() > 2000000000L
|
||||
// ? 2000000000
|
||||
// : locationModel.getPostCount().intValue(),
|
||||
// postCount));
|
||||
// span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
|
||||
// span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
|
||||
// locationDetailsBinding.mainLocPostCount.setText(span);
|
||||
// locationDetailsBinding.mainLocPostCount.setVisibility(View.VISIBLE);
|
||||
locationDetailsBinding.locationFullName.setText(locationModel.getName());
|
||||
CharSequence biography = locationModel.getBio();
|
||||
CharSequence biography = locationModel.getAddress() + "\n" + locationModel.getCity();
|
||||
// binding.locationBiography.setCaptionIsExpandable(true);
|
||||
// binding.locationBiography.setCaptionIsExpanded(true);
|
||||
|
||||
@ -423,22 +430,22 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
} else {
|
||||
locationDetailsBinding.locationBiography.setVisibility(View.VISIBLE);
|
||||
locationDetailsBinding.locationBiography.setText(biography);
|
||||
locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> {
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
final Bundle bundle = new Bundle();
|
||||
final String originalText = autoLinkItem.getOriginalText().trim();
|
||||
bundle.putString(ARG_HASHTAG, originalText);
|
||||
navController.navigate(R.id.action_global_hashTagFragment, bundle);
|
||||
});
|
||||
locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> {
|
||||
final String originalText = autoLinkItem.getOriginalText().trim();
|
||||
navigateToProfile(originalText);
|
||||
});
|
||||
locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(context,
|
||||
autoLinkItem.getOriginalText()
|
||||
.trim()));
|
||||
locationDetailsBinding.locationBiography
|
||||
.addOnURLClickListener(autoLinkItem -> Utils.openURL(context, autoLinkItem.getOriginalText().trim()));
|
||||
// locationDetailsBinding.locationBiography.addOnHashtagListener(autoLinkItem -> {
|
||||
// final NavController navController = NavHostFragment.findNavController(this);
|
||||
// final Bundle bundle = new Bundle();
|
||||
// final String originalText = autoLinkItem.getOriginalText().trim();
|
||||
// bundle.putString(ARG_HASHTAG, originalText);
|
||||
// navController.navigate(R.id.action_global_hashTagFragment, bundle);
|
||||
// });
|
||||
// locationDetailsBinding.locationBiography.addOnMentionClickListener(autoLinkItem -> {
|
||||
// final String originalText = autoLinkItem.getOriginalText().trim();
|
||||
// navigateToProfile(originalText);
|
||||
// });
|
||||
// locationDetailsBinding.locationBiography.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(context,
|
||||
// autoLinkItem.getOriginalText()
|
||||
// .trim()));
|
||||
// locationDetailsBinding.locationBiography
|
||||
// .addOnURLClickListener(autoLinkItem -> Utils.openURL(context, autoLinkItem.getOriginalText().trim()));
|
||||
locationDetailsBinding.locationBiography.setOnLongClickListener(v -> {
|
||||
Utils.copyText(context, biography);
|
||||
return true;
|
||||
@ -457,16 +464,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
locationDetailsBinding.btnMap.setOnClickListener(null);
|
||||
}
|
||||
|
||||
final String url = locationModel.getUrl();
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
locationDetailsBinding.locationUrl.setVisibility(View.GONE);
|
||||
} else if (!url.startsWith("http")) {
|
||||
locationDetailsBinding.locationUrl.setVisibility(View.VISIBLE);
|
||||
locationDetailsBinding.locationUrl.setText(TextUtils.getSpannableUrl("http://" + url));
|
||||
} else {
|
||||
locationDetailsBinding.locationUrl.setVisibility(View.VISIBLE);
|
||||
locationDetailsBinding.locationUrl.setText(TextUtils.getSpannableUrl(url));
|
||||
}
|
||||
final FavoriteDataSource dataSource = FavoriteDataSource.getInstance(context);
|
||||
final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(dataSource);
|
||||
locationDetailsBinding.favChip.setVisibility(View.VISIBLE);
|
||||
@ -481,7 +478,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
String.valueOf(locationId),
|
||||
FavoriteType.LOCATION,
|
||||
locationModel.getName(),
|
||||
locationModel.getSdProfilePic(),
|
||||
"res:/" + R.drawable.ic_location,
|
||||
result.getDateAdded()
|
||||
), new RepositoryCallback<Void>() {
|
||||
@Override
|
||||
@ -523,7 +520,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
String.valueOf(locationId),
|
||||
FavoriteType.LOCATION,
|
||||
locationModel.getName(),
|
||||
locationModel.getSdProfilePic(),
|
||||
"res:/" + R.drawable.ic_location,
|
||||
new Date()
|
||||
), new RepositoryCallback<Void>() {
|
||||
@Override
|
||||
@ -581,18 +578,6 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
|
||||
}
|
||||
}
|
||||
|
||||
private void stopCurrentExecutor() {
|
||||
if (currentlyExecuting != null) {
|
||||
try {
|
||||
currentlyExecuting.cancel(true);
|
||||
} catch (final Exception e) {
|
||||
// if (logCollector != null) logCollector.appendException(
|
||||
// e, LogCollector.LogFile.MAIN_HELPER, "stopCurrentExecutor");
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setTitle() {
|
||||
final ActionBar actionBar = fragmentActivity.getSupportActionBar();
|
||||
if (actionBar != null && locationModel != null) {
|
||||
|
@ -2,7 +2,6 @@ package awais.instagrabber.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
@ -37,9 +36,9 @@ import awais.instagrabber.models.enums.NotificationType;
|
||||
import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
||||
import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
import awais.instagrabber.repositories.responses.NotificationArgs;
|
||||
import awais.instagrabber.repositories.responses.NotificationImage;
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationImage;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
@ -79,7 +79,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
|
||||
public void onHighlightClick(final HighlightModel model, final int position) {
|
||||
if (model == null) return;
|
||||
final NavDirections action = StoryListViewerFragmentDirections
|
||||
.actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forStoryArchive(position));
|
||||
.actionStoryListFragmentToStoryViewerFragment(StoryViewerOptions.forStoryArchive(model.getId()));
|
||||
NavHostFragment.findNavController(StoryListViewerFragment.this).navigate(action);
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
@ -304,11 +306,18 @@ public class StoryViewerFragment extends Fragment {
|
||||
// isNotification = fragmentArgs.getIsNotification();
|
||||
final Type type = options.getType();
|
||||
if (currentFeedStoryIndex >= 0) {
|
||||
viewModel = type == Type.HIGHLIGHT
|
||||
? type == Type.STORY_ARCHIVE
|
||||
? new ViewModelProvider(fragmentActivity).get(ArchivesViewModel.class)
|
||||
: new ViewModelProvider(fragmentActivity).get(HighlightsViewModel.class)
|
||||
: new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class);
|
||||
switch (type) {
|
||||
case HIGHLIGHT:
|
||||
viewModel = new ViewModelProvider(fragmentActivity).get(HighlightsViewModel.class);
|
||||
break;
|
||||
case STORY_ARCHIVE:
|
||||
viewModel = new ViewModelProvider(fragmentActivity).get(ArchivesViewModel.class);
|
||||
break;
|
||||
default:
|
||||
case FEED_STORY_POSITION:
|
||||
viewModel = new ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
setupStories();
|
||||
}
|
||||
@ -728,9 +737,9 @@ public class StoryViewerFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
final HighlightModel model = models.get(currentFeedStoryIndex);
|
||||
currentStoryMediaId = model.getId();
|
||||
currentStoryMediaId = parseStoryMediaId(model.getId());
|
||||
currentStoryUsername = model.getTitle();
|
||||
fetchOptions = StoryViewerOptions.forUser(Long.parseLong(currentStoryMediaId), currentStoryUsername);
|
||||
fetchOptions = StoryViewerOptions.forStoryArchive(model.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1139,4 +1148,20 @@ public class StoryViewerFragment extends Fragment {
|
||||
resetView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Story's media ID. For user stories this is a number, but for archive stories
|
||||
* this is "archiveDay:" plus a number.
|
||||
*/
|
||||
private static String parseStoryMediaId(String rawId) {
|
||||
final String regex = "(?:archiveDay:)?(.+)";
|
||||
final Pattern pattern = Pattern.compile(regex);
|
||||
final Matcher matcher = pattern.matcher(rawId);
|
||||
|
||||
if (matcher.matches() && matcher.groupCount() >= 1) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
return rawId;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@ -104,6 +105,11 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver();
|
||||
isPendingRequestTotalBadgeAttached = false;
|
||||
if (pendingRequestTotalBadgeDrawable != null) {
|
||||
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
|
||||
pendingRequestTotalBadgeDrawable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -124,21 +130,13 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
unregisterReceiver();
|
||||
isPendingRequestTotalBadgeAttached = false;
|
||||
if (pendingRequestTotalBadgeDrawable != null) {
|
||||
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
|
||||
pendingRequestTotalBadgeDrawable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
pendingRequestsMenuItem = menu.add(Menu.NONE, R.id.pending_requests, Menu.NONE, "Pending requests");
|
||||
pendingRequestsMenuItem.setIcon(R.drawable.ic_account_clock_24)
|
||||
.setVisible(false)
|
||||
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
attachPendingRequestsBadge(viewModel.getPendingRequestsTotal().getValue());
|
||||
inflater.inflate(R.menu.dm_inbox_menu, menu);
|
||||
pendingRequestsMenuItem = menu.findItem(R.id.pending_requests);
|
||||
pendingRequestsMenuItem.setVisible(isPendingRequestTotalBadgeAttached);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -213,7 +211,16 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
|
||||
|
||||
@SuppressLint("UnsafeExperimentalUsageError")
|
||||
private void attachPendingRequestsBadge(@Nullable final Integer count) {
|
||||
if (pendingRequestsMenuItem == null) return;
|
||||
if (pendingRequestsMenuItem == null) {
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
attachPendingRequestsBadge(count);
|
||||
}
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
if (pendingRequestTotalBadgeDrawable == null) {
|
||||
final Context context = getContext();
|
||||
if (context == null) return;
|
||||
|
@ -140,6 +140,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
viewModel.isViewerAdmin().observe(getViewLifecycleOwner(), this::setApprovalRelatedUI);
|
||||
viewModel.getApprovalRequiredToJoin().observe(getViewLifecycleOwner(), required -> binding.approvalRequired.setChecked(required));
|
||||
viewModel.getPendingRequests().observe(getViewLifecycleOwner(), this::setPendingRequests);
|
||||
viewModel.isGroup().observe(getViewLifecycleOwner(), this::setupSettings);
|
||||
final NavController navController = NavHostFragment.findNavController(this);
|
||||
final NavBackStackEntry backStackEntry = navController.getCurrentBackStackEntry();
|
||||
if (backStackEntry != null) {
|
||||
@ -186,7 +187,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
R.string.admin_approval_required_description,
|
||||
R.string.ok,
|
||||
R.string.cancel,
|
||||
-1
|
||||
0
|
||||
);
|
||||
confirmDialogFragment.show(getChildFragmentManager(), "approval_required_dialog");
|
||||
return;
|
||||
@ -207,13 +208,11 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setupSettings();
|
||||
// setupSettings();
|
||||
setupMembers();
|
||||
}
|
||||
|
||||
private void setupSettings() {
|
||||
Boolean isGroup = viewModel.isGroup().getValue();
|
||||
if (isGroup == null) isGroup = false;
|
||||
private void setupSettings(final boolean isGroup) {
|
||||
binding.groupSettings.setVisibility(isGroup ? View.VISIBLE : View.GONE);
|
||||
binding.muteMessagesLabel.setOnClickListener(v -> binding.muteMessages.toggle());
|
||||
binding.muteMessages.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
@ -272,10 +271,10 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
final ConfirmDialogFragment confirmDialogFragment = ConfirmDialogFragment.newInstance(
|
||||
LEAVE_THREAD_REQUEST_CODE,
|
||||
R.string.dms_action_leave_question,
|
||||
-1,
|
||||
0,
|
||||
R.string.yes,
|
||||
R.string.no,
|
||||
-1
|
||||
0
|
||||
);
|
||||
confirmDialogFragment.show(getChildFragmentManager(), "leave_thread_confirmation_dialog");
|
||||
});
|
||||
@ -290,7 +289,7 @@ public class DirectMessageSettingsFragment extends Fragment implements ConfirmDi
|
||||
R.string.dms_action_end_description,
|
||||
R.string.yes,
|
||||
R.string.no,
|
||||
-1
|
||||
0
|
||||
);
|
||||
confirmDialogFragment.show(getChildFragmentManager(), "end_thread_confirmation_dialog");
|
||||
});
|
||||
|
@ -1227,7 +1227,10 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
if (!isEmojiPickerShown) {
|
||||
binding.emojiPicker.setAlpha(0);
|
||||
}
|
||||
imm.showSoftInput(binding.input, InputMethodManager.SHOW_IMPLICIT);
|
||||
final boolean shown = imm.showSoftInput(binding.input, InputMethodManager.SHOW_IMPLICIT);
|
||||
if (!shown) {
|
||||
Log.e(TAG, "showKeyboard: System did not display the keyboard");
|
||||
}
|
||||
if (!isEmojiPickerShown) {
|
||||
animatePan(keyboardHeight);
|
||||
}
|
||||
@ -1328,95 +1331,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
}
|
||||
}
|
||||
|
||||
// private void sendText(final String text, final String itemId, final boolean delete) {
|
||||
// DirectThreadBroadcaster.TextBroadcastOptions textOptions = null;
|
||||
// DirectThreadBroadcaster.ReactionBroadcastOptions reactionOptions = null;
|
||||
// if (text != null) {
|
||||
// try {
|
||||
// textOptions = new DirectThreadBroadcaster.TextBroadcastOptions(text);
|
||||
// } catch (UnsupportedEncodingException e) {
|
||||
// Log.e(TAG, "Error", e);
|
||||
// return;
|
||||
// }
|
||||
// } else {
|
||||
// reactionOptions = new DirectThreadBroadcaster.ReactionBroadcastOptions(itemId, delete);
|
||||
// }
|
||||
// broadcast(text != null ? textOptions : reactionOptions, result -> {
|
||||
// final Context context = getContext();
|
||||
// if (context == null) return;
|
||||
// if (result == null || result.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
// Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
// return;
|
||||
// }
|
||||
// if (text != null) {
|
||||
// // binding.commentText.setText("");
|
||||
// } else {
|
||||
// // final View viewWithTag = binding.messageList.findViewWithTag(directItemModel);
|
||||
// // if (viewWithTag != null) {
|
||||
// // final ViewParent dim = viewWithTag.getParent();
|
||||
// // if (dim instanceof View) {
|
||||
// // final View dimView = (View) dim;
|
||||
// // final View likedContainer = dimView.findViewById(R.id.liked_container);
|
||||
// // if (likedContainer != null) {
|
||||
// // likedContainer.setVisibility(delete ? View.GONE : View.VISIBLE);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // directItemModel.setLiked();
|
||||
// }
|
||||
// context.sendBroadcast(new Intent(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM));
|
||||
// hasSentSomething = true;
|
||||
// // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener)
|
||||
// // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
// });
|
||||
// }
|
||||
|
||||
// private void sendImage(final Uri imageUri) {
|
||||
// final Context context = getContext();
|
||||
// if (context == null) return;
|
||||
// try (InputStream inputStream = context.getContentResolver().openInputStream(imageUri)) {
|
||||
// final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
|
||||
// Toast.makeText(context, R.string.uploading, Toast.LENGTH_SHORT).show();
|
||||
// // Upload Image
|
||||
// final ImageUploader imageUploader = new ImageUploader();
|
||||
// imageUploader.setOnTaskCompleteListener(response -> {
|
||||
// if (response == null || response.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
// Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
// if (response != null && response.getResponse() != null) {
|
||||
// Log.e(TAG, response.getResponse().toString());
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// final JSONObject responseJson = response.getResponse();
|
||||
// try {
|
||||
// final String uploadId = responseJson.getString("upload_id");
|
||||
// // Broadcast
|
||||
// final DirectThreadBroadcaster.ImageBroadcastOptions options = new DirectThreadBroadcaster.ImageBroadcastOptions(true, uploadId);
|
||||
// hasSentSomething = true;
|
||||
// broadcast(options,
|
||||
// broadcastResponse -> {
|
||||
// // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener)
|
||||
// // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
// });
|
||||
// } catch (JSONException e) {
|
||||
// Log.e(TAG, "Error parsing json response", e);
|
||||
// }
|
||||
// });
|
||||
// final ImageUploadOptions options = ImageUploadOptions.builder(bitmap).build();
|
||||
// imageUploader.execute(options);
|
||||
// } catch (IOException e) {
|
||||
// Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
|
||||
// Log.e(TAG, "Error opening file", e);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void broadcast(final DirectThreadBroadcaster.BroadcastOptions broadcastOptions,
|
||||
// final DirectThreadBroadcaster.OnBroadcastCompleteListener listener) {
|
||||
// final DirectThreadBroadcaster broadcaster = new DirectThreadBroadcaster(threadId);
|
||||
// broadcaster.setOnTaskCompleteListener(listener);
|
||||
// broadcaster.execute(broadcastOptions);
|
||||
// }
|
||||
|
||||
@NonNull
|
||||
private User getUser(final long userId) {
|
||||
for (final User user : users) {
|
||||
@ -1426,58 +1340,6 @@ public class DirectMessageThreadFragment extends Fragment implements DirectReact
|
||||
return null;
|
||||
}
|
||||
|
||||
// private void searchUsername(final String text) {
|
||||
// final Bundle bundle = new Bundle();
|
||||
// bundle.putString("username", "@" + text);
|
||||
// NavHostFragment.findNavController(this).navigate(R.id.action_global_profileFragment, bundle);
|
||||
// }
|
||||
|
||||
// class ThreadAction extends AsyncTask<String, Void, Void> {
|
||||
// String action, argument;
|
||||
//
|
||||
// protected Void doInBackground(String... rawAction) {
|
||||
// action = rawAction[0];
|
||||
// argument = rawAction[1];
|
||||
// final String url = "https://i.instagram.com/api/v1/direct_v2/threads/" + threadId + "/items/" + argument + "/" + action + "/";
|
||||
// try {
|
||||
// String urlParameters = "_csrftoken=" + COOKIE.split("csrftoken=")[1].split(";")[0]
|
||||
// + "&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID);
|
||||
// final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
// urlConnection.setRequestMethod("POST");
|
||||
// urlConnection.setUseCaches(false);
|
||||
// urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
|
||||
// urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
// urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
|
||||
// urlConnection.setDoOutput(true);
|
||||
// DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
|
||||
// wr.writeBytes(urlParameters);
|
||||
// wr.flush();
|
||||
// wr.close();
|
||||
// urlConnection.connect();
|
||||
// if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
// if (action.equals("delete")) {
|
||||
// hasDeletedSomething = true;
|
||||
// } else if (action.equals("seen")) {
|
||||
// // context.sendBroadcast(new Intent(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM));
|
||||
// }
|
||||
// }
|
||||
// urlConnection.disconnect();
|
||||
// } catch (Throwable ex) {
|
||||
// Log.e("austin_debug", action + ": " + ex);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onPostExecute(Void result) {
|
||||
// if (hasDeletedSomething) {
|
||||
// // directItemModel = null;
|
||||
// // new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener)
|
||||
// // .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private void setupKbHeightProvider() {
|
||||
if (heightProvider != null) return;
|
||||
heightProvider = new HeightProvider(fragmentActivity).init().setHeightListener(height -> {
|
||||
|
@ -588,10 +588,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
binding.swipeRefreshLayout.setEnabled(false);
|
||||
binding.privatePage1.setImageResource(R.drawable.ic_outline_info_24);
|
||||
binding.privatePage2.setText(R.string.no_acc);
|
||||
final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) binding.privatePage.getLayoutParams();
|
||||
layoutParams.topMargin = 0;
|
||||
layoutParams.gravity = Gravity.CENTER;
|
||||
binding.privatePage.setLayoutParams(layoutParams);
|
||||
binding.privatePage.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
@ -683,6 +679,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
binding.postsRecyclerView.refresh();
|
||||
}
|
||||
profileDetailsBinding.isVerified.setVisibility(profileModel.isVerified() ? View.VISIBLE : View.GONE);
|
||||
profileDetailsBinding.isPrivate.setVisibility(profileModel.isPrivate() ? View.VISIBLE : View.GONE);
|
||||
final long profileId = profileModel.getPk();
|
||||
if (isLoggedIn) {
|
||||
fetchStoryAndHighlights(profileId);
|
||||
@ -917,11 +914,11 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
} else {
|
||||
profileDetailsBinding.mainFollowers.setClickable(false);
|
||||
profileDetailsBinding.mainFollowing.setClickable(false);
|
||||
// error
|
||||
binding.privatePage1.setImageResource(R.drawable.lock);
|
||||
binding.privatePage2.setText(R.string.priv_acc);
|
||||
binding.privatePage.setVisibility(View.VISIBLE);
|
||||
binding.postsRecyclerView.setVisibility(View.GONE);
|
||||
binding.swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1206,7 +1203,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
|
||||
}
|
||||
|
||||
private void updateSwipeRefreshState() {
|
||||
Log.d("austin_debug", "usrs: " + binding.postsRecyclerView.isFetching());
|
||||
binding.swipeRefreshLayout.setRefreshing(binding.postsRecyclerView.isFetching());
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.CookieUtils;
|
||||
@ -29,6 +31,14 @@ public class GeneralPreferencesFragment extends BasePreferencesFragment {
|
||||
}
|
||||
screen.addPreference(getUpdateCheckPreference(context));
|
||||
screen.addPreference(getFlagSecurePreference(context));
|
||||
final List<Preference> preferences = FlavorSettings.getInstance().getPreferences(context,
|
||||
getChildFragmentManager(),
|
||||
SettingCategory.GENERAL);
|
||||
if (preferences != null) {
|
||||
for (final Preference preference : preferences) {
|
||||
screen.addPreference(preference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Preference getDefaultTabPreference(@NonNull final Context context) {
|
||||
|
@ -0,0 +1,14 @@
|
||||
package awais.instagrabber.fragments.settings;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IFlavorSettings {
|
||||
List<Preference> getPreferences(Context context,
|
||||
FragmentManager childFragmentManager,
|
||||
SettingCategory settingCategory);
|
||||
}
|
@ -5,4 +5,5 @@ public final class PreferenceKeys {
|
||||
public static final String PREF_ENABLE_DM_AUTO_REFRESH = "enable_dm_auto_refresh";
|
||||
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT = "enable_dm_auto_refresh_freq_unit";
|
||||
public static final String PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER = "enable_dm_auto_refresh_freq_number";
|
||||
public static final String PREF_ENABLE_SENTRY = "enable_sentry";
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package awais.instagrabber.fragments.settings;
|
||||
|
||||
public enum SettingCategory {
|
||||
GENERAL,
|
||||
// add more as and when required
|
||||
}
|
@ -179,6 +179,9 @@ public final class ThreadManager {
|
||||
return null;
|
||||
}
|
||||
final DirectInbox inbox = inboxResource.data;
|
||||
if (inbox == null) {
|
||||
return null;
|
||||
}
|
||||
final List<DirectThread> threads = inbox.getThreads();
|
||||
if (threads == null || threads.isEmpty()) {
|
||||
return null;
|
||||
@ -264,7 +267,10 @@ public final class ThreadManager {
|
||||
}
|
||||
|
||||
private List<User> getUsersWithCurrentUser(final DirectThread t) {
|
||||
final ImmutableList.Builder<User> builder = ImmutableList.<User>builder().add(currentUser);
|
||||
final ImmutableList.Builder<User> builder = ImmutableList.builder();
|
||||
if (currentUser != null) {
|
||||
builder.add(currentUser);
|
||||
}
|
||||
final List<User> users = t.getUsers();
|
||||
if (users != null) {
|
||||
builder.addAll(users);
|
||||
|
@ -1,56 +0,0 @@
|
||||
package awais.instagrabber.models;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public final class LocationModel implements Serializable {
|
||||
private final long postCount;
|
||||
private final long id;
|
||||
private final String name;
|
||||
private final String bio;
|
||||
private final String url;
|
||||
private final String sdProfilePic;
|
||||
private final String lat;
|
||||
private final String lng;
|
||||
|
||||
public LocationModel(final long id,
|
||||
final String name,
|
||||
final String bio,
|
||||
final String url,
|
||||
final String sdProfilePic,
|
||||
final long postCount,
|
||||
final String lat,
|
||||
final String lng) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.bio = bio;
|
||||
this.url = url;
|
||||
this.sdProfilePic = sdProfilePic;
|
||||
this.postCount = postCount;
|
||||
this.lat = lat;
|
||||
this.lng = lng;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getBio() {
|
||||
return bio;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getGeo() { return "geo:" + lat + "," + lng + "?z=17&q=" + lat + "," + lng + "(" + name + ")"; }
|
||||
|
||||
public String getSdProfilePic() {
|
||||
return sdProfilePic;
|
||||
}
|
||||
|
||||
public Long getPostCount() { return postCount; }
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package awais.instagrabber.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import awais.instagrabber.models.enums.SuggestionType;
|
||||
|
||||
public final class SuggestionModel implements Comparable<SuggestionModel> {
|
||||
private final int position;
|
||||
private final boolean isVerified;
|
||||
private final String username, name, profilePic;
|
||||
private final SuggestionType suggestionType;
|
||||
|
||||
public SuggestionModel(final boolean isVerified, final String username, final String name, final String profilePic,
|
||||
final SuggestionType suggestionType, final int position) {
|
||||
this.isVerified = isVerified;
|
||||
this.username = username;
|
||||
this.name = name;
|
||||
this.profilePic = profilePic;
|
||||
this.suggestionType = suggestionType;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public boolean isVerified() {
|
||||
return isVerified;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getProfilePic() {
|
||||
return profilePic;
|
||||
}
|
||||
|
||||
public SuggestionType getSuggestionType() {
|
||||
return suggestionType;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull final SuggestionModel model) {
|
||||
return Integer.compare(getPosition(), model.getPosition());
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package awais.instagrabber.repositories;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.FeedFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.FieldMap;
|
||||
import retrofit2.http.FormUrlEncoded;
|
||||
|
@ -16,4 +16,7 @@ public interface GraphQLRepository {
|
||||
|
||||
@GET("/explore/tags/{tag}/?__a=1")
|
||||
Call<String> getTag(@Path("tag") String tag);
|
||||
|
||||
@GET("/explore/locations/{locationId}/?__a=1")
|
||||
Call<String> getLocation(@Path("locationId") long locationId);
|
||||
}
|
||||
|
@ -3,12 +3,15 @@ package awais.instagrabber.repositories;
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.LocationFeedResponse;
|
||||
import awais.instagrabber.repositories.responses.Place;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
public interface LocationRepository {
|
||||
@GET("/api/v1/locations/{location}/info/")
|
||||
Call<Place> fetch(@Path("location") final long locationId);
|
||||
|
||||
@GET("/api/v1/feed/location/{location}/")
|
||||
Call<LocationFeedResponse> fetchPosts(@Path("location") final long locationId,
|
||||
|
@ -0,0 +1,15 @@
|
||||
package awais.instagrabber.repositories;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.QueryMap;
|
||||
import retrofit2.http.Url;
|
||||
|
||||
public interface SearchRepository {
|
||||
@GET
|
||||
Call<SearchResponse> search(@Url String url, @QueryMap(encoded = true) Map<String, String> queryParams);
|
||||
}
|
@ -57,8 +57,8 @@ public class StoryViewerOptions implements Serializable {
|
||||
return new StoryViewerOptions(position, Type.FEED_STORY_POSITION);
|
||||
}
|
||||
|
||||
public static StoryViewerOptions forStoryArchive(final int position) {
|
||||
return new StoryViewerOptions(position, Type.STORY_ARCHIVE);
|
||||
public static StoryViewerOptions forStoryArchive(final String id) {
|
||||
return new StoryViewerOptions(id, Type.STORY_ARCHIVE);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
|
@ -5,22 +5,22 @@ import java.io.Serializable;
|
||||
import awais.instagrabber.models.enums.FollowingType;
|
||||
|
||||
public final class Hashtag implements Serializable {
|
||||
private final FollowingType following; // 0 false 1 true
|
||||
private final FollowingType following; // 0 false 1 true; not on search results
|
||||
private final long mediaCount;
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final String profilePicUrl; // on app API this is always null (property exists)
|
||||
private final String searchResultSubtitle; // shows how many posts there are on search results
|
||||
|
||||
public Hashtag(final String id,
|
||||
final String name,
|
||||
final String profilePicUrl,
|
||||
final long mediaCount,
|
||||
final FollowingType following) {
|
||||
final FollowingType following,
|
||||
final String searchResultSubtitle) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.profilePicUrl = profilePicUrl;
|
||||
this.mediaCount = mediaCount;
|
||||
this.following = following;
|
||||
this.searchResultSubtitle = searchResultSubtitle;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@ -31,10 +31,6 @@ public final class Hashtag implements Serializable {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getProfilePicUrl() {
|
||||
return profilePicUrl;
|
||||
}
|
||||
|
||||
public Long getMediaCount() {
|
||||
return mediaCount;
|
||||
}
|
||||
@ -42,4 +38,8 @@ public final class Hashtag implements Serializable {
|
||||
public FollowingType getFollowing() {
|
||||
return following;
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return searchResultSubtitle;
|
||||
}
|
||||
}
|
@ -9,16 +9,16 @@ public class Location implements Serializable {
|
||||
private final String name;
|
||||
private final String address;
|
||||
private final String city;
|
||||
private final float lng;
|
||||
private final float lat;
|
||||
private final double lng;
|
||||
private final double lat;
|
||||
|
||||
public Location(final long pk,
|
||||
final String shortName,
|
||||
final String name,
|
||||
final String address,
|
||||
final String city,
|
||||
final float lng,
|
||||
final float lat) {
|
||||
final double lng,
|
||||
final double lat) {
|
||||
this.pk = pk;
|
||||
this.shortName = shortName;
|
||||
this.name = name;
|
||||
@ -48,22 +48,24 @@ public class Location implements Serializable {
|
||||
return city;
|
||||
}
|
||||
|
||||
public float getLng() {
|
||||
public double getLng() {
|
||||
return lng;
|
||||
}
|
||||
|
||||
public float getLat() {
|
||||
public double getLat() {
|
||||
return lat;
|
||||
}
|
||||
|
||||
public String getGeo() { return "geo:" + lat + "," + lng + "?z=17&q=" + lat + "," + lng + "(" + name + ")"; }
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Location location = (Location) o;
|
||||
return pk == location.pk &&
|
||||
Float.compare(location.lng, lng) == 0 &&
|
||||
Float.compare(location.lat, lat) == 0 &&
|
||||
Double.compare(location.lng, lng) == 0 &&
|
||||
Double.compare(location.lat, lat) == 0 &&
|
||||
Objects.equals(shortName, location.shortName) &&
|
||||
Objects.equals(name, location.name) &&
|
||||
Objects.equals(address, location.address) &&
|
||||
|
@ -9,6 +9,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.models.enums.MediaItemType;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class Media implements Serializable {
|
||||
|
@ -2,6 +2,9 @@ package awais.instagrabber.repositories.responses;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationCounts;
|
||||
|
||||
public class NewsInboxResponse {
|
||||
private final NotificationCounts counts;
|
||||
private final List<Notification> newStories;
|
||||
|
@ -0,0 +1,43 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
|
||||
public class Place {
|
||||
private final Location location;
|
||||
// for search
|
||||
private final String title; // those are repeated within location
|
||||
private final String subtitle; // address
|
||||
private final String slug; // browser only; for end of address
|
||||
// for location info
|
||||
private final String status;
|
||||
|
||||
public Place(final Location location,
|
||||
final String title,
|
||||
final String subtitle,
|
||||
final String slug,
|
||||
final String status) {
|
||||
this.location = location;
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
this.slug = slug;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getSubtitle() {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
public String getSlug() {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ public class DirectItemActionLog implements Serializable {
|
||||
return Objects.hash(description, bold, textAttributes);
|
||||
}
|
||||
|
||||
public static class TextRange {
|
||||
public static class TextRange implements Serializable {
|
||||
private final int start;
|
||||
private final int end;
|
||||
private final String color;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.feed;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
@ -1,9 +1,11 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.feed;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class EndOfFeedGroup implements Serializable {
|
||||
private final String id;
|
||||
private final String title;
|
@ -1,4 +1,4 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.feed;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
@ -1,7 +1,9 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.feed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
|
||||
public class FeedFetchResponse {
|
||||
private final List<Media> items;
|
||||
private final int numResults;
|
@ -1,4 +1,4 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.notification;
|
||||
|
||||
import awais.instagrabber.models.enums.NotificationType;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.notification;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@ -7,8 +7,6 @@ import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public class NotificationArgs {
|
@ -1,4 +1,4 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.notification;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package awais.instagrabber.repositories.responses;
|
||||
package awais.instagrabber.repositories.responses.notification;
|
||||
|
||||
public class NotificationImage {
|
||||
private final String id;
|
@ -0,0 +1,38 @@
|
||||
package awais.instagrabber.repositories.responses.search;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Hashtag;
|
||||
import awais.instagrabber.repositories.responses.Place;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public class SearchItem {
|
||||
private final User user;
|
||||
private final Place place;
|
||||
private final Hashtag hashtag;
|
||||
private final int position;
|
||||
|
||||
public SearchItem(final User user,
|
||||
final Place place,
|
||||
final Hashtag hashtag,
|
||||
final int position) {
|
||||
this.user = user;
|
||||
this.place = place;
|
||||
this.hashtag = hashtag;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public Place getPlace() {
|
||||
return place;
|
||||
}
|
||||
|
||||
public Hashtag getHashtag() {
|
||||
return hashtag;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package awais.instagrabber.repositories.responses.search;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
|
||||
public class SearchResponse {
|
||||
// app
|
||||
private final List<SearchItem> list;
|
||||
// browser
|
||||
private final List<SearchItem> users;
|
||||
private final List<SearchItem> places;
|
||||
private final List<SearchItem> hashtags;
|
||||
// universal
|
||||
private final String status;
|
||||
|
||||
public SearchResponse(final List<SearchItem> list,
|
||||
final List<SearchItem> users,
|
||||
final List<SearchItem> places,
|
||||
final List<SearchItem> hashtags,
|
||||
final String status) {
|
||||
this.list = list;
|
||||
this.users = users;
|
||||
this.places = places;
|
||||
this.hashtags = hashtags;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<SearchItem> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<SearchItem> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public List<SearchItem> getPlaces() {
|
||||
return places;
|
||||
}
|
||||
|
||||
public List<SearchItem> getHashtags() {
|
||||
return hashtags;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
@ -18,13 +18,11 @@ import java.util.List;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.activities.MainActivity;
|
||||
import awais.instagrabber.repositories.responses.NotificationCounts;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationCounts;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.webservices.NewsService;
|
||||
import awais.instagrabber.webservices.ServiceCallback;
|
||||
|
||||
import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public class ActivityCheckerService extends Service {
|
||||
private static final String TAG = "ActivityCheckerService";
|
||||
private static final int INITIAL_DELAY_MILLIS = 200;
|
||||
|
@ -1,6 +1,8 @@
|
||||
package awais.instagrabber.utils;
|
||||
|
||||
public final class Constants {
|
||||
public static final String CRASH_REPORT_EMAIL = "barinsta@austinhuang.me";
|
||||
|
||||
// string prefs
|
||||
public static final String FOLDER_PATH = "custom_path";
|
||||
public static final String DATE_TIME_FORMAT = "date_time_format";
|
||||
|
@ -1,10 +1,8 @@
|
||||
package awais.instagrabber.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.webkit.MimeTypeMap;
|
||||
@ -13,8 +11,6 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.Data;
|
||||
import androidx.work.NetworkType;
|
||||
@ -294,7 +290,8 @@ public final class DownloadUtils {
|
||||
final int childPositionIfSingle) {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
for (final Media media : feedModels) {
|
||||
final File downloadDir = getDownloadDir(context, "@" + media.getUser().getUsername());
|
||||
final User mediaUser = media.getUser();
|
||||
final File downloadDir = getDownloadDir(context, mediaUser == null ? "" : "@" + mediaUser.getUsername());
|
||||
if (downloadDir == null) return;
|
||||
switch (media.getMediaType()) {
|
||||
case MEDIA_TYPE_IMAGE:
|
||||
@ -307,9 +304,8 @@ public final class DownloadUtils {
|
||||
case MEDIA_TYPE_VOICE: {
|
||||
final String url = getUrlOfType(media);
|
||||
String fileName = media.getId();
|
||||
final User user = media.getUser();
|
||||
if (user != null) {
|
||||
fileName = user.getUsername() + "_" + fileName;
|
||||
if (mediaUser != null) {
|
||||
fileName = mediaUser.getUsername() + "_" + fileName;
|
||||
}
|
||||
final File file = getDownloadSaveFile(downloadDir, fileName, url);
|
||||
map.put(url, file.getAbsolutePath());
|
||||
|
@ -729,8 +729,11 @@ public final class ResponseBodyUtils {
|
||||
width = dimensions.optInt("width");
|
||||
}
|
||||
String thumbnailUrl = null;
|
||||
final JSONArray displayResources = feedItem.getJSONArray("display_resources");
|
||||
final List<MediaCandidate> candidates = new ArrayList<MediaCandidate>();
|
||||
if (feedItem.has("display_resources") || feedItem.has("thumbnail_resources")) {
|
||||
final JSONArray displayResources = feedItem.has("display_resources")
|
||||
? feedItem.getJSONArray("display_resources")
|
||||
: feedItem.getJSONArray("thumbnail_resources");
|
||||
for (int i = 0; i < displayResources.length(); i++) {
|
||||
final JSONObject displayResource = displayResources.getJSONObject(i);
|
||||
candidates.add(new MediaCandidate(
|
||||
@ -739,6 +742,7 @@ public final class ResponseBodyUtils {
|
||||
displayResource.getString("src")
|
||||
));
|
||||
}
|
||||
}
|
||||
final ImageVersions2 imageVersions2 = new ImageVersions2(candidates);
|
||||
|
||||
User user = backup;
|
||||
@ -943,8 +947,7 @@ public final class ResponseBodyUtils {
|
||||
// }
|
||||
|
||||
public static StoryModel parseStoryItem(final JSONObject data,
|
||||
final boolean isLoc,
|
||||
final boolean isHashtag,
|
||||
final boolean isLocOrHashtag,
|
||||
final String username) throws JSONException {
|
||||
final boolean isVideo = data.has("video_duration");
|
||||
final StoryModel model = new StoryModel(data.getString("id"),
|
||||
@ -952,9 +955,7 @@ public final class ResponseBodyUtils {
|
||||
.getString("url"), null,
|
||||
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||
data.optLong("taken_at", 0),
|
||||
(isLoc || isHashtag)
|
||||
? data.getJSONObject("user").getString("username")
|
||||
: username,
|
||||
isLocOrHashtag ? data.getJSONObject("user").getString("username") : username,
|
||||
data.getJSONObject("user").getLong("pk"),
|
||||
data.optBoolean("can_reply"));
|
||||
|
||||
|
@ -15,6 +15,7 @@ import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_D
|
||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER;
|
||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_AUTO_REFRESH_FREQ_UNIT;
|
||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_DM_NOTIFICATIONS;
|
||||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY;
|
||||
import static awais.instagrabber.utils.Constants.APP_LANGUAGE;
|
||||
import static awais.instagrabber.utils.Constants.APP_THEME;
|
||||
import static awais.instagrabber.utils.Constants.APP_UA;
|
||||
@ -145,6 +146,10 @@ public final class SettingsHelper {
|
||||
if (sharedPreferences != null) sharedPreferences.edit().putBoolean(key, val).apply();
|
||||
}
|
||||
|
||||
public boolean hasPreference(final String key) {
|
||||
return sharedPreferences != null && sharedPreferences.contains(key);
|
||||
}
|
||||
|
||||
@StringDef(
|
||||
{APP_LANGUAGE, APP_THEME, APP_UA, BROWSER_UA, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION,
|
||||
CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME,
|
||||
@ -156,7 +161,7 @@ public final class SettingsHelper {
|
||||
@StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
|
||||
SHOW_CAPTIONS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, CHECK_ACTIVITY,
|
||||
CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED, PREF_ENABLE_DM_NOTIFICATIONS, PREF_ENABLE_DM_AUTO_REFRESH,
|
||||
FLAG_SECURE, TOGGLE_KEYWORD_FILTER})
|
||||
FLAG_SECURE, TOGGLE_KEYWORD_FILTER, PREF_ENABLE_SENTRY})
|
||||
public @interface BooleanSettings {}
|
||||
|
||||
@StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE, PREF_ENABLE_DM_AUTO_REFRESH_FREQ_NUMBER})
|
||||
|
@ -69,7 +69,7 @@ public final class TextUtils {
|
||||
str = str.trim();
|
||||
return "".equals(str) || "null".equals(str) || str.isEmpty();
|
||||
}
|
||||
return "null".contentEquals(charSequence) || "".contentEquals(charSequence) || charSequence.length() < 1;
|
||||
return "null".contentEquals(charSequence) || "".contentEquals(charSequence);
|
||||
}
|
||||
|
||||
public static String millisToTimeString(final long millis) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
package awais.instagrabber.utils.emoji;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
@ -18,6 +21,7 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.customviews.emoji.Emoji;
|
||||
import awais.instagrabber.customviews.emoji.EmojiCategory;
|
||||
import awais.instagrabber.customviews.emoji.EmojiCategoryType;
|
||||
@ -33,25 +37,25 @@ public final class EmojiParser {
|
||||
private Map<EmojiCategoryType, EmojiCategory> categoryMap = Collections.emptyMap();
|
||||
private ImmutableList<EmojiCategory> categories;
|
||||
|
||||
public static EmojiParser getInstance() {
|
||||
public static void setup(@NonNull final Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (LOCK) {
|
||||
if (instance == null) {
|
||||
instance = new EmojiParser();
|
||||
instance = new EmojiParser(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static EmojiParser getInstance() {
|
||||
if (instance == null) {
|
||||
throw new RuntimeException("Setup not done!");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private EmojiParser() {
|
||||
final String file = "res/raw/emojis.json";
|
||||
final ClassLoader classLoader = getClass().getClassLoader();
|
||||
if (classLoader == null) {
|
||||
Log.e(TAG, "Emoji: classLoader is null");
|
||||
return;
|
||||
}
|
||||
try (final InputStream in = classLoader.getResourceAsStream(file)) {
|
||||
private EmojiParser(final Context context) {
|
||||
try (final InputStream in = context.getResources().openRawResource(R.raw.emojis)) {
|
||||
final String json = NetworkUtils.readFromInputStream(in);
|
||||
final Gson gson = new GsonBuilder()
|
||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||
|
@ -181,6 +181,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
||||
MediaUtils.getVoiceInfo(contentResolver, uri, new MediaUtils.OnInfoLoadListener<MediaUtils.VideoInfo>() {
|
||||
@Override
|
||||
public void onLoad(@Nullable final MediaUtils.VideoInfo videoInfo) {
|
||||
if (videoInfo == null) return;
|
||||
threadManager.sendVoice(data,
|
||||
uri,
|
||||
result.getWaveform(),
|
||||
|
@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
|
||||
public class NotificationViewModel extends ViewModel {
|
||||
private MutableLiveData<List<Notification>> list;
|
||||
|
@ -12,10 +12,10 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import awais.instagrabber.repositories.FeedRepository;
|
||||
import awais.instagrabber.repositories.responses.EndOfFeedDemarcator;
|
||||
import awais.instagrabber.repositories.responses.EndOfFeedGroup;
|
||||
import awais.instagrabber.repositories.responses.EndOfFeedGroupSet;
|
||||
import awais.instagrabber.repositories.responses.FeedFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedDemarcator;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroup;
|
||||
import awais.instagrabber.repositories.responses.feed.EndOfFeedGroupSet;
|
||||
import awais.instagrabber.repositories.responses.feed.FeedFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
|
@ -19,6 +19,7 @@ import awais.instagrabber.repositories.GraphQLRepository;
|
||||
import awais.instagrabber.repositories.responses.FriendshipStatus;
|
||||
import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.Hashtag;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.Media;
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
@ -392,9 +393,53 @@ public class GraphQLService extends BaseService {
|
||||
callback.onSuccess(new Hashtag(
|
||||
body.getString(Constants.EXTRAS_ID),
|
||||
body.getString("name"),
|
||||
body.getString("profile_pic_url"),
|
||||
timelineMedia.getLong("count"),
|
||||
body.optBoolean("is_following") ? FollowingType.FOLLOWING : FollowingType.NOT_FOLLOWING));
|
||||
body.optBoolean("is_following") ? FollowingType.FOLLOWING : FollowingType.NOT_FOLLOWING,
|
||||
null));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "onResponse", e);
|
||||
if (callback != null) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
|
||||
if (callback != null) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void fetchLocation(final long locationId,
|
||||
final ServiceCallback<Location> callback) {
|
||||
final Call<String> request = repository.getLocation(locationId);
|
||||
request.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
final String rawBody = response.body();
|
||||
if (rawBody == null) {
|
||||
Log.e(TAG, "Error occurred while fetching gql location of " + locationId);
|
||||
callback.onSuccess(null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final JSONObject body = new JSONObject(rawBody)
|
||||
.getJSONObject("graphql")
|
||||
.getJSONObject(Constants.EXTRAS_LOCATION);
|
||||
final JSONObject timelineMedia = body.getJSONObject("edge_location_to_media");
|
||||
final JSONObject address = new JSONObject(body.getString("address_json"));
|
||||
callback.onSuccess(new Location(
|
||||
body.getLong(Constants.EXTRAS_ID),
|
||||
body.getString("slug"),
|
||||
body.getString("name"),
|
||||
address.optString("street_address"),
|
||||
address.optString("city_name"),
|
||||
body.optDouble("lng", 0d),
|
||||
body.optDouble("lat", 0d)
|
||||
));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "onResponse", e);
|
||||
if (callback != null) {
|
||||
|
@ -5,7 +5,9 @@ import androidx.annotation.NonNull;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import awais.instagrabber.repositories.LocationRepository;
|
||||
import awais.instagrabber.repositories.responses.Location;
|
||||
import awais.instagrabber.repositories.responses.LocationFeedResponse;
|
||||
import awais.instagrabber.repositories.responses.Place;
|
||||
import awais.instagrabber.repositories.responses.PostsFetchResponse;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import retrofit2.Call;
|
||||
@ -67,34 +69,24 @@ public class LocationService extends BaseService {
|
||||
});
|
||||
}
|
||||
|
||||
// private PostsFetchResponse parseResponse(@NonNull final String body) throws JSONException {
|
||||
// final JSONObject root = new JSONObject(body);
|
||||
// final boolean moreAvailable = root.optBoolean("more_available");
|
||||
// final String nextMaxId = root.optString("next_max_id");
|
||||
// final JSONArray itemsJson = root.optJSONArray("items");
|
||||
// final List<FeedModel> items = parseItems(itemsJson);
|
||||
// return new PostsFetchResponse(
|
||||
// items,
|
||||
// moreAvailable,
|
||||
// nextMaxId
|
||||
// );
|
||||
// }
|
||||
|
||||
// private List<FeedModel> parseItems(final JSONArray items) throws JSONException {
|
||||
// if (items == null) {
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
// final List<FeedModel> feedModels = new ArrayList<>();
|
||||
// for (int i = 0; i < items.length(); i++) {
|
||||
// final JSONObject itemJson = items.optJSONObject(i);
|
||||
// if (itemJson == null) {
|
||||
// continue;
|
||||
// }
|
||||
// final FeedModel feedModel = ResponseBodyUtils.parseItem(itemJson);
|
||||
// if (feedModel != null) {
|
||||
// feedModels.add(feedModel);
|
||||
// }
|
||||
// }
|
||||
// return feedModels;
|
||||
// }
|
||||
public void fetch(@NonNull final long locationId,
|
||||
final ServiceCallback<Location> callback) {
|
||||
final Call<Place> request = repository.fetch(locationId);
|
||||
request.enqueue(new Callback<Place>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<Place> call, @NonNull final Response<Place> response) {
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
callback.onSuccess(response.body() == null ? null : response.body().getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull final Call<Place> call, @NonNull final Throwable t) {
|
||||
if (callback != null) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,10 @@ import awais.instagrabber.repositories.responses.NewsInboxResponse;
|
||||
import awais.instagrabber.repositories.responses.Notification;
|
||||
import awais.instagrabber.repositories.responses.NotificationArgs;
|
||||
import awais.instagrabber.repositories.responses.NotificationCounts;
|
||||
import awais.instagrabber.repositories.responses.NewsInboxResponse;
|
||||
import awais.instagrabber.repositories.responses.notification.Notification;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationArgs;
|
||||
import awais.instagrabber.repositories.responses.notification.NotificationCounts;
|
||||
import awais.instagrabber.repositories.responses.User;
|
||||
import awais.instagrabber.repositories.responses.UserSearchResponse;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
|
@ -0,0 +1,50 @@
|
||||
package awais.instagrabber.webservices;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import awais.instagrabber.repositories.SearchRepository;
|
||||
import awais.instagrabber.repositories.responses.search.SearchResponse;
|
||||
import awais.instagrabber.utils.TextUtils;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
|
||||
public class SearchService extends BaseService {
|
||||
private static final String TAG = "LocationService";
|
||||
|
||||
private final SearchRepository repository;
|
||||
|
||||
private static SearchService instance;
|
||||
|
||||
private SearchService() {
|
||||
final Retrofit retrofit = getRetrofitBuilder()
|
||||
.baseUrl("https://www.instagram.com")
|
||||
.build();
|
||||
repository = retrofit.create(SearchRepository.class);
|
||||
}
|
||||
|
||||
public static SearchService getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new SearchService();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Call<SearchResponse> search(final boolean isLoggedIn,
|
||||
final String query,
|
||||
final String context) {
|
||||
final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||
builder.put("query", query);
|
||||
// context is one of: "blended", "user", "place", "hashtag"
|
||||
// note that "place" and "hashtag" can contain ONE user result, who knows why
|
||||
builder.put("context", context);
|
||||
builder.put("count", "50");
|
||||
return repository.search(isLoggedIn
|
||||
? "https://i.instagram.com/api/v1/fbsearch/topsearch_flat/"
|
||||
: "https://www.instagram.com/web/search/topsearch/",
|
||||
builder.build());
|
||||
}
|
||||
}
|
@ -93,7 +93,7 @@ public class StoriesService extends BaseService {
|
||||
}
|
||||
try {
|
||||
final JSONObject itemJson = new JSONObject(body).getJSONArray("items").getJSONObject(0);
|
||||
callback.onSuccess(ResponseBodyUtils.parseStoryItem(itemJson, false, false, null));
|
||||
callback.onSuccess(ResponseBodyUtils.parseStoryItem(itemJson, false, null));
|
||||
} catch (JSONException e) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
@ -185,7 +185,7 @@ public class StoriesService extends BaseService {
|
||||
final boolean isBestie = node.optBoolean("has_besties_media", false);
|
||||
StoryModel firstStoryModel = null;
|
||||
if (itemJson != null) {
|
||||
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, false, null);
|
||||
firstStoryModel = ResponseBodyUtils.parseStoryItem(itemJson, false, null);
|
||||
}
|
||||
feedStoryModels.add(new FeedStoryModel(id, user, fullyRead, timestamp, firstStoryModel, mediaCount, false, isBestie));
|
||||
} catch (Exception e) {} // to cover promotional reels with non-long user pk's
|
||||
@ -361,9 +361,8 @@ public class StoriesService extends BaseService {
|
||||
final ServiceCallback<List<StoryModel>> callback) {
|
||||
final String url = buildUrl(options);
|
||||
final Call<String> userStoryCall = repository.getUserStory(url);
|
||||
final boolean isLoc = options.getType() == StoryViewerOptions.Type.LOCATION;
|
||||
final boolean isHashtag = options.getType() == StoryViewerOptions.Type.HASHTAG;
|
||||
final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT;
|
||||
final boolean isLocOrHashtag = options.getType() == StoryViewerOptions.Type.LOCATION || options.getType() == StoryViewerOptions.Type.HASHTAG;
|
||||
final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT || options.getType() == StoryViewerOptions.Type.STORY_ARCHIVE;
|
||||
userStoryCall.enqueue(new Callback<String>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
|
||||
@ -377,7 +376,7 @@ public class StoriesService extends BaseService {
|
||||
data = new JSONObject(body);
|
||||
|
||||
if (!isHighlight) {
|
||||
data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel");
|
||||
data = data.optJSONObject((isLocOrHashtag) ? "story" : "reel");
|
||||
} else {
|
||||
data = data.getJSONObject("reels").optJSONObject(options.getName());
|
||||
}
|
||||
@ -385,8 +384,7 @@ public class StoriesService extends BaseService {
|
||||
String username = null;
|
||||
if (data != null
|
||||
// && localUsername == null
|
||||
&& !isLoc
|
||||
&& !isHashtag) {
|
||||
&& !isLocOrHashtag) {
|
||||
username = data.getJSONObject("user").getString("username");
|
||||
}
|
||||
|
||||
@ -394,12 +392,11 @@ public class StoriesService extends BaseService {
|
||||
if (data != null
|
||||
&& (media = data.optJSONArray("items")) != null
|
||||
&& media.length() > 0 && media.optJSONObject(0) != null) {
|
||||
|
||||
final int mediaLen = media.length();
|
||||
final List<StoryModel> models = new ArrayList<>();
|
||||
for (int i = 0; i < mediaLen; ++i) {
|
||||
data = media.getJSONObject(i);
|
||||
models.add(ResponseBodyUtils.parseStoryItem(data, isLoc, isHashtag, username));
|
||||
models.add(ResponseBodyUtils.parseStoryItem(data, isLocOrHashtag, username));
|
||||
}
|
||||
callback.onSuccess(models);
|
||||
} else {
|
||||
@ -540,6 +537,7 @@ public class StoriesService extends BaseService {
|
||||
id = String.valueOf(options.getId());
|
||||
break;
|
||||
case HIGHLIGHT:
|
||||
case STORY_ARCHIVE:
|
||||
builder.append("feed/reels_media/?user_ids=");
|
||||
id = options.getName();
|
||||
break;
|
||||
@ -547,15 +545,12 @@ public class StoriesService extends BaseService {
|
||||
break;
|
||||
// case FEED_STORY_POSITION:
|
||||
// break;
|
||||
// case STORY_ARCHIVE:
|
||||
// break;
|
||||
}
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
final String userId = id.replace(":", "%3A");
|
||||
builder.append(userId);
|
||||
if (type != StoryViewerOptions.Type.HIGHLIGHT) {
|
||||
builder.append(id);
|
||||
if (type != StoryViewerOptions.Type.HIGHLIGHT && type != StoryViewerOptions.Type.STORY_ARCHIVE) {
|
||||
builder.append("/story/");
|
||||
}
|
||||
return builder.toString();
|
||||
|
@ -1,50 +1,35 @@
|
||||
package awaisomereport;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Date;
|
||||
//import java.util.zip.ZipEntry;
|
||||
//import java.util.zip.ZipOutputStream;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
public final class CrashReporter implements Thread.UncaughtExceptionHandler {
|
||||
private static final String TAG = CrashReporter.class.getSimpleName();
|
||||
|
||||
private static CrashReporter reporterInstance;
|
||||
private final Application application;
|
||||
private final String email;
|
||||
|
||||
// private final File crashLogsZip;
|
||||
private final CrashHandler crashHandler;
|
||||
|
||||
private boolean startAttempted = false;
|
||||
private Thread.UncaughtExceptionHandler defaultEH;
|
||||
|
||||
public static CrashReporter get(final Application application) {
|
||||
if (reporterInstance == null) reporterInstance = new CrashReporter(application);
|
||||
if (reporterInstance == null) {
|
||||
reporterInstance = new CrashReporter(application);
|
||||
}
|
||||
return reporterInstance;
|
||||
}
|
||||
|
||||
private CrashReporter(@NonNull final Application application) {
|
||||
this.application = application;
|
||||
this.email = "barinsta@austinhuang.me";
|
||||
crashHandler = new CrashHandler(application);
|
||||
// this.crashLogsZip = new File(application.getExternalCacheDir(), "crash_logs.zip");
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (!startAttempted) {
|
||||
defaultEH = Thread.getDefaultUncaughtExceptionHandler();
|
||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
||||
startAttempted = true;
|
||||
}
|
||||
@ -52,140 +37,10 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
@Override
|
||||
public void uncaughtException(@NonNull final Thread t, @NonNull final Throwable exception) {
|
||||
final StringBuilder reportBuilder = new StringBuilder();
|
||||
reportBuilder.append("IMPORTANT: If sending by email, your email address and the entire content will be made public on GitHub issues.");
|
||||
reportBuilder.append("\r\nIMPORTANT: When possible, please describe the steps leading to this crash. Thank you for your cooperation.");
|
||||
reportBuilder.append("\r\n\r\nError report collected on: ").append(new Date().toString());
|
||||
|
||||
reportBuilder
|
||||
.append("\r\n\r\nInformation:\r\n==============")
|
||||
.append("\r\nVERSION : ").append(BuildConfig.VERSION_NAME)
|
||||
.append("\r\nVERSION_CODE : ").append(BuildConfig.VERSION_CODE)
|
||||
.append("\r\nPHONE-MODEL : ").append(Build.MODEL)
|
||||
.append("\r\nANDROID_VERS : ").append(Build.VERSION.RELEASE)
|
||||
.append("\r\nANDROID_REL : ").append(Build.VERSION.SDK_INT)
|
||||
.append("\r\nBRAND : ").append(Build.BRAND)
|
||||
.append("\r\nMANUFACTURER : ").append(Build.MANUFACTURER)
|
||||
.append("\r\nBOARD : ").append(Build.BOARD)
|
||||
.append("\r\nDEVICE : ").append(Build.DEVICE)
|
||||
.append("\r\nPRODUCT : ").append(Build.PRODUCT)
|
||||
.append("\r\nHOST : ").append(Build.HOST)
|
||||
.append("\r\nTAGS : ").append(Build.TAGS);
|
||||
|
||||
reportBuilder.append("\r\n\r\nStack:\r\n==============\r\n");
|
||||
final Writer result = new StringWriter();
|
||||
try (final PrintWriter printWriter = new PrintWriter(result)) {
|
||||
exception.printStackTrace(printWriter);
|
||||
reportBuilder.append(result.toString());
|
||||
|
||||
reportBuilder.append("\r\nCause:\r\n==============");
|
||||
|
||||
// for AsyncTask crashes
|
||||
Throwable cause = exception.getCause();
|
||||
while (cause != null) {
|
||||
cause.printStackTrace(printWriter);
|
||||
reportBuilder.append(result.toString());
|
||||
cause = cause.getCause();
|
||||
}
|
||||
}
|
||||
reportBuilder.append("\r\n\r\n**** End of current Report ***");
|
||||
|
||||
final String errorContent = reportBuilder.toString();
|
||||
try (final FileOutputStream trace = application.openFileOutput("stack-" + System.currentTimeMillis() + ".stacktrace", Context.MODE_PRIVATE)) {
|
||||
trace.write(errorContent.getBytes());
|
||||
} catch (final Exception ex) {
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", ex);
|
||||
}
|
||||
|
||||
application.startActivity(new Intent(application, ErrorReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
// zipLogs();
|
||||
|
||||
Process.killProcess(Process.myPid());
|
||||
System.exit(10);
|
||||
}
|
||||
|
||||
// public synchronized CrashReporter zipLogs() {
|
||||
// final File logDir = Utils.logCollector != null ? Utils.logCollector.getLogDir() :
|
||||
// new File(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? application.getDataDir() : application.getFilesDir(), "crashlogs");
|
||||
//
|
||||
// try (final FileOutputStream fos = new FileOutputStream(crashLogsZip);
|
||||
// final ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||
//
|
||||
// final File[] files = logDir.listFiles();
|
||||
//
|
||||
// if (files != null) {
|
||||
// zos.setLevel(5);
|
||||
// byte[] buffer;
|
||||
// for (final File file : files) {
|
||||
// if (file != null && file.length() > 0) {
|
||||
// buffer = new byte[1024];
|
||||
// try (final FileInputStream fis = new FileInputStream(file)) {
|
||||
// zos.putNextEntry(new ZipEntry(file.getName()));
|
||||
// int length;
|
||||
// while ((length = fis.read(buffer)) > 0) zos.write(buffer, 0, length);
|
||||
// zos.closeEntry();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } catch (final Exception e) {
|
||||
// if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
// }
|
||||
//
|
||||
// return this;
|
||||
// }
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public void startCrashEmailIntent(final Context context) {
|
||||
try {
|
||||
final String filePath = context.getFilesDir().getAbsolutePath();
|
||||
|
||||
String[] errorFileList;
|
||||
|
||||
try {
|
||||
final File dir = new File(filePath);
|
||||
if (dir.exists() && !dir.isDirectory()) dir.delete();
|
||||
dir.mkdir();
|
||||
errorFileList = dir.list((d, name) -> name.endsWith(".stacktrace"));
|
||||
} catch (final Exception e) {
|
||||
errorFileList = null;
|
||||
}
|
||||
|
||||
if (errorFileList != null && errorFileList.length > 0) {
|
||||
final StringBuilder errorStringBuilder;
|
||||
|
||||
errorStringBuilder = new StringBuilder("\r\n\r\n");
|
||||
final int maxSendMail = 5;
|
||||
|
||||
int curIndex = 0;
|
||||
for (final String curString : errorFileList) {
|
||||
final File file = new File(filePath + '/' + curString);
|
||||
|
||||
if (curIndex++ <= maxSendMail) {
|
||||
errorStringBuilder.append("New Trace collected:\r\n=====================\r\n");
|
||||
try (final BufferedReader input = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = input.readLine()) != null)
|
||||
errorStringBuilder.append(line).append("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
file.delete();
|
||||
}
|
||||
|
||||
errorStringBuilder.append("\r\n\r\n");
|
||||
|
||||
context.startActivity(Intent.createChooser(new Intent(Intent.ACTION_SEND).setType("message/rfc822")
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_EMAIL, new String[]{email})
|
||||
// .putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(application, BuildConfig.APPLICATION_ID + ".provider", crashLogsZip))
|
||||
.putExtra(Intent.EXTRA_SUBJECT, "Barinsta Crash Report")
|
||||
.putExtra(Intent.EXTRA_TEXT, errorStringBuilder.toString()), "Select an email app to send crash logs"));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||
}
|
||||
if (crashHandler == null) {
|
||||
defaultEH.uncaughtException(t, exception);
|
||||
return;
|
||||
}
|
||||
crashHandler.uncaughtException(t, exception, defaultEH);
|
||||
}
|
||||
}
|
||||
|
134
app/src/main/java/awaisomereport/CrashReporterHelper.java
Normal file
134
app/src/main/java/awaisomereport/CrashReporterHelper.java
Normal file
@ -0,0 +1,134 @@
|
||||
package awaisomereport;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Date;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
|
||||
public final class CrashReporterHelper {
|
||||
private static final String TAG = CrashReporterHelper.class.getSimpleName();
|
||||
|
||||
public static void startErrorReporterActivity(@NonNull final Application application,
|
||||
@NonNull final Throwable exception) {
|
||||
final StringBuilder reportBuilder = new StringBuilder();
|
||||
reportBuilder.append("IMPORTANT: If sending by email, your email address and the entire content will be made public on GitHub issues.")
|
||||
.append("\r\nIMPORTANT: When possible, please describe the steps leading to this crash. Thank you for your cooperation.")
|
||||
.append("\r\n\r\nError report collected on: ").append(new Date().toString())
|
||||
.append("\r\n\r\nInformation:\r\n==============")
|
||||
.append("\r\nVERSION : ").append(BuildConfig.VERSION_NAME)
|
||||
.append("\r\nVERSION_CODE : ").append(BuildConfig.VERSION_CODE)
|
||||
.append("\r\nPHONE-MODEL : ").append(Build.MODEL)
|
||||
.append("\r\nANDROID_VERS : ").append(Build.VERSION.RELEASE)
|
||||
.append("\r\nANDROID_REL : ").append(Build.VERSION.SDK_INT)
|
||||
.append("\r\nBRAND : ").append(Build.BRAND)
|
||||
.append("\r\nMANUFACTURER : ").append(Build.MANUFACTURER)
|
||||
.append("\r\nBOARD : ").append(Build.BOARD)
|
||||
.append("\r\nDEVICE : ").append(Build.DEVICE)
|
||||
.append("\r\nPRODUCT : ").append(Build.PRODUCT)
|
||||
.append("\r\nHOST : ").append(Build.HOST)
|
||||
.append("\r\nTAGS : ").append(Build.TAGS);
|
||||
|
||||
reportBuilder.append("\r\n\r\nStack:\r\n==============\r\n");
|
||||
final Writer result = new StringWriter();
|
||||
try (final PrintWriter printWriter = new PrintWriter(result)) {
|
||||
exception.printStackTrace(printWriter);
|
||||
reportBuilder.append(result.toString());
|
||||
reportBuilder.append("\r\nCause:\r\n==============");
|
||||
// for AsyncTask crashes
|
||||
Throwable cause = exception.getCause();
|
||||
while (cause != null) {
|
||||
cause.printStackTrace(printWriter);
|
||||
reportBuilder.append(result.toString());
|
||||
cause = cause.getCause();
|
||||
}
|
||||
}
|
||||
reportBuilder.append("\r\n\r\n**** End of current Report ***");
|
||||
|
||||
final String errorContent = reportBuilder.toString();
|
||||
try (final FileOutputStream trace = application.openFileOutput("stack-" + System.currentTimeMillis() + ".stacktrace", Context.MODE_PRIVATE)) {
|
||||
trace.write(errorContent.getBytes());
|
||||
} catch (final Exception ex) {
|
||||
if (BuildConfig.DEBUG) Log.e(TAG, "", ex);
|
||||
}
|
||||
|
||||
application.startActivity(new Intent(application, ErrorReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
public static void startCrashEmailIntent(final Context context) {
|
||||
try {
|
||||
final String filePath = context.getFilesDir().getAbsolutePath();
|
||||
|
||||
String[] errorFileList;
|
||||
|
||||
try {
|
||||
final File dir = new File(filePath);
|
||||
if (dir.exists() && !dir.isDirectory()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
dir.delete();
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
dir.mkdirs();
|
||||
errorFileList = dir.list((d, name) -> name.endsWith(".stacktrace"));
|
||||
} catch (final Exception e) {
|
||||
errorFileList = null;
|
||||
}
|
||||
|
||||
if (errorFileList == null || errorFileList.length <= 0) {
|
||||
return;
|
||||
}
|
||||
final StringBuilder errorStringBuilder;
|
||||
|
||||
errorStringBuilder = new StringBuilder("\r\n\r\n");
|
||||
final int maxSendMail = 5;
|
||||
int curIndex = 0;
|
||||
for (final String curString : errorFileList) {
|
||||
final File file = new File(filePath + '/' + curString);
|
||||
|
||||
if (curIndex++ <= maxSendMail) {
|
||||
errorStringBuilder.append("New Trace collected:\r\n=====================\r\n");
|
||||
try (final BufferedReader input = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = input.readLine()) != null)
|
||||
errorStringBuilder.append(line).append("\r\n");
|
||||
}
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
}
|
||||
|
||||
errorStringBuilder.append("\r\n\r\n");
|
||||
final Resources resources = context.getResources();
|
||||
context.startActivity(Intent.createChooser(
|
||||
new Intent(Intent.ACTION_SEND)
|
||||
.setType("message/rfc822")
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_EMAIL, new String[]{Constants.CRASH_REPORT_EMAIL})
|
||||
// .putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(application, BuildConfig.APPLICATION_ID + ".provider", crashLogsZip))
|
||||
.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.crash_report_subject))
|
||||
.putExtra(Intent.EXTRA_TEXT, errorStringBuilder.toString()),
|
||||
context.getResources().getString(R.string.crash_report_title))
|
||||
);
|
||||
} catch (final Exception e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -43,8 +43,9 @@ public final class ErrorReporterActivity extends Activity implements View.OnClic
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull final View v) {
|
||||
if (v == btnReport)
|
||||
CrashReporter.get(getApplication()).startCrashEmailIntent(this);
|
||||
if (v == btnReport) {
|
||||
CrashReporterHelper.startCrashEmailIntent(this);
|
||||
}
|
||||
finish();
|
||||
System.exit(10);
|
||||
}
|
||||
|
7
app/src/main/java/awaisomereport/ICrashHandler.java
Normal file
7
app/src/main/java/awaisomereport/ICrashHandler.java
Normal file
@ -0,0 +1,7 @@
|
||||
package awaisomereport;
|
||||
|
||||
public interface ICrashHandler {
|
||||
void uncaughtException(Thread t,
|
||||
Throwable exception,
|
||||
Thread.UncaughtExceptionHandler defaultEH);
|
||||
}
|
BIN
app/src/main/res/drawable/ic_hashtag.png
Normal file
BIN
app/src/main/res/drawable/ic_hashtag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
@ -156,7 +156,7 @@
|
||||
android:hint="@string/message"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:textColor="@color/white"
|
||||
android:textColor="?dmInputTextColor"
|
||||
android:textColorHint="@color/grey_500"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
@ -50,8 +50,8 @@
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/privatePage1"
|
||||
android:layout_width="@dimen/private_page_margins"
|
||||
android:layout_height="@dimen/private_page_margins"
|
||||
android:layout_width="@dimen/private_page_size"
|
||||
android:layout_height="@dimen/private_page_size"
|
||||
app:srcCompat="@drawable/lock" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
|
@ -9,8 +9,7 @@
|
||||
android:id="@+id/story_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
app:layout_constraintBottom_toTopOf="@id/storiesList"
|
||||
app:layout_constraintBottom_toTopOf="@id/postActions"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
@ -37,11 +36,17 @@
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/postActions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
app:layout_constraintTop_toBottomOf="@id/story_container"
|
||||
app:layout_constraintBottom_toTopOf="@id/storiesList"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:background="#0000">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
@ -123,7 +128,6 @@
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="@color/btn_green_background" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnBackward"
|
||||
@ -144,7 +148,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
app:layout_constraintTop_toBottomOf="@id/story_container"
|
||||
app:layout_constraintTop_toBottomOf="@id/postActions"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/btnForward"
|
||||
app:layout_constraintStart_toEndOf="@id/btnBackward" />
|
||||
|
@ -113,6 +113,7 @@
|
||||
android:paddingEnd="@dimen/dm_message_card_radius"
|
||||
android:paddingBottom="4dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constraintBottom_toTopOf="@id/chat_message_layout"
|
||||
app:layout_constraintEnd_toEndOf="@id/chat_message_layout"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
|
@ -15,6 +15,7 @@
|
||||
android:paddingEnd="@dimen/dm_message_card_radius"
|
||||
android:paddingBottom="@dimen/dm_message_card_radius_small"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/white"
|
||||
tools:text="Some message" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
@ -35,6 +36,7 @@
|
||||
android:paddingTop="@dimen/dm_message_card_radius_small"
|
||||
android:paddingEnd="@dimen/dm_message_card_radius"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/white"
|
||||
tools:text="Title of the website" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
@ -46,6 +48,7 @@
|
||||
android:paddingStart="@dimen/dm_message_card_radius"
|
||||
android:paddingTop="@dimen/dm_message_card_radius_small"
|
||||
android:paddingEnd="@dimen/dm_message_card_radius"
|
||||
android:textColor="@color/white"
|
||||
tools:text="Some summary of the website" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
@ -59,5 +62,6 @@
|
||||
android:paddingEnd="@dimen/dm_message_card_radius"
|
||||
android:paddingBottom="@dimen/dm_message_card_radius_small"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||
android:textColor="@color/white"
|
||||
tools:text="test.com" />
|
||||
</LinearLayout>
|
@ -86,6 +86,7 @@
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="0dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@id/caption"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -101,6 +102,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -27,7 +27,7 @@
|
||||
android:ellipsize="end"
|
||||
android:gravity="bottom"
|
||||
android:singleLine="true"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constrainedWidth="true"
|
||||
@ -62,12 +62,14 @@
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/white"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/barrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/username"
|
||||
app:layout_constraintTop_toBottomOf="@id/username"
|
||||
tools:text="Full name" />
|
||||
tools:text="Full name"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier"
|
||||
|
@ -78,6 +78,7 @@
|
||||
android:layout_marginEnd="4dp"
|
||||
android:padding="8dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/preview"
|
||||
|
@ -41,5 +41,6 @@
|
||||
android:layout_gravity="start|fill_horizontal"
|
||||
android:padding="8dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/white"
|
||||
tools:text="Some text " />
|
||||
</LinearLayout>
|
@ -9,4 +9,5 @@
|
||||
android:paddingEnd="@dimen/dm_message_card_radius"
|
||||
android:paddingBottom="@dimen/dm_message_card_radius_small"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/white"
|
||||
tools:text="Text message" />
|
@ -66,10 +66,12 @@
|
||||
android:layout_height="54dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:waveformBackgroundColor="?dmWaveformBgColor"
|
||||
app:layout_constraintBottom_toTopOf="@id/duration"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/play_wrapper"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:waveformProgressColor="?dmWaveformProgressColor" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/duration"
|
||||
|
@ -15,25 +15,25 @@
|
||||
android:layout_height="@dimen/profile_picture_size"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
app:actualImageScaleType="centerCrop"
|
||||
app:layout_constraintEnd_toStartOf="@id/mainLocPostCount"
|
||||
app:layout_constraintEnd_toStartOf="@id/btnMap"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:background="@mipmap/ic_launcher" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/mainLocPostCount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat"
|
||||
app:layout_constraintBottom_toTopOf="@id/btnMap"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/mainLocationImage"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="35 Posts" />
|
||||
<!-- <androidx.appcompat.widget.AppCompatTextView-->
|
||||
<!-- android:id="@+id/mainLocPostCount"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="0dp"-->
|
||||
<!-- android:gravity="center_vertical"-->
|
||||
<!-- android:maxLines="1"-->
|
||||
<!-- android:paddingStart="12dp"-->
|
||||
<!-- android:paddingEnd="12dp"-->
|
||||
<!-- android:textAppearance="@style/TextAppearance.AppCompat"-->
|
||||
<!-- app:layout_constraintBottom_toTopOf="@id/btnMap"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintStart_toEndOf="@id/mainLocationImage"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
||||
<!-- tools:text="35 Posts" />-->
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/btnMap"
|
||||
@ -44,9 +44,8 @@
|
||||
app:chipBackgroundColor="@null"
|
||||
app:chipIcon="@drawable/ic_outline_map_24"
|
||||
app:chipIconTint="@color/green_500"
|
||||
app:layout_constraintBottom_toTopOf="@id/locationFullName"
|
||||
app:layout_constraintTop_toTopOf="@id/mainLocationImage"
|
||||
app:layout_constraintStart_toEndOf="@id/mainLocationImage"
|
||||
app:layout_constraintTop_toBottomOf="@id/mainLocPostCount"
|
||||
app:rippleColor="@color/grey_500"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@ -60,8 +59,8 @@
|
||||
app:chipIcon="@drawable/ic_outline_star_plus_24"
|
||||
app:chipIconTint="@color/yellow_800"
|
||||
app:layout_constraintBottom_toBottomOf="@id/mainLocationImage"
|
||||
app:layout_constraintStart_toEndOf="@id/btnMap"
|
||||
app:layout_constraintTop_toBottomOf="@id/mainLocPostCount"
|
||||
app:layout_constraintStart_toEndOf="@id/mainLocationImage"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnMap"
|
||||
app:rippleColor="@color/yellow_400" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
@ -90,27 +89,10 @@
|
||||
android:padding="8dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
app:layout_constraintBottom_toTopOf="@id/locationUrl"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/locationFullName"
|
||||
tools:text="IN THE MIDDLE OF OUR STREET" />
|
||||
|
||||
<awais.instagrabber.customviews.RamboTextViewV2
|
||||
android:id="@+id/locationUrl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/locationBiography"
|
||||
android:ellipsize="marquee"
|
||||
android:padding="8dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/locationBiography"
|
||||
tools:text="https://austinhuang.me/"
|
||||
tools:textColor="@android:color/holo_blue_dark"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -36,6 +36,7 @@
|
||||
app:chipIconTint="@color/deep_purple_200"
|
||||
app:layout_constraintBottom_toTopOf="@id/fav_chip"
|
||||
app:layout_constraintStart_toEndOf="@id/mainProfileImage"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:rippleColor="@color/purple_200"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@ -50,6 +51,7 @@
|
||||
app:chipBackgroundColor="@null"
|
||||
app:layout_constraintBottom_toTopOf="@id/fav_chip"
|
||||
app:layout_constraintStart_toEndOf="@id/btnFollow"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="omg what do u expect"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@ -66,6 +68,7 @@
|
||||
app:chipIconTint="@color/blue_700"
|
||||
app:layout_constraintBottom_toTopOf="@id/fav_chip"
|
||||
app:layout_constraintStart_toEndOf="@id/mainStatus"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:rippleColor="@color/blue_A400"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@ -81,6 +84,7 @@
|
||||
app:chipIconTint="@color/red_600"
|
||||
app:layout_constraintBottom_toTopOf="@id/fav_chip"
|
||||
app:layout_constraintStart_toEndOf="@id/btnSaved"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:rippleColor="@color/red_300"
|
||||
tools:visibility="visible" />
|
||||
|
||||
@ -109,6 +113,7 @@
|
||||
app:chipBackgroundColor="@null"
|
||||
app:chipIcon="@drawable/ic_outline_person_pin_24"
|
||||
app:chipIconTint="@color/deep_orange_800"
|
||||
app:layout_constraintBottom_toTopOf="@+id/mainFullName"
|
||||
app:layout_constraintStart_toEndOf="@id/mainProfileImage"
|
||||
app:layout_constraintTop_toBottomOf="@id/fav_chip"
|
||||
app:rippleColor="@color/deep_orange_400"
|
||||
@ -124,6 +129,7 @@
|
||||
app:chipBackgroundColor="@null"
|
||||
app:chipIcon="@drawable/ic_round_send_24"
|
||||
app:chipIconTint="@color/green"
|
||||
app:layout_constraintBottom_toTopOf="@+id/mainFullName"
|
||||
app:layout_constraintStart_toEndOf="@id/btnTagged"
|
||||
app:layout_constraintTop_toBottomOf="@id/fav_chip"
|
||||
app:rippleColor="@color/green"
|
||||
@ -161,6 +167,23 @@
|
||||
app:srcCompat="@drawable/verified"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/isPrivate"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:tint="@color/red_500"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/mainFullName"
|
||||
app:layout_constraintStart_toEndOf="@id/isVerified"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnTagged"
|
||||
app:srcCompat="@drawable/lock"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/fav_cb"
|
||||
android:layout_width="wrap_content"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user