Compare commits
323 commits
fullscreen
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
fdd759b241 | ||
|
57cd649c02 | ||
|
7250435d7f | ||
|
b81abf74a1 | ||
|
208e2c2d42 | ||
|
a5bdd1c042 | ||
|
1e3a74cae1 | ||
|
ca08f71a72 | ||
|
b60ca39df1 | ||
|
696bc86b7c | ||
|
4c163c6244 | ||
|
2ad49ca281 | ||
|
56caeef72b | ||
|
84bb014557 | ||
|
9278e74e85 | ||
|
cf6f09c60d | ||
|
f2cbed48d9 | ||
|
f1ead0c247 | ||
|
5f2c72ec4d | ||
|
a6869eb2e6 | ||
|
cbae6c476a | ||
|
48d257ceaf | ||
|
5355456498 | ||
|
1436895ace | ||
|
6e32f7724f | ||
|
3f5104d60a | ||
|
d8fdb3b818 | ||
|
5c187e7a8d | ||
|
24862550a1 | ||
|
146fced44e | ||
|
d535ed8c98 | ||
|
b675dbad9b | ||
|
dabe9fe691 | ||
|
9ac216504d | ||
|
911ca998e7 | ||
|
36c105d3a7 | ||
|
a655d0112b | ||
|
493c771e94 | ||
|
e9d70dbf87 | ||
|
0849ce2b66 | ||
|
d0a8b3b218 | ||
|
a8cdc4a771 | ||
|
67b883660f | ||
|
f328efb831 | ||
|
b2f56364d6 | ||
|
2761857fe8 | ||
|
d439260d69 | ||
|
f0f0a5028b | ||
|
13e170cb61 | ||
|
127d8052ca | ||
|
1b3086572f | ||
|
6fa308ef96 | ||
|
f3e513fc2d | ||
|
d72a8faec4 | ||
|
fdb4578349 | ||
|
c08237d399 | ||
|
bdf8a58818 | ||
|
e1d51c881a | ||
|
28212808f8 | ||
|
74f08f8f98 | ||
|
cb5c29fbce | ||
|
4d775d3a17 | ||
|
fd94ef9fa7 | ||
|
2e0331305a | ||
|
fb560f8f01 | ||
|
ef80c9f7fd | ||
|
99a4a0a22f | ||
|
136853853a | ||
|
ebf3299c30 | ||
|
036b49a871 | ||
|
67d5f88d34 | ||
|
b1e0b9af33 | ||
|
c30b012787 | ||
|
c8c6305757 | ||
|
ee1d090e62 | ||
|
9e56a86492 | ||
|
e6b83877f1 | ||
|
b567e39aef | ||
|
ae62dba0a6 | ||
|
df1e8abf50 | ||
|
31cfb26c3b | ||
|
e5f34dc464 | ||
|
601031e55d | ||
|
a9aadbe6a8 | ||
|
f9a4b71037 | ||
|
0f10e9dc1f | ||
|
0647deb06c | ||
|
b2f5fec293 | ||
|
daf4e5aca2 | ||
|
c1324efb41 | ||
|
6221de2d3c | ||
|
983bc68af2 | ||
|
f1b167693d | ||
|
68ac64b534 | ||
|
6819ae46f9 | ||
|
6c406c5a85 | ||
|
c179243d22 | ||
|
d0f5504c80 | ||
|
896c566a02 | ||
|
da9352cc68 | ||
|
b8d2375e20 | ||
|
dd52ff9d07 | ||
|
d9891f8a8a | ||
|
ea5fe6842d | ||
|
fc649187df | ||
|
b0f7c41885 | ||
|
45935717c8 | ||
|
ac5e666369 | ||
|
ffeb72a383 | ||
|
0ec09d751c | ||
|
b8e4fcff92 | ||
|
b79f0f4820 | ||
|
a1cd58a214 | ||
|
cfca8facbe | ||
|
066a0a099c | ||
|
afeee2e5df | ||
|
76036acfc7 | ||
|
897bfdaffd | ||
|
7475ae323c | ||
|
faf7f3ccbf | ||
|
4940d1ca33 | ||
|
3d48fa5741 | ||
|
f9887cffae | ||
|
6644907665 | ||
|
5f850685d6 | ||
|
5f9674e49c | ||
|
0d185c6db3 | ||
|
53d22dd22d | ||
|
ff8ffda3c6 | ||
|
64bd540322 | ||
|
919f9a48f3 | ||
|
746d442051 | ||
|
1877b75188 | ||
|
6e8c38cace | ||
|
eab7bab267 | ||
|
aab648c3cf | ||
|
f79ff509bd | ||
|
1197e990ca | ||
|
dce1c0715e | ||
|
6a0263c5bc | ||
|
ca64db0499 | ||
|
a5d4eda4d1 | ||
|
5d210961c1 | ||
|
1b88f565af | ||
|
991a98b571 | ||
|
0073277d6e | ||
|
eeca602f7a | ||
|
6c171560fd | ||
|
66c4c00215 | ||
|
9b9ef9ab74 | ||
|
39a289e7f1 | ||
|
722c829502 | ||
|
7ecb80d136 | ||
|
ea19af04d4 | ||
|
8196b69211 | ||
|
dc861caf6c | ||
|
adb5ffa8d0 | ||
|
d918cb28bd | ||
|
7ce7314ab9 | ||
|
13e5caa0ef | ||
|
ff59a7a89f | ||
|
c3efa4d004 | ||
|
ed50e1300a | ||
|
86dbfd54d1 | ||
|
535120eebd | ||
|
c1106d7186 | ||
|
45be7f2c9b | ||
|
d6baf3d1c8 | ||
|
08c38c1723 | ||
|
af4fa454d3 | ||
|
0620582a4e | ||
|
b11c07e3d1 | ||
|
593b34079c | ||
|
becb533624 | ||
|
8efc0522f2 | ||
|
cead924ca5 | ||
|
f83a043664 | ||
|
e8a0bca5ea | ||
|
1198c2298a | ||
|
7205acb9d6 | ||
|
d21cfd55ab | ||
|
47cbc3624c | ||
|
1f9a0886a0 | ||
|
dd5ea68915 | ||
|
b3bba4d273 | ||
|
10c123ba6a | ||
|
a8ba45b941 | ||
|
3652cdf6bc | ||
|
f2a7a8c439 | ||
|
78d5a99441 | ||
|
6931dbe79c | ||
|
4d024c06cc | ||
|
ddcb190457 | ||
|
dd14b90d7e | ||
|
4b86444478 | ||
|
feb7f260dc | ||
|
74c7a1de4d | ||
|
88a43dc679 | ||
|
1bb5ce72fa | ||
|
b4ce544965 | ||
|
1ec6f6173a | ||
|
8ee19b3f5c | ||
|
1055392b7f | ||
|
c772cf2ead | ||
|
481c50f465 | ||
|
71bc969f2a | ||
|
e4edebfed7 | ||
|
e8a5ab8307 | ||
|
3738f3af21 | ||
|
74d10e4199 | ||
|
080e00becf | ||
|
049d905d7d | ||
|
33094f8c88 | ||
|
6c44e503db | ||
|
fa78c80592 | ||
|
07630ca97b | ||
|
a2b6d4e570 | ||
|
9d6b3ddf81 | ||
|
0a2769859a | ||
|
c4a1ed801a | ||
|
453394bf1b | ||
|
4b7dfba5a1 | ||
|
e699fcf0b3 | ||
|
7e80f707e0 | ||
|
467f037170 | ||
|
89d5b40e5f | ||
|
34fba010e1 | ||
|
d7396bb044 | ||
|
fda0817ad1 | ||
|
895ca75506 | ||
|
a04448ebe8 | ||
|
26ccbf2709 | ||
|
7d6c11a88c | ||
|
8742913c33 | ||
|
8e6e0f0099 | ||
|
a4585de807 | ||
|
6c24749ad5 | ||
|
c73509a4ca | ||
|
673b85b2aa | ||
|
fe6e60cd67 | ||
|
8bcee90d68 | ||
|
084407e129 | ||
|
4a3db5ae20 | ||
|
b36813ebe6 | ||
|
cc1ddfa16e | ||
|
5f1775d478 | ||
|
288e35dd64 | ||
|
d4af28d1c5 | ||
|
37cf85a5f6 | ||
|
c2cbd76f49 | ||
|
3d874435c3 | ||
|
9ed8864f23 | ||
|
61263dd59d | ||
|
2707e135c6 | ||
|
f9de0d7937 | ||
|
f03d58d648 | ||
|
f49a3570e9 | ||
|
1d97f9008d | ||
|
e85ca9114c | ||
|
85ed2da518 | ||
|
dcc91f75cc | ||
|
a40c160ac6 | ||
|
e6861c8436 | ||
|
e6a5d97fb8 | ||
|
ddeb209d51 | ||
|
3283b3a607 | ||
|
83a41ca6ce | ||
|
6c63eb7d66 | ||
|
7cf9de8c2a | ||
|
a859682954 | ||
|
c844c4f896 | ||
|
a49cfe91da | ||
|
2bacba2c87 | ||
|
e473981063 | ||
|
34ea4f216c | ||
|
52e34b3027 | ||
|
c6a6ea0445 | ||
|
59ae6340e1 | ||
|
cbf2aa2311 | ||
|
94b0c7bc01 | ||
|
4c50ffac19 | ||
|
551e736651 | ||
|
0380e35966 | ||
|
5de0906fc1 | ||
|
c2f17b6230 | ||
|
6a3bbe6c0d | ||
|
82307c9f98 | ||
|
d2ec0e2aa1 | ||
|
3951b1080d | ||
|
ef7caeeead | ||
|
7ef8e2029e | ||
|
aaec6ac6a3 | ||
|
731960da7c | ||
|
ac282d2667 | ||
|
7a79601cfc | ||
|
d1167e4d2b | ||
|
613634adcf | ||
|
acbe33c66d | ||
|
053ebbd70b | ||
|
f5dc4fa4e7 | ||
|
343270b757 | ||
|
65f5626aba | ||
|
a051a73c2b | ||
|
6840997793 | ||
|
2c98ed2d8d | ||
|
6a083c4152 | ||
|
b60b5d16c3 | ||
|
52cfe8dc12 | ||
|
737afca031 | ||
|
456f41d28d | ||
|
238f59ad71 | ||
|
cf6d567193 | ||
|
20f8f3852d | ||
|
4bb9f5cb43 | ||
|
540a841255 | ||
|
3544637405 | ||
|
651448dfa1 | ||
|
4bac266b8b | ||
|
f86b61741d | ||
|
6c60d299af | ||
|
08582238c3 | ||
|
b931d0ce7d | ||
|
5e1fc9dbd8 |
306 changed files with 26563 additions and 3485 deletions
1
.github/workflows/deploy.yml
vendored
Normal file
1
.github/workflows/deploy.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -60,8 +60,10 @@ buck-out/
|
||||||
|
|
||||||
# Other Files
|
# Other Files
|
||||||
app/google-services.json
|
app/google-services.json
|
||||||
|
app/twitter.properties
|
||||||
*.log
|
*.log
|
||||||
.vagrant
|
.vagrant
|
||||||
*.hprof
|
*.hprof
|
||||||
app/build
|
app/build
|
||||||
bin
|
bin
|
||||||
|
app/debuglib
|
||||||
|
|
|
@ -8,10 +8,13 @@ build apk:
|
||||||
stage: build
|
stage: build
|
||||||
image: lbry/android-base:platform-28
|
image: lbry/android-base:platform-28
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get -y update && apt-get -y install build-essential ca-certificates curl git gpg-agent openjdk-8-jdk software-properties-common wget zipalign
|
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
|
||||||
|
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
|
||||||
|
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
|
||||||
|
- apt-get -y update && apt-get -y install build-essential ca-certificates curl git gpg-agent openjdk-8-jdk software-properties-common wget zipalign git-secret
|
||||||
|
- git secret reveal
|
||||||
- chmod u+x $CI_PROJECT_DIR/gradlew
|
- chmod u+x $CI_PROJECT_DIR/gradlew
|
||||||
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
|
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
|
||||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- bin/browser-*-release__arm.apk
|
- bin/browser-*-release__arm.apk
|
||||||
|
@ -19,12 +22,7 @@ build apk:
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
script:
|
script:
|
||||||
- export PATH=/usr/bin:$PATH
|
- export PATH=/usr/bin:$PATH
|
||||||
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
|
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
|
||||||
- echo "deb https://dl.bintray.com/sobolevn/deb git-secret main" | tee -a /etc/apt/sources.list
|
|
||||||
- wget -O - https://api.bintray.com/users/sobolevn/keys/gpg/public.key | apt-key add -
|
|
||||||
- apt-get -y update && apt-get -y install git-secret
|
|
||||||
- git secret reveal
|
|
||||||
- yarn
|
|
||||||
- chmod u+x ./release.sh
|
- chmod u+x ./release.sh
|
||||||
- ./release.sh
|
- ./release.sh
|
||||||
- cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null
|
- cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null
|
||||||
|
@ -36,10 +34,15 @@ deploy build.lbry.io:
|
||||||
dependencies:
|
dependencies:
|
||||||
- build apk
|
- build apk
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get -y update && apt-get -y install openjdk-8-jdk
|
- apt-get -y update && apt-get -y install apt-transport-https
|
||||||
|
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
|
||||||
|
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
|
||||||
|
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
|
||||||
|
- apt-get -y update && apt-get -y install openjdk-8-jdk git git-secret
|
||||||
- pip install awscli
|
- pip install awscli
|
||||||
- chmod u+x $CI_PROJECT_DIR/gradlew
|
- chmod u+x $CI_PROJECT_DIR/gradlew
|
||||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
|
- git secret reveal
|
||||||
|
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
|
||||||
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
|
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
|
||||||
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
|
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
|
||||||
script:
|
script:
|
||||||
|
@ -55,10 +58,15 @@ release apk:
|
||||||
dependencies:
|
dependencies:
|
||||||
- build apk
|
- build apk
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get -y update && apt-get -y install openjdk-8-jdk
|
- apt-get -y update && apt-get -y install apt-transport-https
|
||||||
|
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
|
||||||
|
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
|
||||||
|
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
|
||||||
|
- apt-get -y update && apt-get -y install openjdk-8-jdk git git-secret
|
||||||
- pip install awscli githubrelease
|
- pip install awscli githubrelease
|
||||||
|
- git secret reveal
|
||||||
- chmod u+x $CI_PROJECT_DIR/gradlew
|
- chmod u+x $CI_PROJECT_DIR/gradlew
|
||||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
|
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
|
||||||
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
|
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
|
||||||
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
|
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
|
||||||
script:
|
script:
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,2 +1,3 @@
|
||||||
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
|
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
|
||||||
app/google-services.json:896a0bee8294a36d061f10fa926129d8a780528b34d0a2f03113400c4246d67c
|
app/google-services.json:896a0bee8294a36d061f10fa926129d8a780528b34d0a2f03113400c4246d67c
|
||||||
|
app/twitter.properties:01212d70712f2041efb5c814bf30ecbf6f72e1ca5179c7647c4f8cbd995dd033
|
||||||
|
|
18
README.md
18
README.md
|
@ -2,7 +2,7 @@
|
||||||
[![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master)
|
[![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master)
|
||||||
[![GitHub license](https://img.shields.io/github/license/lbryio/lbry-android)](https://github.com/lbryio/lbry-android/blob/master/LICENSE)
|
[![GitHub license](https://img.shields.io/github/license/lbryio/lbry-android)](https://github.com/lbryio/lbry-android/blob/master/LICENSE)
|
||||||
|
|
||||||
An Android browser and wallet for the [LBRY](https://lbry.com) network. This app bundles [LBRY SDK](https://github.com/lbryio/lbry) as a background service with a UI layer built with React Native.
|
An Android browser and wallet for the [LBRY](https://lbry.com) network.
|
||||||
|
|
||||||
|
|
||||||
<img src="https://spee.ch/@lbry:3f/android-08-homepage.gif" alt="LBRY Android GIF" width="384px" />
|
<img src="https://spee.ch/@lbry:3f/android-08-homepage.gif" alt="LBRY Android GIF" width="384px" />
|
||||||
|
@ -18,7 +18,19 @@ The minimum supported Android version is 5.0 Lollipop. There are two ways to ins
|
||||||
The app can be launched by opening **LBRY** from the device's app drawer or via the shortcut on the home screen if that was created upon installation.
|
The app can be launched by opening **LBRY** from the device's app drawer or via the shortcut on the home screen if that was created upon installation.
|
||||||
|
|
||||||
## Running from Source
|
## Running from Source
|
||||||
Please refer to https://github.com/lbryio/lbry-react-native/blob/master/README.md
|
Clone the repository and open the project in Android Studio. Android Studio will automatically run the initial build process.
|
||||||
|
|
||||||
|
Create file 'twitter.properties' in app/ folder with the following content:
|
||||||
|
|
||||||
|
```
|
||||||
|
twitterConsumerKey=XXXXXX
|
||||||
|
|
||||||
|
twitterConsumerSecret=XXXXXX
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the file 'google-services.sample.json' to 'google-services.json' in the app/ folder.
|
||||||
|
|
||||||
|
Click the Sync button and when process finishes, the Run button to launch the app on your simulator or connected debugging device after the build process is complete.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing
|
Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing
|
||||||
|
@ -27,7 +39,7 @@ Contributions to this project are welcome, encouraged, and compensated. For more
|
||||||
This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
|
This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it.
|
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com)
|
The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import com.google.gms.googleservices.GoogleServicesPlugin
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
buildToolsVersion "29.0.1"
|
buildToolsVersion "29.0.2"
|
||||||
flavorDimensions "default"
|
flavorDimensions "default"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
@ -14,12 +16,16 @@ android {
|
||||||
applicationId "io.lbry.browser"
|
applicationId "io.lbry.browser"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 1503
|
versionCode 1701
|
||||||
versionName "0.15.3"
|
versionName "0.17.1"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
exclude 'META-INF/DEPENDENCIES'
|
||||||
|
exclude 'lib/x86_64/darwin/libscrypt.dylib'
|
||||||
|
}
|
||||||
|
|
||||||
productFlavors {
|
productFlavors {
|
||||||
__32bit {
|
__32bit {
|
||||||
versionCode android.defaultConfig.versionCode * 10 + 1
|
versionCode android.defaultConfig.versionCode * 10 + 1
|
||||||
|
@ -36,7 +42,17 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
Properties twitterProps = new Properties()
|
||||||
|
twitterProps.load(project.file('twitter.properties').newDataInputStream())
|
||||||
|
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
|
||||||
|
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
|
||||||
|
}
|
||||||
release {
|
release {
|
||||||
|
Properties twitterProps = new Properties()
|
||||||
|
twitterProps.load(project.file('twitter.properties').newDataInputStream())
|
||||||
|
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
|
||||||
|
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
|
@ -49,35 +65,49 @@ task printVersionName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
all {
|
||||||
|
exclude module: 'httpclient'
|
||||||
|
exclude module: 'commons-logging'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0-rc01'
|
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'com.google.android.material:material:1.2.0-alpha06'
|
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
implementation 'androidx.navigation:navigation-fragment:2.2.2'
|
implementation 'androidx.navigation:navigation-fragment:2.3.1'
|
||||||
implementation 'androidx.navigation:navigation-ui:2.2.2'
|
implementation 'androidx.navigation:navigation-ui:2.3.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
|
implementation 'androidx.webkit:webkit:1.4.0-rc01'
|
||||||
|
implementation 'androidx.camera:camera-core:1.0.0-beta03'
|
||||||
implementation 'androidx.camera:camera-camera2:1.0.0-beta03'
|
implementation 'androidx.camera:camera-camera2:1.0.0-beta03'
|
||||||
implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03'
|
implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03'
|
||||||
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
|
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
|
||||||
|
implementation 'androidx.browser:browser:1.2.0'
|
||||||
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
|
|
||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
|
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
|
||||||
implementation 'com.google.firebase:firebase-analytics:17.4.0'
|
implementation 'com.google.firebase:firebase-analytics:18.0.0'
|
||||||
implementation 'com.google.android.gms:play-services-base:17.2.1'
|
implementation 'com.google.android.gms:play-services-base:17.5.0'
|
||||||
implementation 'com.google.firebase:firebase-messaging:20.1.6'
|
implementation 'com.google.firebase:firebase-messaging:21.0.0'
|
||||||
|
implementation 'com.google.oauth-client:google-oauth-client:1.30.4'
|
||||||
|
|
||||||
|
implementation 'com.android.billingclient:billing:3.0.2'
|
||||||
|
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.11.4'
|
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.2'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-dash:2.11.4'
|
implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.2'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.11.4'
|
implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.2'
|
||||||
implementation 'com.google.android.exoplayer:extension-cast:2.11.4'
|
implementation 'com.google.android.exoplayer:extension-cast:2.12.2'
|
||||||
implementation 'com.google.android.exoplayer:extension-mediasession:2.11.4'
|
implementation 'com.google.android.exoplayer:extension-mediasession:2.12.2'
|
||||||
|
|
||||||
implementation 'com.google.android:flexbox:2.0.1'
|
implementation 'com.google.android:flexbox:2.0.1'
|
||||||
|
|
||||||
|
@ -88,17 +118,27 @@ dependencies {
|
||||||
|
|
||||||
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS'
|
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS'
|
||||||
|
|
||||||
|
implementation 'commons-codec:commons-codec:1.15'
|
||||||
|
implementation 'org.bitcoinj:bitcoinj-tools:0.14.7'
|
||||||
|
implementation 'org.java-websocket:Java-WebSocket:1.5.1'
|
||||||
|
|
||||||
|
implementation ('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
|
||||||
|
implementation 'com.google.zxing:core:3.3.0'
|
||||||
|
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.10'
|
compileOnly 'org.projectlombok:lombok:1.18.10'
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.10'
|
annotationProcessor 'org.projectlombok:lombok:1.18.10'
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test:runner:1.3.0'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test:rules:1.3.0'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
||||||
__32bitImplementation files('libs/lbrysdk-0.74.0-release__arm.aar')
|
__32bitImplementation 'io.lbry:lbrysdk32:0.102.0'
|
||||||
__64bitImplementation files('libs/lbrysdk-0.74.0-release__arm64.aar')
|
__64bitImplementation 'io.lbry:lbrysdk64:0.102.0'
|
||||||
|
//__64bitImplementation(name: 'lbrysdk', ext: 'aar')
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true
|
GoogleServicesPlugin.config.disableVersionCheck = true
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
package io.lbry.browser.utils;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public class HelperTest {
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="io.lbry.browser"
|
package="io.lbry.browser"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
@ -10,6 +11,10 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
|
||||||
|
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -50,12 +55,38 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
<data android:mimeType="text/*" />
|
||||||
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="lbry" />
|
<data android:scheme="lbry" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="https" android:host="open.lbry.com"/>
|
||||||
|
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/..*/*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*:.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*#.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/..*/*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*:.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*#.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/..*/*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*:.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*#.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/..*/*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*:.*" />
|
||||||
|
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*#.*" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -70,6 +101,11 @@
|
||||||
android:theme="@style/AppTheme.NoActionBarTranslucent"
|
android:theme="@style/AppTheme.NoActionBarTranslucent"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
||||||
|
android:screenOrientation="fullSensor"
|
||||||
|
tools:replace="screenOrientation" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="io.lbry.browser.LbrynetMessagingService"
|
android:name="io.lbry.browser.LbrynetMessagingService"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
|
|
BIN
app/src/main/assets/font_awesome_5_free_regular.otf
Normal file
BIN
app/src/main/assets/font_awesome_5_free_regular.otf
Normal file
Binary file not shown.
|
@ -10,20 +10,31 @@ import android.os.Bundle;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.core.text.HtmlCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import io.lbry.browser.exceptions.AuthTokenInvalidatedException;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
import io.lbry.browser.utils.LbryAnalytics;
|
import io.lbry.browser.utils.LbryAnalytics;
|
||||||
import io.lbry.browser.utils.Lbryio;
|
import io.lbry.browser.utils.Lbryio;
|
||||||
|
import io.lbry.lbrysdk.LbrynetService;
|
||||||
|
import io.lbry.lbrysdk.ServiceHelper;
|
||||||
|
import io.lbry.lbrysdk.Utils;
|
||||||
|
|
||||||
public class FirstRunActivity extends AppCompatActivity {
|
public class FirstRunActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private BroadcastReceiver sdkReadyReceiver;
|
private BroadcastReceiver sdkReceiver;
|
||||||
private BroadcastReceiver authReceiver;
|
private BroadcastReceiver authReceiver;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,21 +54,51 @@ public class FirstRunActivity extends AppCompatActivity {
|
||||||
});
|
});
|
||||||
|
|
||||||
registerAuthReceiver();
|
registerAuthReceiver();
|
||||||
if (!Lbry.SDK_READY) {
|
findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE);
|
||||||
findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE);
|
IntentFilter filter = new IntentFilter();
|
||||||
IntentFilter filter = new IntentFilter();
|
filter.addAction(MainActivity.ACTION_SDK_READY);
|
||||||
filter.addAction(MainActivity.ACTION_SDK_READY);
|
filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
|
||||||
sdkReadyReceiver = new BroadcastReceiver() {
|
sdkReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (MainActivity.ACTION_SDK_READY.equals(action)) {
|
||||||
// authenticate after we receive the sdk ready event
|
// authenticate after we receive the sdk ready event
|
||||||
authenticate();
|
authenticate();
|
||||||
|
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
|
||||||
|
finish();
|
||||||
|
if (MainActivity.instance != null) {
|
||||||
|
MainActivity.instance.finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
registerReceiver(sdkReadyReceiver, filter);
|
};
|
||||||
} else {
|
registerReceiver(sdkReceiver, filter);
|
||||||
authenticate();
|
|
||||||
}
|
CheckInstallIdTask task = new CheckInstallIdTask(this, new CheckInstallIdTask.InstallIdHandler() {
|
||||||
|
@Override
|
||||||
|
public void onInstallIdChecked(boolean result) {
|
||||||
|
// start the sdk from FirstRun
|
||||||
|
boolean serviceRunning = MainActivity.isServiceRunning(MainActivity.instance, LbrynetService.class);
|
||||||
|
if (!serviceRunning) {
|
||||||
|
Lbry.SDK_READY = false;
|
||||||
|
ServiceHelper.start(MainActivity.instance, "", LbrynetService.class, "lbrynetservice");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// install_id generated and validated, authenticate now
|
||||||
|
authenticate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we weren't able to generate the install_id ourselves, depend on the sdk for that
|
||||||
|
if (Lbry.SDK_READY) {
|
||||||
|
authenticate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
|
@ -97,7 +138,8 @@ public class FirstRunActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleAuthenticationFailed() {
|
private void handleAuthenticationFailed() {
|
||||||
Toast.makeText(this, "Authentication failed.", Toast.LENGTH_LONG).show();
|
findViewById(R.id.welcome_progress_bar).setVisibility(View.GONE);
|
||||||
|
((TextView) findViewById(R.id.welcome_wait_text)).setText(R.string.startup_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void authenticate() {
|
private void authenticate() {
|
||||||
|
@ -121,17 +163,89 @@ public class FirstRunActivity extends AppCompatActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
Helper.unregisterReceiver(authReceiver, this);
|
Helper.unregisterReceiver(authReceiver, this);
|
||||||
Helper.unregisterReceiver(sdkReadyReceiver, this);
|
Helper.unregisterReceiver(sdkReceiver, this);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateIdAndAuthenticate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CheckInstallIdTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
private final Context context;
|
||||||
|
private final InstallIdHandler handler;
|
||||||
|
public CheckInstallIdTask(Context context, InstallIdHandler handler) {
|
||||||
|
this.context = context;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
// Load the installation id from the file system
|
||||||
|
String lbrynetDir = String.format("%s/%s", Utils.getAppInternalStorageDir(context), "lbrynet");
|
||||||
|
File dir = new File(lbrynetDir);
|
||||||
|
boolean dirExists = dir.isDirectory();
|
||||||
|
if (!dirExists) {
|
||||||
|
dirExists = dir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dirExists) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String installIdPath = String.format("%s/install_id", lbrynetDir);
|
||||||
|
File file = new File(installIdPath);
|
||||||
|
String installId = null;
|
||||||
|
if (!file.exists()) {
|
||||||
|
// generate the install_id
|
||||||
|
installId = Lbry.generateId();
|
||||||
|
BufferedWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new BufferedWriter(new FileWriter(file));
|
||||||
|
writer.write(installId);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
Helper.closeCloseable(writer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// read the installation id from the file
|
||||||
|
BufferedReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(new InputStreamReader(new FileInputStream(installIdPath)));
|
||||||
|
installId = reader.readLine();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
Helper.closeCloseable(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Helper.isNullOrEmpty(installId)) {
|
||||||
|
Lbry.INSTALLATION_ID = installId;
|
||||||
|
}
|
||||||
|
return !Helper.isNullOrEmpty(installId);
|
||||||
|
}
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
if (handler != null) {
|
||||||
|
handler.onInstallIdChecked(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface InstallIdHandler {
|
||||||
|
void onInstallIdChecked(boolean result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class AuthenticateTask extends AsyncTask<Void, Void, Void> {
|
private static class AuthenticateTask extends AsyncTask<Void, Void, Void> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
public AuthenticateTask(Context context) {
|
public AuthenticateTask(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
Lbryio.authenticate(context);
|
try {
|
||||||
|
Lbryio.authenticate(context);
|
||||||
|
} catch (AuthTokenInvalidatedException ex) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
@ -20,19 +21,22 @@ import com.google.firebase.analytics.FirebaseAnalytics;
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||||
import com.google.firebase.messaging.RemoteMessage;
|
import com.google.firebase.messaging.RemoteMessage;
|
||||||
|
|
||||||
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
|
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.LbryAnalytics;
|
import io.lbry.browser.utils.LbryAnalytics;
|
||||||
import io.lbry.lbrysdk.LbrynetService;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class LbrynetMessagingService extends FirebaseMessagingService {
|
public class LbrynetMessagingService extends FirebaseMessagingService {
|
||||||
|
public static final String ACTION_NOTIFICATION_RECEIVED = "io.lbry.browser.Broadcast.NotificationReceived";
|
||||||
|
|
||||||
private static final String TAG = "LbrynetMessagingService";
|
private static final String TAG = "LbrynetMessagingService";
|
||||||
private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
|
private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
|
||||||
|
private static final String TYPE_COMMENT = "comment";
|
||||||
private static final String TYPE_SUBSCRIPTION = "subscription";
|
private static final String TYPE_SUBSCRIPTION = "subscription";
|
||||||
private static final String TYPE_REWARD = "reward";
|
private static final String TYPE_REWARD = "reward";
|
||||||
private static final String TYPE_INTERESTS = "interests";
|
private static final String TYPE_INTERESTS = "interests";
|
||||||
|
@ -52,12 +56,9 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
||||||
String title = payload.get("title");
|
String title = payload.get("title");
|
||||||
String body = payload.get("body");
|
String body = payload.get("body");
|
||||||
String name = payload.get("name"); // notification name
|
String name = payload.get("name"); // notification name
|
||||||
String contentTitle = payload.get("content_title");
|
String hash = payload.get("hash"); // comment hash
|
||||||
String channelUrl = payload.get("channel_url");
|
|
||||||
//String publishTime = payload.get("publish_time");
|
|
||||||
String publishTime = null;
|
|
||||||
|
|
||||||
if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) {
|
if (type != null && getEnabledTypes().contains(type) && body != null && body.trim().length() > 0) {
|
||||||
// only log the receive event for valid notifications received
|
// only log the receive event for valid notifications received
|
||||||
if (firebaseAnalytics != null) {
|
if (firebaseAnalytics != null) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
|
@ -65,14 +66,41 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
||||||
firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
|
firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime);
|
if (!Helper.isNullOrEmpty(hash)) {
|
||||||
|
url = String.format("%s?comment_hash=%s", url, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNotification(title, body, type, url, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// persist the notification data
|
||||||
|
try {
|
||||||
|
DatabaseHelper helper = DatabaseHelper.getInstance();
|
||||||
|
SQLiteDatabase db = helper.getWritableDatabase();
|
||||||
|
LbryNotification lnotification = new LbryNotification();
|
||||||
|
lnotification.setTitle(title);
|
||||||
|
lnotification.setDescription(body);
|
||||||
|
lnotification.setTargetUrl(url);
|
||||||
|
lnotification.setTimestamp(new Date());
|
||||||
|
DatabaseHelper.createOrUpdateNotification(lnotification, db);
|
||||||
|
|
||||||
|
// send a broadcast
|
||||||
|
Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED);
|
||||||
|
intent.putExtra("title", title);
|
||||||
|
intent.putExtra("body", body);
|
||||||
|
intent.putExtra("url", url);
|
||||||
|
intent.putExtra("timestamp", lnotification.getTimestamp().getTime());
|
||||||
|
sendBroadcast(intent);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// don't fail if any error occurs while saving a notification
|
||||||
|
Log.e(TAG, "could not save notification", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewToken(String token) {
|
public void onNewToken(String token) {
|
||||||
Log.d(TAG, "Refreshed token: " + token);
|
//Log.d(TAG, "Refreshed token: " + token);
|
||||||
|
|
||||||
// If you want to send messages to this application instance or
|
// If you want to send messages to this application instance or
|
||||||
// manage this apps subscriptions on the server side, send the
|
// manage this apps subscriptions on the server side, send the
|
||||||
|
@ -97,8 +125,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
||||||
*
|
*
|
||||||
* @param messageBody FCM message body received.
|
* @param messageBody FCM message body received.
|
||||||
*/
|
*/
|
||||||
private void sendNotification(String title, String messageBody, String type, String url, String name,
|
private void sendNotification(String title, String messageBody, String type, String url, String name) {
|
||||||
String contentTitle, String channelUrl, String publishTime) {
|
|
||||||
//Intent intent = new Intent(this, MainActivity.class);
|
//Intent intent = new Intent(this, MainActivity.class);
|
||||||
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
|
@ -143,6 +170,9 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
||||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
List<String> enabledTypes = new ArrayList<String>();
|
List<String> enabledTypes = new ArrayList<String>();
|
||||||
|
|
||||||
|
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_COMMENTS, true)) {
|
||||||
|
enabledTypes.add(TYPE_COMMENT);
|
||||||
|
}
|
||||||
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) {
|
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) {
|
||||||
enabledTypes.add(TYPE_SUBSCRIPTION);
|
enabledTypes.add(TYPE_SUBSCRIPTION);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,25 +1,47 @@
|
||||||
package io.lbry.browser;
|
package io.lbry.browser;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
|
import com.android.billingclient.api.BillingClient;
|
||||||
|
import com.android.billingclient.api.BillingClientStateListener;
|
||||||
|
import com.android.billingclient.api.BillingFlowParams;
|
||||||
|
import com.android.billingclient.api.BillingResult;
|
||||||
|
import com.android.billingclient.api.Purchase;
|
||||||
|
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||||
|
import com.android.billingclient.api.SkuDetails;
|
||||||
|
import com.android.billingclient.api.SkuDetailsParams;
|
||||||
|
import com.android.billingclient.api.SkuDetailsResponseListener;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.lbry.browser.adapter.VerificationPagerAdapter;
|
import io.lbry.browser.adapter.VerificationPagerAdapter;
|
||||||
|
import io.lbry.browser.listener.SdkStatusListener;
|
||||||
import io.lbry.browser.listener.SignInListener;
|
import io.lbry.browser.listener.SignInListener;
|
||||||
import io.lbry.browser.listener.WalletSyncListener;
|
import io.lbry.browser.listener.WalletSyncListener;
|
||||||
|
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||||
import io.lbry.browser.model.lbryinc.User;
|
import io.lbry.browser.model.lbryinc.User;
|
||||||
|
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||||
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
|
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.LbryAnalytics;
|
import io.lbry.browser.utils.LbryAnalytics;
|
||||||
import io.lbry.browser.utils.Lbryio;
|
import io.lbry.browser.utils.Lbryio;
|
||||||
|
import io.lbry.lbrysdk.LbrynetService;
|
||||||
|
|
||||||
public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener {
|
public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener {
|
||||||
|
|
||||||
|
@ -27,14 +49,66 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
public static final int VERIFICATION_FLOW_REWARDS = 2;
|
public static final int VERIFICATION_FLOW_REWARDS = 2;
|
||||||
public static final int VERIFICATION_FLOW_WALLET = 3;
|
public static final int VERIFICATION_FLOW_WALLET = 3;
|
||||||
|
|
||||||
|
private List<SdkStatusListener> sdkStatusListeners;
|
||||||
|
private BillingClient billingClient;
|
||||||
|
private BroadcastReceiver sdkReceiver;
|
||||||
private String email;
|
private String email;
|
||||||
private boolean signedIn;
|
private boolean signedIn;
|
||||||
private int flow;
|
private int flow;
|
||||||
|
|
||||||
|
private final PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
|
||||||
|
@Override
|
||||||
|
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
|
||||||
|
int responseCode = billingResult.getResponseCode();
|
||||||
|
if (responseCode == BillingClient.BillingResponseCode.OK && purchases != null)
|
||||||
|
{
|
||||||
|
for (Purchase purchase : purchases) {
|
||||||
|
if (MainActivity.SKU_SKIP.equalsIgnoreCase(purchase.getSku())) {
|
||||||
|
showLoading();
|
||||||
|
MainActivity.handleBillingPurchase(
|
||||||
|
purchase,
|
||||||
|
billingClient,
|
||||||
|
VerificationActivity.this, null, new RewardVerifiedHandler() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(RewardVerified rewardVerified) {
|
||||||
|
if (Lbryio.currentUser != null) {
|
||||||
|
Lbryio.currentUser.setRewardApproved(rewardVerified.isRewardApproved());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rewardVerified.isRewardApproved()) {
|
||||||
|
// show pending purchase message (possible slow card tx)
|
||||||
|
Snackbar.make(findViewById(R.id.verification_pager), R.string.purchase_request_pending, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
new Handler().postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception error) {
|
||||||
|
showFetchUserError(getString(R.string.purchase_request_failed_error));
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
sdkStatusListeners = new ArrayList<>();
|
||||||
|
|
||||||
signedIn = Lbryio.isSignedIn();
|
signedIn = Lbryio.isSignedIn();
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
|
@ -54,6 +128,32 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
|
||||||
|
filter.addAction(MainActivity.ACTION_SDK_READY);
|
||||||
|
sdkReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (MainActivity.ACTION_SDK_READY.equals(action)) {
|
||||||
|
for (SdkStatusListener listener : sdkStatusListeners) {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onSdkReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
registerReceiver(sdkReceiver, filter);
|
||||||
|
|
||||||
|
billingClient = BillingClient.newBuilder(this)
|
||||||
|
.setListener(purchasesUpdatedListener)
|
||||||
|
.enablePendingPurchases()
|
||||||
|
.build();
|
||||||
|
establishBillingClientConnection();
|
||||||
|
|
||||||
setContentView(R.layout.activity_verification);
|
setContentView(R.layout.activity_verification);
|
||||||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||||
viewPager.setUserInputEnabled(false);
|
viewPager.setUserInputEnabled(false);
|
||||||
|
@ -70,6 +170,24 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void establishBillingClientConnection() {
|
||||||
|
if (billingClient != null) {
|
||||||
|
billingClient.startConnection(new BillingClientStateListener() {
|
||||||
|
@Override
|
||||||
|
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
|
||||||
|
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||||
|
// no need to do anything here. purchases are always checked server-side
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBillingServiceDisconnected() {
|
||||||
|
establishBillingClientConnection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
|
LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
|
||||||
|
@ -85,14 +203,17 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
flowHandled = true;
|
flowHandled = true;
|
||||||
} else if (flow == VERIFICATION_FLOW_REWARDS) {
|
} else if (flow == VERIFICATION_FLOW_REWARDS) {
|
||||||
User user = Lbryio.currentUser;
|
User user = Lbryio.currentUser;
|
||||||
|
// disable phone verification for now
|
||||||
if (!user.isIdentityVerified()) {
|
if (!user.isIdentityVerified()) {
|
||||||
// phone number verification required
|
// phone number verification required
|
||||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||||
flowHandled = true;
|
flowHandled = true;
|
||||||
} else if (!user.isRewardApproved()) {
|
} else {
|
||||||
// manual verification required
|
if (!user.isRewardApproved()) {
|
||||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
// manual verification required
|
||||||
flowHandled = true;
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||||
|
flowHandled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +226,11 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showPhoneVerification() {
|
||||||
|
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||||
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||||
|
}
|
||||||
|
|
||||||
public void showLoading() {
|
public void showLoading() {
|
||||||
findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE);
|
findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE);
|
||||||
findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE);
|
findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE);
|
||||||
|
@ -118,8 +244,12 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
// ignore back press
|
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||||
return;
|
|
||||||
|
if (viewPager.getCurrentItem() != VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL)
|
||||||
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL);
|
||||||
|
else
|
||||||
|
super.onBackPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEmailAdded(String email) {
|
public void onEmailAdded(String email) {
|
||||||
|
@ -148,7 +278,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
|
|
||||||
// only sign in required, don't do anything else
|
// only sign in required, don't do anything else
|
||||||
showLoading();
|
showLoading();
|
||||||
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
|
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(User user) {
|
public void onSuccess(User user) {
|
||||||
Lbryio.currentUser = user;
|
Lbryio.currentUser = user;
|
||||||
|
@ -158,7 +288,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Exception error) {
|
public void onError(Exception error) {
|
||||||
showFetchUserError(error.getMessage());
|
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
|
||||||
hideLoading();
|
hideLoading();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -166,7 +296,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
} else {
|
} else {
|
||||||
// change pager view depending on flow
|
// change pager view depending on flow
|
||||||
showLoading();
|
showLoading();
|
||||||
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
|
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(User user) {
|
public void onSuccess(User user) {
|
||||||
hideLoading();
|
hideLoading();
|
||||||
|
@ -179,13 +309,15 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
if (!user.isIdentityVerified()) {
|
if (!user.isIdentityVerified()) {
|
||||||
// phone number verification required
|
// phone number verification required
|
||||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||||
} else if (!user.isRewardApproved()) {
|
|
||||||
// manual verification required
|
|
||||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
|
||||||
} else {
|
} else {
|
||||||
// fully verified
|
if (!user.isRewardApproved()) {
|
||||||
setResult(RESULT_OK);
|
// manual verification required
|
||||||
finish();
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||||
|
} else {
|
||||||
|
// fully verified
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (flow == VERIFICATION_FLOW_WALLET) {
|
} else if (flow == VERIFICATION_FLOW_WALLET) {
|
||||||
// for wallet sync, if password unlock is required, show password entry page
|
// for wallet sync, if password unlock is required, show password entry page
|
||||||
|
@ -194,7 +326,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onError(Exception error) {
|
public void onError(Exception error) {
|
||||||
showFetchUserError(error.getMessage());
|
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
|
||||||
hideLoading();
|
hideLoading();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -210,7 +342,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
@Override
|
@Override
|
||||||
public void onPhoneVerified() {
|
public void onPhoneVerified() {
|
||||||
showLoading();
|
showLoading();
|
||||||
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
|
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(User user) {
|
public void onSuccess(User user) {
|
||||||
Lbryio.currentUser = user;
|
Lbryio.currentUser = user;
|
||||||
|
@ -223,6 +355,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
||||||
// show manual verification page if the user is still not reward approved
|
// show manual verification page if the user is still not reward approved
|
||||||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||||
|
@ -231,7 +364,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Exception error) {
|
public void onError(Exception error) {
|
||||||
showFetchUserError(error.getMessage());
|
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
|
||||||
hideLoading();
|
hideLoading();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -269,4 +402,68 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
||||||
public void onWalletSyncFailed(Exception error) {
|
public void onWalletSyncFailed(Exception error) {
|
||||||
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSkipQueueAction() {
|
||||||
|
if (billingClient != null) {
|
||||||
|
List<String> skuList = new ArrayList<>();
|
||||||
|
skuList.add(MainActivity.SKU_SKIP);
|
||||||
|
|
||||||
|
SkuDetailsParams detailsParams = SkuDetailsParams.newBuilder().
|
||||||
|
setType(BillingClient.SkuType.INAPP).
|
||||||
|
setSkusList(skuList).build();
|
||||||
|
billingClient.querySkuDetailsAsync(detailsParams, new SkuDetailsResponseListener() {
|
||||||
|
@Override
|
||||||
|
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
|
||||||
|
if (list != null && list.size() > 0) {
|
||||||
|
// we only queried one product, so it should be the first item in the list
|
||||||
|
SkuDetails skuDetails = list.get(0);
|
||||||
|
|
||||||
|
// launch the billing flow for skip queue
|
||||||
|
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().
|
||||||
|
setSkuDetails(skuDetails).build();
|
||||||
|
billingClient.launchBillingFlow(VerificationActivity.this, billingFlowParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTwitterVerified() {
|
||||||
|
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
new Handler().postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onManualProgress(boolean progress) {
|
||||||
|
if (progress) {
|
||||||
|
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
Helper.unregisterReceiver(sdkReceiver, this);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSdkStatusListener(SdkStatusListener listener) {
|
||||||
|
if (!sdkStatusListeners.contains(listener)) {
|
||||||
|
sdkStatusListeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSdkStatusListener(SdkStatusListener listener) {
|
||||||
|
sdkStatusListeners.remove(listener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilterListAdapter.ViewHolder> {
|
public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilterListAdapter.ViewHolder> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Claim> items;
|
private List<Claim> items;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@ -42,12 +42,12 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected View mediaContainer;
|
protected final View mediaContainer;
|
||||||
protected View alphaContainer;
|
protected final View alphaContainer;
|
||||||
protected View allView;
|
protected final View allView;
|
||||||
protected ImageView thumbnailView;
|
protected final ImageView thumbnailView;
|
||||||
protected TextView alphaView;
|
protected final TextView alphaView;
|
||||||
protected TextView titleView;
|
protected final TextView titleView;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
mediaContainer = v.findViewById(R.id.channel_filter_media_container);
|
mediaContainer = v.findViewById(R.id.channel_filter_media_container);
|
||||||
|
@ -95,13 +95,13 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
|
||||||
vh.allView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE);
|
vh.allView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
|
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
|
||||||
String thumbnailUrl = claim.getThumbnailUrl();
|
String thumbnailUrl = claim.getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85);
|
||||||
if (!Helper.isNullOrEmpty(thumbnailUrl) && context != null) {
|
if (!Helper.isNullOrEmpty(thumbnailUrl) && context != null) {
|
||||||
Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
|
Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
|
||||||
}
|
}
|
||||||
vh.alphaContainer.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
|
vh.alphaContainer.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
|
||||||
vh.thumbnailView.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.GONE : View.VISIBLE);
|
vh.thumbnailView.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.GONE : View.VISIBLE);
|
||||||
vh.alphaView.setText(claim.isPlaceholder() ? null : claim.getName() != null ? claim.getName().substring(1, 2) : "");
|
vh.alphaView.setText(claim.isPlaceholder() ? null : claim.getName() != null ? claim.getName().substring(1, 2).toUpperCase() : "");
|
||||||
|
|
||||||
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
|
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
|
||||||
Helper.setIconViewBackgroundColor(vh.alphaContainer, bgColor, claim.isPlaceholder(), context);
|
Helper.setIconViewBackgroundColor(vh.alphaContainer, bgColor, claim.isPlaceholder(), context);
|
||||||
|
|
|
@ -8,7 +8,6 @@ import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
@ -22,7 +21,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
import io.lbry.browser.listener.SelectionModeListener;
|
import io.lbry.browser.listener.SelectionModeListener;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
|
@ -38,18 +36,18 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
private static final int VIEW_TYPE_CHANNEL = 2;
|
private static final int VIEW_TYPE_CHANNEL = 2;
|
||||||
private static final int VIEW_TYPE_FEATURED = 3; // featured search result
|
private static final int VIEW_TYPE_FEATURED = 3; // featured search result
|
||||||
|
|
||||||
private Map<String, Claim> quickClaimIdMap;
|
private final Map<String, Claim> quickClaimIdMap;
|
||||||
private Map<String, Claim> quickClaimUrlMap;
|
private final Map<String, Claim> quickClaimUrlMap;
|
||||||
private Map<String, Boolean> notFoundClaimIdMap;
|
private final Map<String, Boolean> notFoundClaimIdMap;
|
||||||
private Map<String, Boolean> notFoundClaimUrlMap;
|
private final Map<String, Boolean> notFoundClaimUrlMap;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private boolean hideFee;
|
private boolean hideFee;
|
||||||
@Setter
|
@Setter
|
||||||
private boolean canEnterSelectionMode;
|
private boolean canEnterSelectionMode;
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Claim> items;
|
private List<Claim> items;
|
||||||
private List<Claim> selectedItems;
|
private final List<Claim> selectedItems;
|
||||||
@Setter
|
@Setter
|
||||||
private ClaimListItemListener listener;
|
private ClaimListItemListener listener;
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -61,7 +59,13 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
|
|
||||||
public ClaimListAdapter(List<Claim> items, Context context) {
|
public ClaimListAdapter(List<Claim> items, Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.items = new ArrayList<>(items);
|
this.items = new ArrayList<>();
|
||||||
|
for (Claim item : items) {
|
||||||
|
if (item != null) {
|
||||||
|
this.items.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.selectedItems = new ArrayList<>();
|
this.selectedItems = new ArrayList<>();
|
||||||
quickClaimIdMap = new HashMap<>();
|
quickClaimIdMap = new HashMap<>();
|
||||||
quickClaimUrlMap = new HashMap<>();
|
quickClaimUrlMap = new HashMap<>();
|
||||||
|
@ -140,7 +144,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
|
|
||||||
public void addItems(List<Claim> claims) {
|
public void addItems(List<Claim> claims) {
|
||||||
for (Claim claim : claims) {
|
for (Claim claim : claims) {
|
||||||
if (!items.contains(claim)) {
|
if (claim != null && !items.contains(claim)) {
|
||||||
items.add(claim);
|
items.add(claim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +154,12 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
public void setItems(List<Claim> claims) {
|
public void setItems(List<Claim> claims) {
|
||||||
items = new ArrayList<>(claims);
|
items = new ArrayList<>();
|
||||||
|
for (Claim claim : claims) {
|
||||||
|
if (claim != null) {
|
||||||
|
items.add(claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,23 +175,27 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected View feeContainer;
|
protected final View feeContainer;
|
||||||
protected TextView feeView;
|
protected final TextView feeView;
|
||||||
protected ImageView thumbnailView;
|
protected final ImageView thumbnailView;
|
||||||
protected View noThumbnailView;
|
protected final View noThumbnailView;
|
||||||
protected TextView alphaView;
|
protected final TextView alphaView;
|
||||||
protected TextView vanityUrlView;
|
protected final TextView vanityUrlView;
|
||||||
protected TextView durationView;
|
protected final TextView durationView;
|
||||||
protected TextView titleView;
|
protected final TextView titleView;
|
||||||
protected TextView publisherView;
|
protected final TextView publisherView;
|
||||||
protected TextView publishTimeView;
|
protected final TextView publishTimeView;
|
||||||
protected TextView pendingTextView;
|
protected final TextView pendingTextView;
|
||||||
protected View repostInfoView;
|
protected final View repostInfoView;
|
||||||
protected TextView repostChannelView;
|
protected final TextView repostChannelView;
|
||||||
protected View selectedOverlayView;
|
protected final View selectedOverlayView;
|
||||||
protected TextView fileSizeView;
|
protected final TextView fileSizeView;
|
||||||
protected ProgressBar downloadProgressView;
|
protected final ProgressBar downloadProgressView;
|
||||||
protected TextView deviceView;
|
protected final TextView deviceView;
|
||||||
|
|
||||||
|
protected final View loadingImagePlaceholder;
|
||||||
|
protected final View loadingTextPlaceholder1;
|
||||||
|
protected final View loadingTextPlaceholder2;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
feeContainer = v.findViewById(R.id.claim_fee_container);
|
feeContainer = v.findViewById(R.id.claim_fee_container);
|
||||||
|
@ -202,6 +215,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
fileSizeView = v.findViewById(R.id.claim_file_size);
|
fileSizeView = v.findViewById(R.id.claim_file_size);
|
||||||
downloadProgressView = v.findViewById(R.id.claim_download_progress);
|
downloadProgressView = v.findViewById(R.id.claim_download_progress);
|
||||||
deviceView = v.findViewById(R.id.claim_view_device);
|
deviceView = v.findViewById(R.id.claim_view_device);
|
||||||
|
|
||||||
|
loadingImagePlaceholder = v.findViewById(R.id.claim_thumbnail_placeholder);
|
||||||
|
loadingTextPlaceholder1 = v.findViewById(R.id.claim_text_loading_placeholder_1);
|
||||||
|
loadingTextPlaceholder2 = v.findViewById(R.id.claim_text_loading_placeholder_2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,29 +315,27 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
return new ClaimListAdapter.ViewHolder(v);
|
return new ClaimListAdapter.ViewHolder(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getScaledValue(int value) {
|
|
||||||
return (int) (value * scale + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
|
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
|
||||||
int type = getItemViewType(position);
|
int type = getItemViewType(position);
|
||||||
int paddingTop = position == 0 ? 16 : 8;
|
int paddingTop = position == 0 ? 16 : 8;
|
||||||
int paddingBottom = position == getItemCount() - 1 ? 16 : 8;
|
int paddingBottom = position == getItemCount() - 1 ? 16 : 8;
|
||||||
int paddingTopScaled = getScaledValue(paddingTop);
|
int paddingTopScaled = Helper.getScaledValue(paddingTop, scale);
|
||||||
int paddingBottomScaled = getScaledValue(paddingBottom);
|
int paddingBottomScaled = Helper.getScaledValue(paddingBottom, scale);
|
||||||
vh.itemView.setPadding(vh.itemView.getPaddingLeft(), paddingTopScaled, vh.itemView.getPaddingRight(), paddingBottomScaled);
|
vh.itemView.setPadding(vh.itemView.getPaddingStart(), paddingTopScaled, vh.itemView.getPaddingEnd(), paddingBottomScaled);
|
||||||
|
|
||||||
Claim original = items.get(position);
|
Claim original = items.get(position);
|
||||||
boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType());
|
boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType());
|
||||||
final Claim item = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType()) ? original.getRepostedClaim() : original;
|
final Claim item = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType()) ?
|
||||||
|
(original.getRepostedClaim() != null ? original.getRepostedClaim() : original): original;
|
||||||
Claim.GenericMetadata metadata = item.getValue();
|
Claim.GenericMetadata metadata = item.getValue();
|
||||||
Claim signingChannel = item.getSigningChannel();
|
Claim signingChannel = item.getSigningChannel();
|
||||||
Claim.StreamMetadata streamMetadata = null;
|
Claim.StreamMetadata streamMetadata = null;
|
||||||
if (metadata instanceof Claim.StreamMetadata) {
|
if (metadata instanceof Claim.StreamMetadata) {
|
||||||
streamMetadata = (Claim.StreamMetadata) metadata;
|
streamMetadata = (Claim.StreamMetadata) metadata;
|
||||||
}
|
}
|
||||||
String thumbnailUrl = item.getThumbnailUrl();
|
|
||||||
|
String thumbnailUrl = item.getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85);
|
||||||
long publishTime = (streamMetadata != null && streamMetadata.getReleaseTime() > 0) ? streamMetadata.getReleaseTime() * 1000 : item.getTimestamp() * 1000;
|
long publishTime = (streamMetadata != null && streamMetadata.getReleaseTime() > 0) ? streamMetadata.getReleaseTime() * 1000 : item.getTimestamp() * 1000;
|
||||||
int bgColor = Helper.generateRandomColorForValue(item.getClaimId());
|
int bgColor = Helper.generateRandomColorForValue(item.getClaimId());
|
||||||
if (bgColor == 0) {
|
if (bgColor == 0) {
|
||||||
|
@ -328,14 +343,17 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isPending = item.getConfirmations() == 0;
|
boolean isPending = item.getConfirmations() == 0;
|
||||||
boolean isSelected = isClaimSelected(item);
|
boolean isSelected = isClaimSelected(original);
|
||||||
vh.itemView.setSelected(isSelected);
|
vh.itemView.setSelected(isSelected);
|
||||||
vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE);
|
vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE);
|
||||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if (isPending) {
|
if (isPending) {
|
||||||
Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG).show();
|
Snackbar snackbar = Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG);
|
||||||
|
TextView snackbarText = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
|
||||||
|
snackbarText.setMaxLines(5);
|
||||||
|
snackbar.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +374,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPending) {
|
if (isPending) {
|
||||||
Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG).show();
|
Snackbar snackbar = Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG);
|
||||||
|
TextView snackbarText = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
|
||||||
|
snackbarText.setMaxLines(5);
|
||||||
|
snackbar.show();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,9 +402,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
});
|
});
|
||||||
|
|
||||||
vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE);
|
vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE);
|
||||||
vh.pendingTextView.setVisibility(isPending ? View.VISIBLE : View.GONE);
|
vh.pendingTextView.setVisibility(isPending && !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
vh.repostInfoView.setVisibility(isRepost ? View.VISIBLE : View.GONE);
|
vh.repostInfoView.setVisibility(isRepost && type != VIEW_TYPE_FEATURED ? View.VISIBLE : View.GONE);
|
||||||
vh.repostChannelView.setText(isRepost ? original.getSigningChannel().getName() : null);
|
vh.repostChannelView.setText(isRepost && original.getSigningChannel() != null ? original.getSigningChannel().getName() : null);
|
||||||
vh.repostChannelView.setOnClickListener(new View.OnClickListener() {
|
vh.repostChannelView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
@ -404,6 +425,13 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
|
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
|
||||||
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
|
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
|
||||||
|
|
||||||
|
Helper.setViewVisibility(vh.loadingImagePlaceholder, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
|
Helper.setViewVisibility(vh.loadingTextPlaceholder1, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
|
Helper.setViewVisibility(vh.loadingTextPlaceholder2, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
|
Helper.setViewVisibility(vh.titleView, !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
|
Helper.setViewVisibility(vh.publisherView, !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||||
|
Helper.setViewVisibility(vh.publishTimeView, !item.isLoadingPlaceholder() && !isPending ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
if (type == VIEW_TYPE_FEATURED && item.isUnresolved()) {
|
if (type == VIEW_TYPE_FEATURED && item.isUnresolved()) {
|
||||||
vh.durationView.setVisibility(View.GONE);
|
vh.durationView.setVisibility(View.GONE);
|
||||||
vh.titleView.setText("Nothing here. Publish something!");
|
vh.titleView.setText("Nothing here. Publish something!");
|
||||||
|
@ -413,6 +441,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
long duration = item.getDuration();
|
long duration = item.getDuration();
|
||||||
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
|
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
|
||||||
Glide.with(context.getApplicationContext()).
|
Glide.with(context.getApplicationContext()).
|
||||||
|
asBitmap().
|
||||||
load(thumbnailUrl).
|
load(thumbnailUrl).
|
||||||
centerCrop().
|
centerCrop().
|
||||||
placeholder(R.drawable.bg_thumbnail_placeholder).
|
placeholder(R.drawable.bg_thumbnail_placeholder).
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
package io.lbry.browser.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
|
|
||||||
|
import io.lbry.browser.R;
|
||||||
|
import io.lbry.browser.model.Claim;
|
||||||
|
import io.lbry.browser.model.ClaimCacheKey;
|
||||||
|
import io.lbry.browser.model.Comment;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
import io.lbry.browser.utils.LbryUri;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
public class CommentListAdapter extends RecyclerView.Adapter<CommentListAdapter.ViewHolder> {
|
||||||
|
private final List<Comment> items;
|
||||||
|
private final Context context;
|
||||||
|
private final boolean nested;
|
||||||
|
private float scale;
|
||||||
|
@Setter
|
||||||
|
private ClaimListAdapter.ClaimListItemListener listener;
|
||||||
|
@Setter
|
||||||
|
private ReplyClickListener replyListener;
|
||||||
|
|
||||||
|
public CommentListAdapter(List<Comment> items, Context context) {
|
||||||
|
this(items, context, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommentListAdapter(List<Comment> items, Context context, boolean nested) {
|
||||||
|
this.items = new ArrayList<>(items);
|
||||||
|
this.context = context;
|
||||||
|
this.nested = nested;
|
||||||
|
if (context != null) {
|
||||||
|
scale = context.getResources().getDisplayMetrics().density;
|
||||||
|
}
|
||||||
|
for (Comment item : this.items) {
|
||||||
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
|
key.setClaimId(item.getChannelId());
|
||||||
|
if (Lbry.claimCache.containsKey(key)) {
|
||||||
|
item.setPoster(Lbry.claimCache.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearItems() {
|
||||||
|
items.clear();
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getPositionForComment(String commentHash) {
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
if (commentHash.equalsIgnoreCase(items.get(i).getId())) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return items != null ? items.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getClaimUrlsToResolve() {
|
||||||
|
List<String> urls = new ArrayList<>();
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
Comment item = items.get(i);
|
||||||
|
if (item.getPoster() == null) {
|
||||||
|
LbryUri url = LbryUri.tryParse(String.format("%s#%s", item.getChannelName(), item.getChannelId()));
|
||||||
|
if (url != null && !urls.contains(url.toString())) {
|
||||||
|
urls.add(url.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.getReplies().size() > 0) {
|
||||||
|
for (int j = 0; j < item.getReplies().size(); j++) {
|
||||||
|
Comment reply = item.getReplies().get(j);
|
||||||
|
if (reply.getPoster() == null) {
|
||||||
|
LbryUri url = LbryUri.tryParse(String.format("%s#%s", reply.getChannelName(), reply.getChannelId()));
|
||||||
|
if (url != null && !urls.contains(url.toString())) {
|
||||||
|
urls.add(url.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
protected final TextView channelName;
|
||||||
|
protected final TextView commentText;
|
||||||
|
protected final ImageView thumbnailView;
|
||||||
|
protected final View noThumbnailView;
|
||||||
|
protected final TextView alphaView;
|
||||||
|
protected final TextView commentTimeView;
|
||||||
|
protected final View replyLink;
|
||||||
|
protected final RecyclerView repliesList;
|
||||||
|
|
||||||
|
public ViewHolder (View v) {
|
||||||
|
super(v);
|
||||||
|
channelName = v.findViewById(R.id.comment_channel_name);
|
||||||
|
commentTimeView = v.findViewById(R.id.comment_time);
|
||||||
|
commentText = v.findViewById(R.id.comment_text);
|
||||||
|
replyLink = v.findViewById(R.id.comment_reply_link);
|
||||||
|
thumbnailView = v.findViewById(R.id.comment_thumbnail);
|
||||||
|
noThumbnailView = v.findViewById(R.id.comment_no_thumbnail);
|
||||||
|
alphaView = v.findViewById(R.id.comment_thumbnail_alpha);
|
||||||
|
repliesList = v.findViewById(R.id.comment_replies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insert(int index, Comment comment) {
|
||||||
|
if (!items.contains(comment)) {
|
||||||
|
items.add(index, comment);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addReply(Comment comment) {
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
Comment parent = items.get(i);
|
||||||
|
if (parent.getId().equalsIgnoreCase(comment.getParentId())) {
|
||||||
|
parent.addReply(comment);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePosterForComment(String channelId, Claim channel) {
|
||||||
|
for (int i = 0 ; i < items.size(); i++) {
|
||||||
|
Comment item = items.get(i);
|
||||||
|
List<Comment> replies = item.getReplies();
|
||||||
|
if (replies != null && replies.size() > 0) {
|
||||||
|
for (int j = 0; j < replies.size(); j++) {
|
||||||
|
Comment reply = item.getReplies().get(j);
|
||||||
|
if (channelId.equalsIgnoreCase(reply.getChannelId())) {
|
||||||
|
reply.setPoster(channel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelId.equalsIgnoreCase(item.getChannelId())) {
|
||||||
|
item.setPoster(channel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(context).inflate(R.layout.list_item_comment, parent, false);
|
||||||
|
return new CommentListAdapter.ViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||||
|
Comment comment = items.get(position);
|
||||||
|
holder.itemView.setPadding(
|
||||||
|
nested ? Helper.getScaledValue(56, scale) : holder.itemView.getPaddingStart(),
|
||||||
|
holder.itemView.getPaddingTop(),
|
||||||
|
nested ? 0 : holder.itemView.getPaddingEnd(),
|
||||||
|
holder.itemView.getPaddingBottom());
|
||||||
|
|
||||||
|
holder.channelName.setText(comment.getChannelName());
|
||||||
|
holder.commentTimeView.setText(DateUtils.getRelativeTimeSpanString(
|
||||||
|
(comment.getTimestamp() * 1000), System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
|
||||||
|
holder.commentText.setText(comment.getText());
|
||||||
|
holder.replyLink.setVisibility(!nested ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
boolean hasThumbnail = comment.getPoster() != null && !Helper.isNullOrEmpty(comment.getPoster().getThumbnailUrl());
|
||||||
|
holder.thumbnailView.setVisibility(hasThumbnail ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
holder.noThumbnailView.setVisibility(!hasThumbnail ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
int bgColor = Helper.generateRandomColorForValue(comment.getChannelId());
|
||||||
|
Helper.setIconViewBackgroundColor(holder.noThumbnailView, bgColor, false, context);
|
||||||
|
if (hasThumbnail) {
|
||||||
|
Glide.with(context.getApplicationContext()).asBitmap().load(comment.getPoster().getThumbnailUrl(holder.thumbnailView.getLayoutParams().width, holder.thumbnailView.getLayoutParams().height, 85)).
|
||||||
|
apply(RequestOptions.circleCropTransform()).into(holder.thumbnailView);
|
||||||
|
}
|
||||||
|
holder.alphaView.setText(comment.getChannelName() != null ? comment.getChannelName().substring(1, 2).toUpperCase() : null);
|
||||||
|
List<Comment> replies = comment.getReplies();
|
||||||
|
boolean hasReplies = replies != null && replies.size() > 0;
|
||||||
|
if (hasReplies) {
|
||||||
|
holder.repliesList.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
holder.repliesList.setAdapter(new CommentListAdapter(replies, context, true));
|
||||||
|
} else {
|
||||||
|
holder.repliesList.setAdapter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.channelName.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (listener != null && comment.getPoster() != null) {
|
||||||
|
listener.onClaimClicked(comment.getPoster());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
holder.replyLink.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (replyListener != null) {
|
||||||
|
replyListener.onReplyClicked(comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ReplyClickListener {
|
||||||
|
void onReplyClicked(Comment comment);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,8 +23,8 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
|
||||||
private static final int VIEW_TYPE_HEADER = 1;
|
private static final int VIEW_TYPE_HEADER = 1;
|
||||||
private static final int VIEW_TYPE_CONTENT = 2;
|
private static final int VIEW_TYPE_CONTENT = 2;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<EditorsChoiceItem> items;
|
private final List<EditorsChoiceItem> items;
|
||||||
@Setter
|
@Setter
|
||||||
private EditorsChoiceItemListener listener;
|
private EditorsChoiceItemListener listener;
|
||||||
|
|
||||||
|
@ -48,11 +48,11 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected ImageView thumbnailView;
|
protected final ImageView thumbnailView;
|
||||||
protected TextView descriptionView;
|
protected final TextView descriptionView;
|
||||||
protected TextView headerView;
|
protected final TextView headerView;
|
||||||
protected TextView titleView;
|
protected final TextView titleView;
|
||||||
protected View cardView;
|
protected final View cardView;
|
||||||
|
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
@ -95,6 +95,7 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
|
||||||
vh.descriptionView.setText(item.getDescription());
|
vh.descriptionView.setText(item.getDescription());
|
||||||
if (!Helper.isNullOrEmpty(item.getThumbnailUrl())) {
|
if (!Helper.isNullOrEmpty(item.getThumbnailUrl())) {
|
||||||
Glide.with(context.getApplicationContext()).
|
Glide.with(context.getApplicationContext()).
|
||||||
|
asBitmap().
|
||||||
load(item.getThumbnailUrl()).
|
load(item.getThumbnailUrl()).
|
||||||
centerCrop().
|
centerCrop().
|
||||||
placeholder(R.drawable.bg_thumbnail_placeholder).
|
placeholder(R.drawable.bg_thumbnail_placeholder).
|
||||||
|
|
|
@ -21,8 +21,8 @@ import io.lbry.browser.utils.Helper;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> {
|
public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<GalleryItem> items;
|
private final List<GalleryItem> items;
|
||||||
@Setter
|
@Setter
|
||||||
private GalleryItemClickListener listener;
|
private GalleryItemClickListener listener;
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected ImageView thumbnailView;
|
protected final ImageView thumbnailView;
|
||||||
protected TextView durationView;
|
protected final TextView durationView;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
thumbnailView = v.findViewById(R.id.gallery_item_thumbnail);
|
thumbnailView = v.findViewById(R.id.gallery_item_thumbnail);
|
||||||
|
@ -96,8 +96,8 @@ public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.
|
||||||
|
|
||||||
public static class GalleryGridItemDecoration extends RecyclerView.ItemDecoration {
|
public static class GalleryGridItemDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
|
||||||
private int spanCount;
|
private final int spanCount;
|
||||||
private int spacing;
|
private final int spacing;
|
||||||
|
|
||||||
public GalleryGridItemDecoration(int spanCount, int spacing) {
|
public GalleryGridItemDecoration(int spanCount, int spacing) {
|
||||||
this.spanCount = spanCount;
|
this.spanCount = spanCount;
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
package io.lbry.browser.adapter;
|
package io.lbry.browser.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.DataSetObserver;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.SpinnerAdapter;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
|
@ -17,9 +16,9 @@ import io.lbry.browser.model.Claim;
|
||||||
|
|
||||||
public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
|
public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
|
||||||
|
|
||||||
private List<Claim> channels;
|
private final List<Claim> channels;
|
||||||
private int layoutResourceId;
|
private final int layoutResourceId;
|
||||||
private LayoutInflater inflater;
|
private final LayoutInflater inflater;
|
||||||
|
|
||||||
public InlineChannelSpinnerAdapter(Context context, int resource, List<Claim> channels) {
|
public InlineChannelSpinnerAdapter(Context context, int resource, List<Claim> channels) {
|
||||||
super(context, resource, 0, channels);
|
super(context, resource, 0, channels);
|
||||||
|
@ -40,11 +39,30 @@ public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
|
||||||
channels.add(1, anonymous);
|
channels.add(1, anonymous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void addAnonymousPlaceholder() {
|
||||||
|
Claim anonymous = new Claim();
|
||||||
|
anonymous.setPlaceholderAnonymous(true);
|
||||||
|
insert(anonymous, 0);
|
||||||
|
channels.add(0, anonymous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAll(Collection<? extends Claim> collection) {
|
||||||
|
for (Claim claim : collection) {
|
||||||
|
if (!channels.contains(claim)) {
|
||||||
|
channels.add(claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.addAll(collection);
|
||||||
|
}
|
||||||
|
public void clear() {
|
||||||
|
channels.clear();
|
||||||
|
super.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public int getItemPosition(Claim item) {
|
public int getItemPosition(Claim item) {
|
||||||
for (int i = 0; i < channels.size(); i++) {
|
for (int i = 0; i < channels.size(); i++) {
|
||||||
Claim channel = channels.get(i);
|
Claim channel = channels.get(i);
|
||||||
if (item.getClaimId().equalsIgnoreCase(channel.getClaimId())) {
|
if (item.getClaimId() != null && item.getClaimId().equalsIgnoreCase(channel.getClaimId())) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package io.lbry.browser.adapter;
|
package io.lbry.browser.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -11,21 +9,16 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
import io.lbry.browser.model.lbryinc.Invitee;
|
import io.lbry.browser.model.lbryinc.Invitee;
|
||||||
import io.lbry.browser.utils.Helper;
|
|
||||||
import io.lbry.browser.utils.LbryUri;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.ViewHolder> {
|
public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.ViewHolder> {
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Invitee> items;
|
private final List<Invitee> items;
|
||||||
|
|
||||||
public InviteeListAdapter(List<Invitee> invitees, Context context) {
|
public InviteeListAdapter(List<Invitee> invitees, Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -80,8 +73,8 @@ public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected TextView emailView;
|
protected final TextView emailView;
|
||||||
protected TextView rewardView;
|
protected final TextView rewardView;
|
||||||
|
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
|
|
@ -10,13 +10,12 @@ import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
import io.lbry.browser.model.Claim;
|
|
||||||
import io.lbry.browser.model.Language;
|
import io.lbry.browser.model.Language;
|
||||||
import io.lbry.browser.utils.Predefined;
|
import io.lbry.browser.utils.Predefined;
|
||||||
|
|
||||||
public class LanguageSpinnerAdapter extends ArrayAdapter<Language> {
|
public class LanguageSpinnerAdapter extends ArrayAdapter<Language> {
|
||||||
private int layoutResourceId;
|
private final int layoutResourceId;
|
||||||
private LayoutInflater inflater;
|
private final LayoutInflater inflater;
|
||||||
|
|
||||||
public LanguageSpinnerAdapter(Context context, int resource) {
|
public LanguageSpinnerAdapter(Context context, int resource) {
|
||||||
super(context, resource, 0, Predefined.PUBLISH_LANGUAGES);
|
super(context, resource, 0, Predefined.PUBLISH_LANGUAGES);
|
||||||
|
|
|
@ -10,13 +10,12 @@ import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
import io.lbry.browser.model.Language;
|
|
||||||
import io.lbry.browser.model.License;
|
import io.lbry.browser.model.License;
|
||||||
import io.lbry.browser.utils.Predefined;
|
import io.lbry.browser.utils.Predefined;
|
||||||
|
|
||||||
public class LicenseSpinnerAdapter extends ArrayAdapter<License> {
|
public class LicenseSpinnerAdapter extends ArrayAdapter<License> {
|
||||||
private int layoutResourceId;
|
private final int layoutResourceId;
|
||||||
private LayoutInflater inflater;
|
private final LayoutInflater inflater;
|
||||||
|
|
||||||
public LicenseSpinnerAdapter(Context context, int resource) {
|
public LicenseSpinnerAdapter(Context context, int resource) {
|
||||||
super(context, resource, 0, Predefined.LICENSES);
|
super(context, resource, 0, Predefined.LICENSES);
|
||||||
|
|
|
@ -2,10 +2,8 @@ package io.lbry.browser.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
@ -17,15 +15,14 @@ import io.lbry.browser.R;
|
||||||
import io.lbry.browser.model.NavMenuItem;
|
import io.lbry.browser.model.NavMenuItem;
|
||||||
import io.lbry.browser.ui.controls.SolidIconView;
|
import io.lbry.browser.ui.controls.SolidIconView;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> {
|
public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> {
|
||||||
private static final int TYPE_GROUP = 1;
|
private static final int TYPE_GROUP = 1;
|
||||||
private static final int TYPE_ITEM = 2;
|
private static final int TYPE_ITEM = 2;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<NavMenuItem> menuItems;
|
private final List<NavMenuItem> menuItems;
|
||||||
private NavMenuItem currentItem;
|
private NavMenuItem currentItem;
|
||||||
@Setter
|
@Setter
|
||||||
private NavigationMenuItemClickListener listener;
|
private NavigationMenuItemClickListener listener;
|
||||||
|
@ -65,8 +62,8 @@ public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAd
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected SolidIconView iconView;
|
protected final SolidIconView iconView;
|
||||||
protected TextView titleView;
|
protected final TextView titleView;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
titleView = v.findViewById(R.id.nav_menu_title);
|
titleView = v.findViewById(R.id.nav_menu_title);
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
package io.lbry.browser.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import io.lbry.browser.R;
|
||||||
|
import io.lbry.browser.listener.SelectionModeListener;
|
||||||
|
import io.lbry.browser.model.Claim;
|
||||||
|
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||||
|
import io.lbry.browser.ui.controls.SolidIconView;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class NotificationListAdapter extends RecyclerView.Adapter<NotificationListAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private static final String RULE_CREATOR_SUBSCRIBER = "creator_subscriber";
|
||||||
|
private static final String RULE_COMMENT = "comment";
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
private final List<LbryNotification> items;
|
||||||
|
private final List<LbryNotification> selectedItems;
|
||||||
|
@Setter
|
||||||
|
private NotificationClickListener clickListener;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private boolean inSelectionMode;
|
||||||
|
@Setter
|
||||||
|
private SelectionModeListener selectionModeListener;
|
||||||
|
|
||||||
|
public NotificationListAdapter(List<LbryNotification> notifications, Context context) {
|
||||||
|
this.context = context;
|
||||||
|
this.items = new ArrayList<>(notifications);
|
||||||
|
this.selectedItems = new ArrayList<>();
|
||||||
|
Collections.sort(items, Collections.reverseOrder(new LbryNotification()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
protected final View layoutView;
|
||||||
|
protected final TextView titleView;
|
||||||
|
protected final TextView bodyView;
|
||||||
|
protected final TextView timeView;
|
||||||
|
protected final SolidIconView iconView;
|
||||||
|
protected final ImageView thumbnailView;
|
||||||
|
protected final View selectedOverlayView;
|
||||||
|
public ViewHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
layoutView = v.findViewById(R.id.notification_layout);
|
||||||
|
titleView = v.findViewById(R.id.notification_title);
|
||||||
|
bodyView = v.findViewById(R.id.notification_body);
|
||||||
|
timeView = v.findViewById(R.id.notification_time);
|
||||||
|
iconView = v.findViewById(R.id.notification_icon);
|
||||||
|
thumbnailView = v.findViewById(R.id.notification_author_thumbnail);
|
||||||
|
selectedOverlayView = v.findViewById(R.id.notification_selected_overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getItemCount() {
|
||||||
|
return items != null ? items.size() : 0;
|
||||||
|
}
|
||||||
|
public List<LbryNotification> getSelectedItems() {
|
||||||
|
return this.selectedItems;
|
||||||
|
}
|
||||||
|
public int getSelectedCount() {
|
||||||
|
return selectedItems != null ? selectedItems.size() : 0;
|
||||||
|
}
|
||||||
|
public void clearSelectedItems() {
|
||||||
|
this.selectedItems.clear();
|
||||||
|
}
|
||||||
|
public boolean isNotificationSelected(LbryNotification notification) {
|
||||||
|
return selectedItems.contains(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertNotification(LbryNotification notification, int index) {
|
||||||
|
if (!items.contains(notification)) {
|
||||||
|
items.add(index, notification);
|
||||||
|
}
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNotification(LbryNotification notification) {
|
||||||
|
if (!items.contains(notification)) {
|
||||||
|
items.add(notification);
|
||||||
|
}
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
public void removeNotifications(List<LbryNotification> notifications) {
|
||||||
|
for (LbryNotification notification : notifications) {
|
||||||
|
items.remove(notification);
|
||||||
|
}
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAuthorUrls() {
|
||||||
|
List<String> urls = new ArrayList<>();
|
||||||
|
for (LbryNotification item : items) {
|
||||||
|
if (!Helper.isNullOrEmpty(item.getAuthorUrl())) {
|
||||||
|
urls.add(item.getAuthorUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAuthorClaims(List<Claim> claims) {
|
||||||
|
for (Claim claim : claims) {
|
||||||
|
if (claim != null && claim.getThumbnailUrl() != null) {
|
||||||
|
updateClaimForAuthorUrl(claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateClaimForAuthorUrl(Claim claim) {
|
||||||
|
for (LbryNotification item : items) {
|
||||||
|
if (claim.getPermanentUrl().equalsIgnoreCase(item.getAuthorUrl())) {
|
||||||
|
item.setCommentAuthor(claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNotifications(List<LbryNotification> notifications) {
|
||||||
|
for (LbryNotification notification : notifications) {
|
||||||
|
if (!items.contains(notification)) {
|
||||||
|
items.add(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(items, Collections.reverseOrder(new LbryNotification()));
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotificationListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
|
||||||
|
View v = LayoutInflater.from(context).inflate(R.layout.list_item_notification, root, false);
|
||||||
|
return new NotificationListAdapter.ViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getStringIdForRule(String rule) {
|
||||||
|
if (RULE_CREATOR_SUBSCRIBER.equalsIgnoreCase(rule)) {
|
||||||
|
return R.string.fa_heart;
|
||||||
|
}
|
||||||
|
if (RULE_COMMENT.equalsIgnoreCase(rule)) {
|
||||||
|
return R.string.fa_comment_alt;
|
||||||
|
}
|
||||||
|
return R.string.fa_asterisk;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getColorForRule(String rule) {
|
||||||
|
if (RULE_CREATOR_SUBSCRIBER.equalsIgnoreCase(rule)) {
|
||||||
|
return Color.RED;
|
||||||
|
}
|
||||||
|
if (RULE_COMMENT.equalsIgnoreCase(rule)) {
|
||||||
|
return ContextCompat.getColor(context, R.color.nextLbryGreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContextCompat.getColor(context, R.color.lbryGreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(NotificationListAdapter.ViewHolder vh, int position) {
|
||||||
|
LbryNotification notification = items.get(position);
|
||||||
|
vh.layoutView.setBackgroundColor(ContextCompat.getColor(context, notification.isSeen() ? android.R.color.transparent : R.color.nextLbryGreenSemiTransparent));
|
||||||
|
vh.selectedOverlayView.setVisibility(isNotificationSelected(notification) ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
vh.titleView.setVisibility(!Helper.isNullOrEmpty(notification.getTitle()) ? View.VISIBLE : View.GONE);
|
||||||
|
vh.titleView.setText(notification.getTitle());
|
||||||
|
vh.bodyView.setText(notification.getDescription());
|
||||||
|
vh.timeView.setText(DateUtils.getRelativeTimeSpanString(
|
||||||
|
getLocalNotificationTime(notification), System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
|
||||||
|
|
||||||
|
vh.thumbnailView.setVisibility(notification.getCommentAuthor() == null ? View.INVISIBLE : View.VISIBLE);
|
||||||
|
if (notification.getCommentAuthor() != null) {
|
||||||
|
Glide.with(context.getApplicationContext()).load(
|
||||||
|
notification.getCommentAuthor().getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85)).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
|
||||||
|
}
|
||||||
|
|
||||||
|
vh.iconView.setVisibility(notification.getCommentAuthor() != null ? View.INVISIBLE : View.VISIBLE);
|
||||||
|
vh.iconView.setText(getStringIdForRule(notification.getRule()));
|
||||||
|
vh.iconView.setTextColor(getColorForRule(notification.getRule()));
|
||||||
|
|
||||||
|
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (inSelectionMode) {
|
||||||
|
toggleSelectedNotification(notification);
|
||||||
|
} else {
|
||||||
|
if (clickListener != null) {
|
||||||
|
clickListener.onNotificationClicked(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View view) {
|
||||||
|
if (!inSelectionMode) {
|
||||||
|
inSelectionMode = true;
|
||||||
|
if (selectionModeListener != null) {
|
||||||
|
selectionModeListener.onEnterSelectionMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toggleSelectedNotification(notification);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleSelectedNotification(LbryNotification notification) {
|
||||||
|
if (selectedItems.contains(notification)) {
|
||||||
|
selectedItems.remove(notification);
|
||||||
|
} else {
|
||||||
|
selectedItems.add(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectionModeListener != null) {
|
||||||
|
selectionModeListener.onItemSelectionToggled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItems.size() == 0) {
|
||||||
|
inSelectionMode = false;
|
||||||
|
if (selectionModeListener != null) {
|
||||||
|
selectionModeListener.onExitSelectionMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getLocalNotificationTime(LbryNotification notification) {
|
||||||
|
TimeZone utcTZ = TimeZone.getTimeZone("UTC");
|
||||||
|
TimeZone targetTZ = TimeZone.getDefault();
|
||||||
|
Calendar cal = new GregorianCalendar(utcTZ);
|
||||||
|
cal.setTimeInMillis(notification.getTimestamp().getTime());
|
||||||
|
|
||||||
|
cal.add(Calendar.MILLISECOND, utcTZ.getRawOffset() * -1);
|
||||||
|
cal.add(Calendar.MILLISECOND, targetTZ.getRawOffset());
|
||||||
|
return cal.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface NotificationClickListener {
|
||||||
|
void onNotificationClicked(LbryNotification notification);
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
|
||||||
public static final int DISPLAY_MODE_ALL = 1;
|
public static final int DISPLAY_MODE_ALL = 1;
|
||||||
public static final int DISPLAY_MODE_UNCLAIMED = 2;
|
public static final int DISPLAY_MODE_UNCLAIMED = 2;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
@Setter
|
@Setter
|
||||||
private List<Reward> all;
|
private List<Reward> all;
|
||||||
private List<Reward> items;
|
private List<Reward> items;
|
||||||
|
@ -85,16 +85,16 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected View iconClaimed;
|
protected final View iconClaimed;
|
||||||
protected View loading;
|
protected final View loading;
|
||||||
protected View upTo;
|
protected final View upTo;
|
||||||
protected TextView textTitle;
|
protected final TextView textTitle;
|
||||||
protected TextView textDescription;
|
protected final TextView textDescription;
|
||||||
protected TextView textLbcValue;
|
protected final TextView textLbcValue;
|
||||||
protected TextView textUsdValue;
|
protected final TextView textUsdValue;
|
||||||
protected TextView textLinkTransaction;
|
protected final TextView textLinkTransaction;
|
||||||
protected EditText inputCustomCode;
|
protected final EditText inputCustomCode;
|
||||||
protected MaterialButton buttonClaimCustom;
|
protected final MaterialButton buttonClaimCustom;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
|
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
|
||||||
|
@ -168,6 +168,10 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vh.inputCustomCode != null && !vh.inputCustomCode.hasFocus()) {
|
||||||
|
vh.inputCustomCode.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
if (clickListener != null) {
|
if (clickListener != null) {
|
||||||
clickListener.onRewardClicked(reward, vh.loading);
|
clickListener.onRewardClicked(reward, vh.loading);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package io.lbry.browser.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.lbry.browser.R;
|
||||||
|
import io.lbry.browser.model.StartupStage;
|
||||||
|
|
||||||
|
public class StartupStageAdapter extends BaseAdapter {
|
||||||
|
private final List<StartupStage> list;
|
||||||
|
private final LayoutInflater inflater;
|
||||||
|
private final String[] stagesString;
|
||||||
|
|
||||||
|
public StartupStageAdapter(Context ctx, List<StartupStage> rows) {
|
||||||
|
this.list = rows;
|
||||||
|
this.inflater = LayoutInflater.from(ctx);
|
||||||
|
|
||||||
|
stagesString = new String[9];
|
||||||
|
|
||||||
|
stagesString[0] = ctx.getResources().getString(R.string.installation_id_loaded);
|
||||||
|
stagesString[1] = ctx.getResources().getString(R.string.known_tags_loaded);
|
||||||
|
stagesString[2] = ctx.getResources().getString(R.string.exchange_rate_loaded);
|
||||||
|
stagesString[3] = ctx.getResources().getString(R.string.user_authenticated);
|
||||||
|
stagesString[4] = ctx.getResources().getString(R.string.installation_registered);
|
||||||
|
stagesString[5] = ctx.getResources().getString(R.string.subscriptions_loaded);
|
||||||
|
stagesString[6] = ctx.getResources().getString(R.string.subscriptions_resolved);
|
||||||
|
stagesString[7] = ctx.getResources().getString(R.string.block_list_loaded);
|
||||||
|
stagesString[8] = ctx.getResources().getString(R.string.filter_list_loaded);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int i) {
|
||||||
|
return list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
if (view == null) {
|
||||||
|
view = inflater.inflate(R.layout.list_item_startupstage, viewGroup, false);
|
||||||
|
|
||||||
|
ImageView iconView = view.findViewById(R.id.startup_stage_icon);
|
||||||
|
TextView textView = view.findViewById(R.id.startup_stage_text);
|
||||||
|
|
||||||
|
StartupStage item = (StartupStage) getItem(i);
|
||||||
|
|
||||||
|
iconView.setImageResource(item.stageDone ? R.drawable.ic_check : R.drawable.ic_close);
|
||||||
|
iconView.setColorFilter(item.stageDone ? Color.WHITE : Color.RED);
|
||||||
|
|
||||||
|
textView.setText(stagesString[item.stage - 1]);
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,9 +22,9 @@ import io.lbry.browser.utils.Helper;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> {
|
public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Claim> items;
|
private final List<Claim> items;
|
||||||
private List<Claim> selectedItems;
|
private final List<Claim> selectedItems;
|
||||||
@Setter
|
@Setter
|
||||||
private ChannelItemSelectionListener listener;
|
private ChannelItemSelectionListener listener;
|
||||||
|
|
||||||
|
@ -35,11 +35,11 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected View noThumbnailView;
|
protected final View noThumbnailView;
|
||||||
protected ImageView thumbnailView;
|
protected final ImageView thumbnailView;
|
||||||
protected TextView alphaView;
|
protected final TextView alphaView;
|
||||||
protected TextView titleView;
|
protected final TextView titleView;
|
||||||
protected TextView tagView;
|
protected final TextView tagView;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
|
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
|
||||||
|
@ -89,7 +89,8 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) {
|
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) {
|
||||||
Claim claim = items.get(position);
|
Claim claim = items.get(position);
|
||||||
String thumbnailUrl = claim.getThumbnailUrl();
|
ViewGroup.LayoutParams lp = vh.thumbnailView.getLayoutParams();
|
||||||
|
String thumbnailUrl = claim.getThumbnailUrl(lp.width, lp.height, 85);
|
||||||
|
|
||||||
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
|
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
|
||||||
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
|
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
|
||||||
|
|
|
@ -23,12 +23,13 @@ public class TagListAdapter extends RecyclerView.Adapter<TagListAdapter.ViewHold
|
||||||
public static final int CUSTOMIZE_MODE_ADD = 1;
|
public static final int CUSTOMIZE_MODE_ADD = 1;
|
||||||
public static final int CUSTOMIZE_MODE_REMOVE = 2;
|
public static final int CUSTOMIZE_MODE_REMOVE = 2;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Tag> items;
|
private List<Tag> items;
|
||||||
@Setter
|
@Setter
|
||||||
private TagClickListener clickListener;
|
private TagClickListener clickListener;
|
||||||
@Getter
|
|
||||||
@Setter
|
@Setter
|
||||||
|
@Getter
|
||||||
private int customizeMode;
|
private int customizeMode;
|
||||||
|
|
||||||
public TagListAdapter(List<Tag> tags, Context context) {
|
public TagListAdapter(List<Tag> tags, Context context) {
|
||||||
|
@ -38,8 +39,8 @@ public class TagListAdapter extends RecyclerView.Adapter<TagListAdapter.ViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected ImageView iconView;
|
protected final ImageView iconView;
|
||||||
protected TextView nameView;
|
protected final TextView nameView;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
iconView = v.findViewById(R.id.tag_action);
|
iconView = v.findViewById(R.id.tag_action);
|
||||||
|
|
|
@ -26,8 +26,8 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
||||||
private static final DecimalFormat TX_LIST_AMOUNT_FORMAT = new DecimalFormat("#,##0.0000");
|
private static final DecimalFormat TX_LIST_AMOUNT_FORMAT = new DecimalFormat("#,##0.0000");
|
||||||
private static final SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
|
private static final SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Transaction> items;
|
private final List<Transaction> items;
|
||||||
@Setter
|
@Setter
|
||||||
private TransactionClickListener listener;
|
private TransactionClickListener listener;
|
||||||
|
|
||||||
|
@ -72,7 +72,9 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
||||||
vh.claimView.setText(item.getClaim());
|
vh.claimView.setText(item.getClaim());
|
||||||
vh.feeView.setText(context.getString(R.string.tx_list_fee, TX_LIST_AMOUNT_FORMAT.format(item.getFee().doubleValue())));
|
vh.feeView.setText(context.getString(R.string.tx_list_fee, TX_LIST_AMOUNT_FORMAT.format(item.getFee().doubleValue())));
|
||||||
vh.txidLinkView.setText(item.getTxid().substring(0, 7));
|
vh.txidLinkView.setText(item.getTxid().substring(0, 7));
|
||||||
vh.dateView.setText(TX_LIST_DATE_FORMAT.format(item.getTxDate()));
|
vh.dateView.setVisibility(item.getConfirmations() > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
vh.dateView.setText(item.getConfirmations() > 0 ? TX_LIST_DATE_FORMAT.format(item.getTxDate()) : null);
|
||||||
|
vh.pendingView.setVisibility(item.getConfirmations() == 0 ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
vh.infoFeeContainer.setVisibility(!Helper.isNullOrEmpty(item.getClaim()) || Math.abs(item.getFee().doubleValue()) > 0 ?
|
vh.infoFeeContainer.setVisibility(!Helper.isNullOrEmpty(item.getClaim()) || Math.abs(item.getFee().doubleValue()) > 0 ?
|
||||||
View.VISIBLE : View.GONE);
|
View.VISIBLE : View.GONE);
|
||||||
|
@ -105,13 +107,14 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected TextView descView;
|
protected final TextView descView;
|
||||||
protected TextView amountView;
|
protected final TextView amountView;
|
||||||
protected TextView claimView;
|
protected final TextView claimView;
|
||||||
protected TextView feeView;
|
protected final TextView feeView;
|
||||||
protected TextView txidLinkView;
|
protected final TextView txidLinkView;
|
||||||
protected TextView dateView;
|
protected final TextView dateView;
|
||||||
protected View infoFeeContainer;
|
protected final TextView pendingView;
|
||||||
|
protected final View infoFeeContainer;
|
||||||
|
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
|
@ -121,6 +124,7 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
||||||
feeView = v.findViewById(R.id.transaction_fee);
|
feeView = v.findViewById(R.id.transaction_fee);
|
||||||
txidLinkView = v.findViewById(R.id.transaction_id_link);
|
txidLinkView = v.findViewById(R.id.transaction_id_link);
|
||||||
dateView = v.findViewById(R.id.transaction_date);
|
dateView = v.findViewById(R.id.transaction_date);
|
||||||
|
pendingView = v.findViewById(R.id.transaction_pending_text);
|
||||||
infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container);
|
infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ import io.lbry.browser.utils.LbryUri;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestionListAdapter.ViewHolder> {
|
public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestionListAdapter.ViewHolder> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<UrlSuggestion> items;
|
private final List<UrlSuggestion> items;
|
||||||
@Setter
|
@Setter
|
||||||
private UrlSuggestionClickListener listener;
|
private UrlSuggestionClickListener listener;
|
||||||
|
|
||||||
|
@ -130,9 +130,9 @@ public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestion
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
protected SolidIconView iconView;
|
protected final SolidIconView iconView;
|
||||||
protected TextView titleView;
|
protected final TextView titleView;
|
||||||
protected TextView descView;
|
protected final TextView descView;
|
||||||
public ViewHolder(View v) {
|
public ViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
iconView = v.findViewById(R.id.url_suggestion_icon);
|
iconView = v.findViewById(R.id.url_suggestion_icon);
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class VerificationPagerAdapter extends FragmentStateAdapter {
|
||||||
public static final int PAGE_VERIFICATION_WALLET = 2;
|
public static final int PAGE_VERIFICATION_WALLET = 2;
|
||||||
public static final int PAGE_VERIFICATION_MANUAL = 3;
|
public static final int PAGE_VERIFICATION_MANUAL = 3;
|
||||||
|
|
||||||
private FragmentActivity activity;
|
private final FragmentActivity activity;
|
||||||
|
|
||||||
public VerificationPagerAdapter(FragmentActivity activity) {
|
public VerificationPagerAdapter(FragmentActivity activity) {
|
||||||
super(activity);
|
super(activity);
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
package io.lbry.browser.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.lbry.browser.MainActivity;
|
||||||
|
import io.lbry.browser.R;
|
||||||
|
import io.lbry.browser.model.WalletDetailItem;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import io.lbry.browser.views.CreditsBalanceView;
|
||||||
|
|
||||||
|
public class WalletDetailAdapter extends BaseAdapter {
|
||||||
|
private final List<WalletDetailItem> list;
|
||||||
|
private final LayoutInflater inflater;
|
||||||
|
|
||||||
|
public WalletDetailAdapter(Context ctx, List<WalletDetailItem> rows) {
|
||||||
|
this.list = rows;
|
||||||
|
this.inflater = LayoutInflater.from(ctx);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int i) {
|
||||||
|
return list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
if (view == null) {
|
||||||
|
view = inflater.inflate(R.layout.list_item_boosting_balance, viewGroup, false);
|
||||||
|
|
||||||
|
CreditsBalanceView balanceView = view.findViewById(R.id.wallet_supporting_balance);
|
||||||
|
TextView detailTextView = view.findViewById(R.id.detail);
|
||||||
|
TextView detailExplanationTextView = view.findViewById(R.id.detail_explanation);
|
||||||
|
|
||||||
|
WalletDetailItem item = (WalletDetailItem) getItem(i);
|
||||||
|
|
||||||
|
detailTextView.setText(item.detail);
|
||||||
|
detailExplanationTextView.setText(item.detailDesc);
|
||||||
|
|
||||||
|
Helper.setViewText(balanceView, item.detailAmount);
|
||||||
|
|
||||||
|
ProgressBar progressUnlockTips = view.findViewById(R.id.wallet_unlock_tips_progress);
|
||||||
|
progressUnlockTips.setVisibility(item.isInProgress ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
ImageButton buttonLock = view.findViewById(R.id.lock_button);
|
||||||
|
buttonLock.setVisibility((item.isUnlockable && !item.isInProgress) ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
if (item.isUnlockable) {
|
||||||
|
buttonLock.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (view.getContext() != null) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()).
|
||||||
|
setTitle(R.string.unlock_tips).
|
||||||
|
setMessage(R.string.confirm_unlock_tips)
|
||||||
|
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
unlockTips(view);
|
||||||
|
}
|
||||||
|
}).setNegativeButton(R.string.no, null);
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unlockTips(View v) {
|
||||||
|
Context ctx = v.getContext();
|
||||||
|
if (ctx instanceof MainActivity) {
|
||||||
|
v.setVisibility(View.GONE);
|
||||||
|
View progress = v.getRootView().findViewById(R.id.wallet_unlock_tips_progress);
|
||||||
|
progress.setVisibility(View.VISIBLE);
|
||||||
|
((MainActivity) ctx).unlockTips();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.opengl.Visibility;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
@ -13,22 +12,22 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.lbry.browser.exceptions.LbryUriException;
|
|
||||||
import io.lbry.browser.model.Tag;
|
import io.lbry.browser.model.Tag;
|
||||||
import io.lbry.browser.model.UrlSuggestion;
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
import io.lbry.browser.model.ViewHistory;
|
import io.lbry.browser.model.ViewHistory;
|
||||||
|
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||||
import io.lbry.browser.model.lbryinc.Subscription;
|
import io.lbry.browser.model.lbryinc.Subscription;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.LbryUri;
|
import io.lbry.browser.utils.LbryUri;
|
||||||
|
|
||||||
public class DatabaseHelper extends SQLiteOpenHelper {
|
public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
public static final int DATABASE_VERSION = 2;
|
public static final int DATABASE_VERSION = 8;
|
||||||
public static final String DATABASE_NAME = "LbryApp.db";
|
public static final String DATABASE_NAME = "LbryApp.db";
|
||||||
private static DatabaseHelper instance;
|
private static DatabaseHelper instance;
|
||||||
|
|
||||||
private static final String[] SQL_CREATE_TABLES = {
|
private static final String[] SQL_CREATE_TABLES = {
|
||||||
// local subscription store
|
// local subscription store
|
||||||
"CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL)",
|
"CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL, is_notifications_disabled INTEGER DEFAULT 0 NOT NULL)",
|
||||||
// url entry / suggestion history
|
// url entry / suggestion history
|
||||||
"CREATE TABLE url_history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)",
|
"CREATE TABLE url_history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)",
|
||||||
// tags (known and followed)
|
// tags (known and followed)
|
||||||
|
@ -48,7 +47,20 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
", thumbnail_url TEXT" +
|
", thumbnail_url TEXT" +
|
||||||
", release_time INTEGER " +
|
", release_time INTEGER " +
|
||||||
", device TEXT" +
|
", device TEXT" +
|
||||||
", timestamp TEXT NOT NULL)"
|
", timestamp TEXT NOT NULL)",
|
||||||
|
"CREATE TABLE notifications (" +
|
||||||
|
" id INTEGER PRIMARY KEY NOT NULL" +
|
||||||
|
", remote_id INTEGER NOT NULL" +
|
||||||
|
", author_url TEXT" +
|
||||||
|
", title TEXT" +
|
||||||
|
", description TEXT" +
|
||||||
|
", thumbnail_url TEXT" +
|
||||||
|
", target_url TEXT" +
|
||||||
|
", rule TEXT" +
|
||||||
|
", is_read INTEGER DEFAULT 0 NOT NULL" +
|
||||||
|
", is_seen INTEGER DEFAULT 0 NOT NULL " +
|
||||||
|
", timestamp TEXT NOT NULL)",
|
||||||
|
"CREATE TABLE shuffle_watched (id INTEGER PRIMARY KEY NOT NULL, claim_id TEXT NOT NULL)"
|
||||||
};
|
};
|
||||||
private static final String[] SQL_CREATE_INDEXES = {
|
private static final String[] SQL_CREATE_INDEXES = {
|
||||||
"CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)",
|
"CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)",
|
||||||
|
@ -56,22 +68,69 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
"CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)",
|
"CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)",
|
||||||
"CREATE UNIQUE INDEX idx_tag_name ON tags (name)",
|
"CREATE UNIQUE INDEX idx_tag_name ON tags (name)",
|
||||||
"CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)",
|
"CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)",
|
||||||
"CREATE INDEX idx_view_history_device ON view_history (device)"
|
"CREATE INDEX idx_view_history_device ON view_history (device)",
|
||||||
|
"CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)",
|
||||||
|
"CREATE INDEX idx_notification_timestamp ON notifications (timestamp)",
|
||||||
|
"CREATE UNIQUE INDEX idx_shuffle_watched_claim ON shuffle_watched (claim_id)",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] SQL_V1_V2_UPGRADE = {
|
private static final String[] SQL_V1_V2_UPGRADE = {
|
||||||
"ALTER TABLE view_history ADD COLUMN currency TEXT"
|
"ALTER TABLE view_history ADD COLUMN currency TEXT"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)";
|
private static final String[] SQL_V2_V3_UPGRADE = {
|
||||||
|
"CREATE TABLE notifications (" +
|
||||||
|
" id INTEGER PRIMARY KEY NOT NULL" +
|
||||||
|
", title TEXT" +
|
||||||
|
", description TEXT" +
|
||||||
|
", thumbnail_url TEXT" +
|
||||||
|
", target_url TEXT" +
|
||||||
|
", is_read INTEGER DEFAULT 0 NOT NULL" +
|
||||||
|
", timestamp TEXT NOT NULL)",
|
||||||
|
"CREATE INDEX idx_notification_timestamp ON notifications (timestamp)"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String[] SQL_V3_V4_UPGRADE = {
|
||||||
|
"ALTER TABLE notifications ADD COLUMN remote_id INTEGER",
|
||||||
|
"CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)"
|
||||||
|
};
|
||||||
|
private static final String[] SQL_V4_V5_UPGRADE = {
|
||||||
|
"ALTER TABLE notifications ADD COLUMN rule TEXT",
|
||||||
|
"ALTER TABLE notifications ADD COLUMN is_seen TEXT"
|
||||||
|
};
|
||||||
|
private static final String[] SQL_V5_V6_UPGRADE = {
|
||||||
|
"ALTER TABLE notifications ADD COLUMN author_url TEXT"
|
||||||
|
};
|
||||||
|
private static final String[] SQL_V6_V7_UPGRADE = {
|
||||||
|
"CREATE TABLE shuffle_watched (id INTEGER PRIMARY KEY NOT NULL, claim_id TEXT NOT NULL)",
|
||||||
|
"CREATE UNIQUE INDEX idx_shuffle_watched_claim ON shuffle_watched (claim_id)"
|
||||||
|
};
|
||||||
|
private static final String[] SQL_V7_V8_UPGRADE = {
|
||||||
|
"AlTER TABLE subscriptions ADD COLUMN is_notifications_disabled INTEGER DEFAULT 0 NOT NULL"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url, is_notifications_disabled) VALUES (?, ?, ?)";
|
||||||
|
private static final String SQL_UPDATE_SUBSCRIPTION_NOTIFICATION = "UPDATE subscriptions SET is_notification_disabled = ? WHERE url = ?";
|
||||||
|
private static final String SQL_CLEAR_SUBSCRIPTIONS = "DELETE FROM subscriptions";
|
||||||
private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?";
|
private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?";
|
||||||
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url FROM subscriptions";
|
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url, is_notifications_disabled FROM subscriptions";
|
||||||
|
|
||||||
private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?, ?)";
|
private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?, ?)";
|
||||||
private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
|
private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
|
||||||
private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?";
|
private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?";
|
||||||
private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10";
|
private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10";
|
||||||
|
|
||||||
|
private static final String SQL_INSERT_NOTIFICATION = "REPLACE INTO notifications (remote_id, author_url, title, description, rule, target_url, is_read, is_seen, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
private static final String SQL_GET_NOTIFICATIONS = "SELECT id, remote_id, author_url, title, description, rule, target_url, is_read, is_seen, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500";
|
||||||
|
private static final String SQL_GET_UNREAD_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_read <> 1";
|
||||||
|
private static final String SQL_GET_UNSEEN_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_seen <> 1";
|
||||||
|
private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0";
|
||||||
|
private static final String SQL_MARK_NOTIFICATIONS_SEEN = "UPDATE notifications SET is_seen = 1 WHERE is_seen = 0";
|
||||||
|
private static final String SQL_MARK_NOTIFICATION_READ_AND_SEEN = "UPDATE notifications SET is_read = 1, is_seen = 1 WHERE id = ?";
|
||||||
|
|
||||||
|
private static final String SQL_INSERT_SHUFFLE_WATCHED = "REPLACE INTO shuffle_watched (claim_id) VALUES (?)";
|
||||||
|
private static final String SQL_GET_SHUFFLE_WATCHED_CLAIMS = "SELECT claim_id FROM shuffle_watched";
|
||||||
|
|
||||||
private static final String SQL_INSERT_VIEW_HISTORY =
|
private static final String SQL_INSERT_VIEW_HISTORY =
|
||||||
"REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
"REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
private static final String SQL_GET_VIEW_HISTORY =
|
private static final String SQL_GET_VIEW_HISTORY =
|
||||||
|
@ -110,6 +169,36 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
db.execSQL(sql);
|
db.execSQL(sql);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (oldVersion < 3) {
|
||||||
|
for (String sql : SQL_V2_V3_UPGRADE) {
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldVersion < 4) {
|
||||||
|
for (String sql : SQL_V3_V4_UPGRADE) {
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldVersion < 5) {
|
||||||
|
for (String sql : SQL_V4_V5_UPGRADE) {
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldVersion < 6) {
|
||||||
|
for (String sql : SQL_V5_V6_UPGRADE) {
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldVersion < 7) {
|
||||||
|
for (String sql : SQL_V6_V7_UPGRADE) {
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldVersion < 8) {
|
||||||
|
for (String sql : SQL_V7_V8_UPGRADE) {
|
||||||
|
db.execSQL(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
|
||||||
|
@ -126,6 +215,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) {
|
public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) {
|
||||||
db.execSQL(SQL_CLEAR_URL_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) });
|
db.execSQL(SQL_CLEAR_URL_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) });
|
||||||
}
|
}
|
||||||
|
|
||||||
// History items are essentially url suggestions
|
// History items are essentially url suggestions
|
||||||
public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) {
|
public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) {
|
||||||
List<UrlSuggestion> suggestions = new ArrayList<>();
|
List<UrlSuggestion> suggestions = new ArrayList<>();
|
||||||
|
@ -225,11 +315,21 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void createOrUpdateSubscription(Subscription subscription, SQLiteDatabase db) {
|
public static void createOrUpdateSubscription(Subscription subscription, SQLiteDatabase db) {
|
||||||
db.execSQL(SQL_INSERT_SUBSCRIPTION, new Object[] { subscription.getChannelName(), subscription.getUrl() });
|
db.execSQL(SQL_INSERT_SUBSCRIPTION, new Object[] {
|
||||||
|
subscription.getChannelName(),
|
||||||
|
subscription.getUrl(),
|
||||||
|
subscription.isNotificationsDisabled() ? 1 : 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void setSubscriptionNotificationDisabled(boolean flag, String url, SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_UPDATE_SUBSCRIPTION_NOTIFICATION, new Object[] { flag ? 1 : 0, url });
|
||||||
}
|
}
|
||||||
public static void deleteSubscription(Subscription subscription, SQLiteDatabase db) {
|
public static void deleteSubscription(Subscription subscription, SQLiteDatabase db) {
|
||||||
db.execSQL(SQL_DELETE_SUBSCRIPTION, new Object[] { subscription.getUrl() });
|
db.execSQL(SQL_DELETE_SUBSCRIPTION, new Object[] { subscription.getUrl() });
|
||||||
}
|
}
|
||||||
|
public static void clearSubscriptions(SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_CLEAR_SUBSCRIPTIONS);
|
||||||
|
}
|
||||||
public static List<Subscription> getSubscriptions(SQLiteDatabase db) {
|
public static List<Subscription> getSubscriptions(SQLiteDatabase db) {
|
||||||
List<Subscription> subscriptions = new ArrayList<>();
|
List<Subscription> subscriptions = new ArrayList<>();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
@ -239,6 +339,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
Subscription subscription = new Subscription();
|
Subscription subscription = new Subscription();
|
||||||
subscription.setChannelName(cursor.getString(0));
|
subscription.setChannelName(cursor.getString(0));
|
||||||
subscription.setUrl(cursor.getString(1));
|
subscription.setUrl(cursor.getString(1));
|
||||||
|
subscription.setNotificationsDisabled(cursor.getInt(2) == 1);
|
||||||
subscriptions.add(subscription);
|
subscriptions.add(subscription);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -247,4 +348,112 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
return subscriptions;
|
return subscriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void createOrUpdateNotification(LbryNotification notification, SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_INSERT_NOTIFICATION, new Object[] {
|
||||||
|
notification.getRemoteId(),
|
||||||
|
notification.getAuthorUrl(),
|
||||||
|
notification.getTitle(),
|
||||||
|
notification.getDescription(),
|
||||||
|
notification.getRule(),
|
||||||
|
notification.getTargetUrl(),
|
||||||
|
notification.isRead() ? 1 : 0,
|
||||||
|
notification.isSeen() ? 1 : 0,
|
||||||
|
new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(notification.getTimestamp() != null ? notification.getTimestamp() : new Date())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static List<LbryNotification> getNotifications(SQLiteDatabase db) {
|
||||||
|
List<LbryNotification> notifications = new ArrayList<>();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = db.rawQuery(SQL_GET_NOTIFICATIONS, null);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
LbryNotification notification = new LbryNotification();
|
||||||
|
int columnIndex = 0;
|
||||||
|
notification.setId(cursor.getLong(columnIndex++));
|
||||||
|
notification.setRemoteId(cursor.getLong(columnIndex++));
|
||||||
|
notification.setAuthorUrl(cursor.getString(columnIndex++));
|
||||||
|
notification.setTitle(cursor.getString(columnIndex++));
|
||||||
|
notification.setDescription(cursor.getString(columnIndex++));
|
||||||
|
notification.setRule(cursor.getString(columnIndex++));
|
||||||
|
notification.setTargetUrl(cursor.getString(columnIndex++));
|
||||||
|
notification.setRead(cursor.getInt(columnIndex++) == 1);
|
||||||
|
notification.setSeen(cursor.getInt(columnIndex++) == 1);
|
||||||
|
try {
|
||||||
|
notification.setTimestamp(new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).parse(cursor.getString(columnIndex++)));
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
// invalid timestamp (which shouldn't happen). Skip this item
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
notifications.add(notification);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Helper.closeCursor(cursor);
|
||||||
|
}
|
||||||
|
return notifications;
|
||||||
|
}
|
||||||
|
public static void deleteNotifications(List<LbryNotification> notifications, SQLiteDatabase db) {
|
||||||
|
StringBuilder sb = new StringBuilder("DELETE FROM notifications WHERE remote_id IN (");
|
||||||
|
List<Object> remoteIds = new ArrayList<>();
|
||||||
|
String delim = "";
|
||||||
|
for (int i = 0; i < notifications.size(); i++) {
|
||||||
|
remoteIds.add(String.valueOf(notifications.get(i).getRemoteId()));
|
||||||
|
sb.append(delim).append("?");
|
||||||
|
delim = ",";
|
||||||
|
}
|
||||||
|
sb.append(")");
|
||||||
|
|
||||||
|
String sql = sb.toString();
|
||||||
|
db.execSQL(sql, remoteIds.toArray());
|
||||||
|
}
|
||||||
|
public static int getUnreadNotificationsCount(SQLiteDatabase db) {
|
||||||
|
int count = 0;
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = db.rawQuery(SQL_GET_UNREAD_NOTIFICATIONS_COUNT, null);
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
count = cursor.getInt(0);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Helper.closeCursor(cursor);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
public static int getUnseenNotificationsCount(SQLiteDatabase db) {
|
||||||
|
int count = 0;
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = db.rawQuery(SQL_GET_UNSEEN_NOTIFICATIONS_COUNT, null);
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
count = cursor.getInt(0);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Helper.closeCursor(cursor);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
public static void markNotificationsSeen(SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_MARK_NOTIFICATIONS_SEEN);
|
||||||
|
}
|
||||||
|
public static void markNotificationsRead(SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_MARK_NOTIFICATIONS_READ);
|
||||||
|
}
|
||||||
|
public static void markNotificationReadAndSeen(long notificationId, SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_MARK_NOTIFICATION_READ_AND_SEEN, new Object[] { notificationId });
|
||||||
|
}
|
||||||
|
public static void createOrUpdateShuffleWatched(String claimId, SQLiteDatabase db) {
|
||||||
|
db.execSQL(SQL_INSERT_SHUFFLE_WATCHED, new Object[] { claimId });
|
||||||
|
}
|
||||||
|
public static List<String> getShuffleWatchedClaims(SQLiteDatabase db) {
|
||||||
|
List<String> claimIds = new ArrayList<>();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = db.rawQuery(SQL_GET_SHUFFLE_WATCHED_CLAIMS, null);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
claimIds.add(cursor.getString(0));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Helper.closeCursor(cursor);
|
||||||
|
}
|
||||||
|
return claimIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,8 @@ public class ContentFromDialogFragment extends BottomSheetDialogFragment {
|
||||||
R.id.content_from_past_year_item,
|
R.id.content_from_past_year_item,
|
||||||
R.id.content_from_all_time_item
|
R.id.content_from_all_time_item
|
||||||
};
|
};
|
||||||
private BottomSheetDialogFragment dialog;
|
private final BottomSheetDialogFragment dialog;
|
||||||
private ContentFromListener listener;
|
private final ContentFromListener listener;
|
||||||
|
|
||||||
public ContentFromItemClickListener(BottomSheetDialogFragment dialog, ContentFromListener listener) {
|
public ContentFromItemClickListener(BottomSheetDialogFragment dialog, ContentFromListener listener) {
|
||||||
this.dialog = dialog;
|
this.dialog = dialog;
|
||||||
|
|
|
@ -54,8 +54,8 @@ public class ContentScopeDialogFragment extends BottomSheetDialogFragment {
|
||||||
private final int[] checkViewIds = {
|
private final int[] checkViewIds = {
|
||||||
R.id.content_scope_everyone_item_selected, R.id.content_scope_tags_item_selected
|
R.id.content_scope_everyone_item_selected, R.id.content_scope_tags_item_selected
|
||||||
};
|
};
|
||||||
private BottomSheetDialogFragment dialog;
|
private final BottomSheetDialogFragment dialog;
|
||||||
private ContentScopeListener listener;
|
private final ContentScopeListener listener;
|
||||||
|
|
||||||
public ContentScopeItemClickListener(BottomSheetDialogFragment dialog, ContentScopeListener listener) {
|
public ContentScopeItemClickListener(BottomSheetDialogFragment dialog, ContentScopeListener listener) {
|
||||||
this.dialog = dialog;
|
this.dialog = dialog;
|
||||||
|
|
|
@ -57,8 +57,8 @@ public class ContentSortDialogFragment extends BottomSheetDialogFragment {
|
||||||
private final int[] checkViewIds = {
|
private final int[] checkViewIds = {
|
||||||
R.id.sort_by_trending_item_selected, R.id.sort_by_new_item_selected, R.id.sort_by_top_item_selected
|
R.id.sort_by_trending_item_selected, R.id.sort_by_new_item_selected, R.id.sort_by_top_item_selected
|
||||||
};
|
};
|
||||||
private BottomSheetDialogFragment dialog;
|
private final BottomSheetDialogFragment dialog;
|
||||||
private SortByListener listener;
|
private final SortByListener listener;
|
||||||
|
|
||||||
public SortByItemClickListener(BottomSheetDialogFragment dialog, SortByListener listener) {
|
public SortByItemClickListener(BottomSheetDialogFragment dialog, SortByListener listener) {
|
||||||
this.dialog = dialog;
|
this.dialog = dialog;
|
||||||
|
|
|
@ -0,0 +1,349 @@
|
||||||
|
package io.lbry.browser.dialog;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.AppCompatSpinner;
|
||||||
|
import androidx.core.text.HtmlCompat;
|
||||||
|
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.lbry.browser.MainActivity;
|
||||||
|
import io.lbry.browser.R;
|
||||||
|
import io.lbry.browser.adapter.InlineChannelSpinnerAdapter;
|
||||||
|
import io.lbry.browser.listener.WalletBalanceListener;
|
||||||
|
import io.lbry.browser.model.Claim;
|
||||||
|
import io.lbry.browser.model.WalletBalance;
|
||||||
|
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||||
|
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
||||||
|
import io.lbry.browser.tasks.claim.ClaimListTask;
|
||||||
|
import io.lbry.browser.tasks.wallet.SupportCreateTask;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
|
public class CreateSupportDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener {
|
||||||
|
public static final String TAG = "CreateSupportDialog";
|
||||||
|
|
||||||
|
private MaterialButton sendButton;
|
||||||
|
private View cancelLink;
|
||||||
|
private TextInputEditText inputAmount;
|
||||||
|
private View inlineBalanceContainer;
|
||||||
|
private TextView inlineBalanceValue;
|
||||||
|
private ProgressBar sendProgress;
|
||||||
|
|
||||||
|
private InlineChannelSpinnerAdapter channelSpinnerAdapter;
|
||||||
|
private AppCompatSpinner channelSpinner;
|
||||||
|
private SwitchMaterial switchTip;
|
||||||
|
|
||||||
|
private boolean fetchingChannels;
|
||||||
|
private ProgressBar progressLoadingChannels;
|
||||||
|
|
||||||
|
|
||||||
|
private final CreateSupportListener listener;
|
||||||
|
private final Claim claim;
|
||||||
|
|
||||||
|
private CreateSupportDialogFragment(Claim claim, CreateSupportListener listener) {
|
||||||
|
super();
|
||||||
|
this.claim = claim;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CreateSupportDialogFragment newInstance(Claim claim, CreateSupportListener listener) {
|
||||||
|
return new CreateSupportDialogFragment(claim, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableControls() {
|
||||||
|
Dialog dialog = getDialog();
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog.setCanceledOnTouchOutside(false);
|
||||||
|
}
|
||||||
|
channelSpinner.setEnabled(false);
|
||||||
|
switchTip.setEnabled(false);
|
||||||
|
sendButton.setEnabled(false);
|
||||||
|
cancelLink.setEnabled(false);
|
||||||
|
}
|
||||||
|
private void enableControls() {
|
||||||
|
Dialog dialog = getDialog();
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog.setCanceledOnTouchOutside(true);
|
||||||
|
}
|
||||||
|
channelSpinner.setEnabled(true);
|
||||||
|
switchTip.setEnabled(true);
|
||||||
|
sendButton.setEnabled(true);
|
||||||
|
cancelLink.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.dialog_create_support, container, false);
|
||||||
|
|
||||||
|
inputAmount = view.findViewById(R.id.create_support_input_amount);
|
||||||
|
inlineBalanceContainer = view.findViewById(R.id.create_support_inline_balance_container);
|
||||||
|
inlineBalanceValue = view.findViewById(R.id.create_support_inline_balance_value);
|
||||||
|
sendProgress = view.findViewById(R.id.create_support_progress);
|
||||||
|
cancelLink = view.findViewById(R.id.create_support_cancel_link);
|
||||||
|
sendButton = view.findViewById(R.id.create_support_send);
|
||||||
|
|
||||||
|
channelSpinner = view.findViewById(R.id.create_support_channel_spinner);
|
||||||
|
switchTip = view.findViewById(R.id.create_support_make_tip_switch);
|
||||||
|
progressLoadingChannels = view.findViewById(R.id.create_support_channel_progress);
|
||||||
|
|
||||||
|
inputAmount.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onFocusChange(View view, boolean hasFocus) {
|
||||||
|
inputAmount.setHint(hasFocus ? getString(R.string.zero) : "");
|
||||||
|
inlineBalanceContainer.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
inputAmount.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||||
|
updateSendButtonText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateInfoText();
|
||||||
|
updateSendButtonText();
|
||||||
|
|
||||||
|
String channel = null;
|
||||||
|
if (Claim.TYPE_CHANNEL.equalsIgnoreCase(claim.getValueType())) {
|
||||||
|
channel = claim.getTitleOrName();
|
||||||
|
} else if (claim.getSigningChannel() != null) {
|
||||||
|
channel = claim.getPublisherTitle();
|
||||||
|
}
|
||||||
|
TextView titleView = view.findViewById(R.id.create_support_title);
|
||||||
|
String tipTitleText = Helper.isNullOrEmpty(channel) ? getString(R.string.send_a_tip) : getString(R.string.send_a_tip_to, channel);
|
||||||
|
titleView.setText(tipTitleText);
|
||||||
|
|
||||||
|
switchTip.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||||
|
if (checked) {
|
||||||
|
// show tip info
|
||||||
|
titleView.setText(tipTitleText);
|
||||||
|
updateSendButtonText();
|
||||||
|
} else {
|
||||||
|
// show support info
|
||||||
|
titleView.setText(R.string.support_this_content);
|
||||||
|
sendButton.setText(R.string.send_revocable_support);
|
||||||
|
}
|
||||||
|
updateInfoText();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sendButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
String amountString = Helper.getValue(inputAmount.getText());
|
||||||
|
if (Helper.isNullOrEmpty(amountString)) {
|
||||||
|
showError(getString(R.string.invalid_amount));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal amount = new BigDecimal(amountString);
|
||||||
|
if (amount.doubleValue() > Lbry.walletBalance.getAvailable().doubleValue()) {
|
||||||
|
showError(getString(R.string.insufficient_balance));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (amount.doubleValue() < Helper.MIN_SPEND) {
|
||||||
|
showError(getString(R.string.min_spend_required));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Claim selectedChannel = (Claim) channelSpinner.getSelectedItem();
|
||||||
|
String channelId = !fetchingChannels && selectedChannel != null ? selectedChannel.getClaimId() : null;
|
||||||
|
boolean isTip = switchTip.isChecked();
|
||||||
|
SupportCreateTask task = new SupportCreateTask(
|
||||||
|
claim.getClaimId(), channelId, amount, isTip, sendProgress, new GenericTaskHandler() {
|
||||||
|
@Override
|
||||||
|
public void beforeStart() {
|
||||||
|
disableControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
enableControls();
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onSupportCreated(amount, isTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception error) {
|
||||||
|
showError(error.getMessage());
|
||||||
|
enableControls();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelLink.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onWalletBalanceUpdated(Lbry.walletBalance);
|
||||||
|
updateInfoText();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSendButtonText() {
|
||||||
|
boolean isTip = switchTip.isChecked();
|
||||||
|
if (!isTip) {
|
||||||
|
sendButton.setText(R.string.send_revocable_support);
|
||||||
|
} else {
|
||||||
|
String amountString = Helper.getValue(inputAmount.getText(), "0");
|
||||||
|
double parsedAmount = Helper.parseDouble(amountString, 0);
|
||||||
|
String text = getResources().getQuantityString(R.plurals.send_lbc_tip, parsedAmount == 1.0 ? 1 : 2, amountString);
|
||||||
|
sendButton.setText(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInfoText() {
|
||||||
|
View view = getView();
|
||||||
|
if (view != null && switchTip != null) {
|
||||||
|
TextView infoText = view.findViewById(R.id.create_support_info);
|
||||||
|
boolean isTip = switchTip.isChecked();
|
||||||
|
|
||||||
|
infoText.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
if (!isTip) {
|
||||||
|
infoText.setText(HtmlCompat.fromHtml(getString(R.string.support_info), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
|
} else if (claim != null) {
|
||||||
|
infoText.setText(HtmlCompat.fromHtml(
|
||||||
|
Claim.TYPE_CHANNEL.equalsIgnoreCase(claim.getValueType()) ?
|
||||||
|
getString(R.string.send_tip_info_channel, claim.getTitleOrName()) :
|
||||||
|
getString(R.string.send_tip_info_content, claim.getTitleOrName()),
|
||||||
|
HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchChannels() {
|
||||||
|
if (Lbry.ownChannels != null && Lbry.ownChannels.size() > 0) {
|
||||||
|
updateChannelList(Lbry.ownChannels);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchingChannels = true;
|
||||||
|
disableChannelSpinner();
|
||||||
|
ClaimListTask task = new ClaimListTask(Claim.TYPE_CHANNEL, progressLoadingChannels, new ClaimListResultHandler() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<Claim> claims) {
|
||||||
|
Lbry.ownChannels = new ArrayList<>(claims);
|
||||||
|
updateChannelList(Lbry.ownChannels);
|
||||||
|
enableChannelSpinner();
|
||||||
|
fetchingChannels = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception error) {
|
||||||
|
enableChannelSpinner();
|
||||||
|
fetchingChannels = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
private void disableChannelSpinner() {
|
||||||
|
Helper.setViewEnabled(channelSpinner, false);
|
||||||
|
}
|
||||||
|
private void enableChannelSpinner() {
|
||||||
|
Helper.setViewEnabled(channelSpinner, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateChannelList(List<Claim> channels) {
|
||||||
|
if (channelSpinnerAdapter == null) {
|
||||||
|
Context context = getContext();
|
||||||
|
if (context != null) {
|
||||||
|
channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, new ArrayList<>(channels));
|
||||||
|
channelSpinnerAdapter.addAnonymousPlaceholder();
|
||||||
|
channelSpinnerAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channelSpinnerAdapter.clear();
|
||||||
|
channelSpinnerAdapter.addAll(channels);
|
||||||
|
channelSpinnerAdapter.addAnonymousPlaceholder();
|
||||||
|
channelSpinnerAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelSpinner != null) {
|
||||||
|
channelSpinner.setAdapter(channelSpinnerAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelSpinnerAdapter != null && channelSpinner != null) {
|
||||||
|
if (channelSpinnerAdapter.getCount() > 1) {
|
||||||
|
channelSpinner.setSelection(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
Context context = getContext();
|
||||||
|
if (context instanceof MainActivity) {
|
||||||
|
((MainActivity) context).addWalletBalanceListener(this);
|
||||||
|
}
|
||||||
|
updateInfoText();
|
||||||
|
fetchChannels();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPause() {
|
||||||
|
Context context = getContext();
|
||||||
|
if (context instanceof MainActivity) {
|
||||||
|
((MainActivity) context).removeWalletBalanceListener(this);
|
||||||
|
}
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWalletBalanceUpdated(WalletBalance walletBalance) {
|
||||||
|
if (walletBalance != null && inlineBalanceValue != null) {
|
||||||
|
inlineBalanceValue.setText(Helper.shortCurrencyFormat(walletBalance.getAvailable().doubleValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showError(String message) {
|
||||||
|
Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
|
||||||
|
setBackgroundTint(Color.RED).
|
||||||
|
setTextColor(Color.WHITE).
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface CreateSupportListener {
|
||||||
|
void onSupportCreated(BigDecimal amount, boolean isTip);
|
||||||
|
}
|
||||||
|
}
|
|
@ -142,7 +142,7 @@ public class CustomizeTagsDialogFragment extends BottomSheetDialogFragment {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
|
private final TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onTagClicked(Tag tag, int customizeMode) {
|
public void onTagClicked(Tag tag, int customizeMode) {
|
||||||
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {
|
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ProgressBar;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
|
|
|
@ -37,7 +37,6 @@ import io.lbry.browser.tasks.claim.StreamRepostTask;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
import io.lbry.browser.utils.LbryUri;
|
import io.lbry.browser.utils.LbryUri;
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
public class RepostClaimDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener {
|
public class RepostClaimDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener {
|
||||||
public static final String TAG = "RepostClaimDialog";
|
public static final String TAG = "RepostClaimDialog";
|
||||||
|
@ -57,13 +56,17 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
||||||
private TextView linkToggleAdvanced;
|
private TextView linkToggleAdvanced;
|
||||||
private View advancedContainer;
|
private View advancedContainer;
|
||||||
|
|
||||||
@Setter
|
private final RepostClaimListener listener;
|
||||||
private RepostClaimListener listener;
|
private final Claim claim;
|
||||||
@Setter
|
|
||||||
private Claim claim;
|
|
||||||
|
|
||||||
public static RepostClaimDialogFragment newInstance() {
|
private RepostClaimDialogFragment(Claim claim, RepostClaimListener listener) {
|
||||||
return new RepostClaimDialogFragment();
|
super();
|
||||||
|
this.listener = listener;
|
||||||
|
this.claim = claim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RepostClaimDialogFragment newInstance(Claim claim, RepostClaimListener listener) {
|
||||||
|
return new RepostClaimDialogFragment(claim, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -192,14 +195,16 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
||||||
private void loadChannels(List<Claim> channels) {
|
private void loadChannels(List<Claim> channels) {
|
||||||
if (channelSpinnerAdapter == null) {
|
if (channelSpinnerAdapter == null) {
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels);
|
if (context != null) {
|
||||||
channelSpinnerAdapter.notifyDataSetChanged();
|
channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels);
|
||||||
|
channelSpinnerAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
channelSpinnerAdapter.clear();
|
channelSpinnerAdapter.clear();
|
||||||
channelSpinnerAdapter.addAll(channels);
|
channelSpinnerAdapter.addAll(channels);
|
||||||
channelSpinnerAdapter.notifyDataSetChanged();
|
channelSpinnerAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
if (channelSpinner != null) {
|
if (channelSpinner != null && channelSpinnerAdapter != null) {
|
||||||
channelSpinner.setAdapter(channelSpinnerAdapter);
|
channelSpinner.setAdapter(channelSpinnerAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,8 +234,18 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
||||||
showError(getString(R.string.insufficient_balance));
|
showError(getString(R.string.insufficient_balance));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (bid.doubleValue() < Helper.MIN_DEPOSIT) {
|
||||||
|
String message = getResources().getQuantityString(R.plurals.min_deposit_required, 2, String.valueOf(Helper.MIN_DEPOSIT));
|
||||||
|
showError(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Claim channel = (Claim) channelSpinner.getSelectedItem();
|
Claim channel = (Claim) channelSpinner.getSelectedItem();
|
||||||
|
if (channel == null) {
|
||||||
|
showError(getString(R.string.please_select_repost_channel));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StreamRepostTask task = new StreamRepostTask(name, bid, claim.getClaimId(), channel.getClaimId(), repostProgress, new ClaimResultHandler() {
|
StreamRepostTask task = new StreamRepostTask(name, bid, claim.getClaimId(), channel.getClaimId(), repostProgress, new ClaimResultHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeStart() {
|
public void beforeStart() {
|
||||||
|
@ -256,10 +271,13 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showError(String message) {
|
private void showError(String message) {
|
||||||
Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
|
View view = getView();
|
||||||
setBackgroundTint(Color.RED).
|
if (view != null && !Helper.isNullOrEmpty(message)) {
|
||||||
setTextColor(Color.WHITE).
|
Snackbar.make(view, message, Snackbar.LENGTH_LONG).
|
||||||
show();
|
setBackgroundTint(Color.RED).
|
||||||
|
setTextColor(Color.WHITE).
|
||||||
|
show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startLoading() {
|
private void startLoading() {
|
||||||
|
|
|
@ -1,196 +0,0 @@
|
||||||
package io.lbry.browser.dialog;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.core.text.HtmlCompat;
|
|
||||||
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
|
||||||
import io.lbry.browser.R;
|
|
||||||
import io.lbry.browser.listener.WalletBalanceListener;
|
|
||||||
import io.lbry.browser.model.Claim;
|
|
||||||
import io.lbry.browser.model.WalletBalance;
|
|
||||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
|
||||||
import io.lbry.browser.tasks.wallet.SupportCreateTask;
|
|
||||||
import io.lbry.browser.utils.Helper;
|
|
||||||
import io.lbry.browser.utils.Lbry;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
public class SendTipDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener {
|
|
||||||
public static final String TAG = "SendTipDialog";
|
|
||||||
|
|
||||||
private MaterialButton sendButton;
|
|
||||||
private View cancelLink;
|
|
||||||
private TextInputEditText inputAmount;
|
|
||||||
private View inlineBalanceContainer;
|
|
||||||
private TextView inlineBalanceValue;
|
|
||||||
private ProgressBar sendProgress;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private SendTipListener listener;
|
|
||||||
@Setter
|
|
||||||
private Claim claim;
|
|
||||||
|
|
||||||
public static SendTipDialogFragment newInstance() {
|
|
||||||
return new SendTipDialogFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disableControls() {
|
|
||||||
Dialog dialog = getDialog();
|
|
||||||
if (dialog != null) {
|
|
||||||
dialog.setCanceledOnTouchOutside(false);
|
|
||||||
}
|
|
||||||
sendButton.setEnabled(false);
|
|
||||||
cancelLink.setEnabled(false);
|
|
||||||
}
|
|
||||||
private void enableControls() {
|
|
||||||
Dialog dialog = getDialog();
|
|
||||||
if (dialog != null) {
|
|
||||||
dialog.setCanceledOnTouchOutside(true);
|
|
||||||
}
|
|
||||||
sendButton.setEnabled(true);
|
|
||||||
cancelLink.setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.dialog_send_tip, container, false);
|
|
||||||
|
|
||||||
inputAmount = view.findViewById(R.id.tip_input_amount);
|
|
||||||
inlineBalanceContainer = view.findViewById(R.id.tip_inline_balance_container);
|
|
||||||
inlineBalanceValue = view.findViewById(R.id.tip_inline_balance_value);
|
|
||||||
sendProgress = view.findViewById(R.id.tip_send_progress);
|
|
||||||
cancelLink = view.findViewById(R.id.tip_cancel_link);
|
|
||||||
sendButton = view.findViewById(R.id.tip_send);
|
|
||||||
|
|
||||||
inputAmount.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onFocusChange(View view, boolean hasFocus) {
|
|
||||||
inputAmount.setHint(hasFocus ? getString(R.string.zero) : "");
|
|
||||||
inlineBalanceContainer.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
TextView infoText = view.findViewById(R.id.tip_info);
|
|
||||||
infoText.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
infoText.setText(HtmlCompat.fromHtml(
|
|
||||||
Claim.TYPE_CHANNEL.equalsIgnoreCase(claim.getValueType()) ?
|
|
||||||
getString(R.string.send_tip_info_channel, claim.getTitleOrName()) :
|
|
||||||
getString(R.string.send_tip_info_content, claim.getTitleOrName()),
|
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY));
|
|
||||||
|
|
||||||
sendButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
String amountString = Helper.getValue(inputAmount.getText());
|
|
||||||
if (Helper.isNullOrEmpty(amountString)) {
|
|
||||||
showError(getString(R.string.invalid_amount));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal amount = new BigDecimal(amountString);
|
|
||||||
if (amount.doubleValue() > Lbry.walletBalance.getAvailable().doubleValue()) {
|
|
||||||
showError(getString(R.string.insufficient_balance));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SupportCreateTask task = new SupportCreateTask(claim.getClaimId(), amount, true, sendProgress, new GenericTaskHandler() {
|
|
||||||
@Override
|
|
||||||
public void beforeStart() {
|
|
||||||
disableControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSuccess() {
|
|
||||||
enableControls();
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onTipSent(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Exception error) {
|
|
||||||
showError(error.getMessage());
|
|
||||||
enableControls();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
cancelLink.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
String channel = null;
|
|
||||||
if (Claim.TYPE_CHANNEL.equalsIgnoreCase(claim.getValueType())) {
|
|
||||||
channel = claim.getTitleOrName();
|
|
||||||
} else if (claim.getSigningChannel() != null) {
|
|
||||||
channel = claim.getPublisherTitle();
|
|
||||||
}
|
|
||||||
((TextView) view.findViewById(R.id.tip_send_title)).setText(
|
|
||||||
Helper.isNullOrEmpty(channel) ? getString(R.string.send_a_tip) : getString(R.string.send_a_tip_to, channel)
|
|
||||||
);
|
|
||||||
|
|
||||||
onWalletBalanceUpdated(Lbry.walletBalance);
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
Context context = getContext();
|
|
||||||
if (context instanceof MainActivity) {
|
|
||||||
((MainActivity) context).addWalletBalanceListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPause() {
|
|
||||||
Context context = getContext();
|
|
||||||
if (context instanceof MainActivity) {
|
|
||||||
((MainActivity) context).removeWalletBalanceListener(this);
|
|
||||||
}
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWalletBalanceUpdated(WalletBalance walletBalance) {
|
|
||||||
if (walletBalance != null && inlineBalanceValue != null) {
|
|
||||||
inlineBalanceValue.setText(Helper.shortCurrencyFormat(walletBalance.getAvailable().doubleValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showError(String message) {
|
|
||||||
Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
|
|
||||||
setBackgroundTint(Color.RED).
|
|
||||||
setTextColor(Color.WHITE).
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface SendTipListener {
|
|
||||||
void onTipSent(BigDecimal amount);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package io.lbry.browser.exceptions;
|
||||||
|
|
||||||
|
public class AuthTokenInvalidatedException extends Exception {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.lbry.browser.listener;
|
||||||
|
|
||||||
|
public interface PIPModeListener {
|
||||||
|
void onEnterPIPMode();
|
||||||
|
void onExitPIPMode();
|
||||||
|
}
|
|
@ -7,4 +7,7 @@ public interface SignInListener {
|
||||||
void onPhoneAdded(String countryCode, String phoneNumber);
|
void onPhoneAdded(String countryCode, String phoneNumber);
|
||||||
void onPhoneVerified();
|
void onPhoneVerified();
|
||||||
void onManualVerifyContinue();
|
void onManualVerifyContinue();
|
||||||
|
void onSkipQueueAction();
|
||||||
|
void onTwitterVerified();
|
||||||
|
void onManualProgress(boolean progress);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package io.lbry.browser.model;
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.gson.FieldNamingPolicy;
|
import com.google.gson.FieldNamingPolicy;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
@ -15,7 +17,6 @@ import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.LbryUri;
|
import io.lbry.browser.utils.LbryUri;
|
||||||
|
@ -54,6 +55,7 @@ public class Claim {
|
||||||
@EqualsAndHashCode.Include
|
@EqualsAndHashCode.Include
|
||||||
private boolean placeholder;
|
private boolean placeholder;
|
||||||
private boolean placeholderAnonymous;
|
private boolean placeholderAnonymous;
|
||||||
|
private boolean loadingPlaceholder;
|
||||||
private boolean featured;
|
private boolean featured;
|
||||||
private boolean unresolved; // used for featured
|
private boolean unresolved; // used for featured
|
||||||
private String address;
|
private String address;
|
||||||
|
@ -137,6 +139,14 @@ public class Claim {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasSource() {
|
||||||
|
if (value instanceof StreamMetadata) {
|
||||||
|
StreamMetadata metadata = (StreamMetadata) value;
|
||||||
|
return metadata.getSource() != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPlayable() {
|
public boolean isPlayable() {
|
||||||
if (value instanceof StreamMetadata) {
|
if (value instanceof StreamMetadata) {
|
||||||
StreamMetadata metadata = (StreamMetadata) value;
|
StreamMetadata metadata = (StreamMetadata) value;
|
||||||
|
@ -176,6 +186,21 @@ public class Claim {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL from the CDN where getting the image file
|
||||||
|
* @param width Pass zero for width and height for the full size image file
|
||||||
|
* @param height Pass zero for width and height for the full size image file
|
||||||
|
* @param q Desired quality for the image to be retrieved
|
||||||
|
* @return URL from the CDN from where image can be retrieved
|
||||||
|
*/
|
||||||
|
public String getThumbnailUrl(int width, int height, int q) {
|
||||||
|
if (value != null && value.getThumbnail() != null) {
|
||||||
|
ImageCDNUrl imageCDNUrl = new ImageCDNUrl(Math.max(width, 0), Math.max(height, 0), q, null, value.getThumbnail().getUrl());
|
||||||
|
return imageCDNUrl.toString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public String getCoverUrl() {
|
public String getCoverUrl() {
|
||||||
if (TYPE_CHANNEL.equals(valueType) && value != null && value instanceof ChannelMetadata && ((ChannelMetadata) value).getCover() != null) {
|
if (TYPE_CHANNEL.equals(valueType) && value != null && value instanceof ChannelMetadata && ((ChannelMetadata) value).getCover() != null) {
|
||||||
return ((ChannelMetadata) value).getCover().getUrl();
|
return ((ChannelMetadata) value).getCover().getUrl();
|
||||||
|
@ -289,6 +314,9 @@ public class Claim {
|
||||||
Claim signingChannel = new Claim();
|
Claim signingChannel = new Claim();
|
||||||
signingChannel.setClaimId(viewHistory.getPublisherClaimId());
|
signingChannel.setClaimId(viewHistory.getPublisherClaimId());
|
||||||
signingChannel.setName(viewHistory.getPublisherName());
|
signingChannel.setName(viewHistory.getPublisherName());
|
||||||
|
|
||||||
|
LbryUri channelUrl = LbryUri.tryParse(String.format("%s#%s", signingChannel.getName(), signingChannel.getClaimId()));
|
||||||
|
signingChannel.setPermanentUrl(channelUrl != null ? channelUrl.toString() : null);
|
||||||
if (!Helper.isNullOrEmpty(viewHistory.getPublisherTitle())) {
|
if (!Helper.isNullOrEmpty(viewHistory.getPublisherTitle())) {
|
||||||
GenericMetadata channelValue = new GenericMetadata();
|
GenericMetadata channelValue = new GenericMetadata();
|
||||||
channelValue.setTitle(viewHistory.getPublisherTitle());
|
channelValue.setTitle(viewHistory.getPublisherTitle());
|
||||||
|
@ -480,6 +508,30 @@ public class Claim {
|
||||||
private String url;
|
private String url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object to be instantiated. In order to get the URLto the CDN, call toString() on it
|
||||||
|
*/
|
||||||
|
static class ImageCDNUrl {
|
||||||
|
private String appendedPath = "";
|
||||||
|
|
||||||
|
public ImageCDNUrl(int width, int height, int quality, @Nullable String format, String thumbnailUrl) {
|
||||||
|
if (width != 0 && height != 0)
|
||||||
|
appendedPath = "s:".concat(String.valueOf(width)).concat(":").concat(String.valueOf(height)).concat("/");
|
||||||
|
|
||||||
|
appendedPath = appendedPath.concat("quality:").concat(String.valueOf(quality)).concat("/");
|
||||||
|
|
||||||
|
appendedPath = appendedPath.concat("plain/").concat(thumbnailUrl);
|
||||||
|
|
||||||
|
if (format != null)
|
||||||
|
appendedPath = appendedPath.concat("@").concat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String url = "https://image-processor.vanwanet.com/optimize/";
|
||||||
|
return url.concat(appendedPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
@Data
|
@Data
|
||||||
public static class StreamInfo {
|
public static class StreamInfo {
|
||||||
private long duration; // video / audio
|
private long duration; // video / audio
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class ClaimCacheKey {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object obj) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
if (obj == null || !(obj instanceof ClaimCacheKey)) {
|
if (!(obj instanceof ClaimCacheKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ClaimCacheKey key = (ClaimCacheKey) obj;
|
ClaimCacheKey key = (ClaimCacheKey) obj;
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
package io.lbry.browser.model;
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
public class ClaimSearchCacheValue {
|
public class ClaimSearchCacheValue {
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
private final List<Claim> claims;
|
||||||
private List<Claim> claims;
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
private final long timestamp;
|
||||||
private long timestamp;
|
|
||||||
|
|
||||||
public ClaimSearchCacheValue(List<Claim> claims, long timestamp) {
|
public ClaimSearchCacheValue(List<Claim> claims, long timestamp) {
|
||||||
this.claims = new ArrayList<>(claims);
|
this.claims = new ArrayList<>(claims);
|
||||||
|
|
72
app/src/main/java/io/lbry/browser/model/Comment.java
Normal file
72
app/src/main/java/io/lbry/browser/model/Comment.java
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Comment implements Comparable<Comment> {
|
||||||
|
public static final int MAX_LENGTH = 2000;
|
||||||
|
|
||||||
|
private Claim poster;
|
||||||
|
private String claimId;
|
||||||
|
private List<Comment> replies;
|
||||||
|
private long timestamp;
|
||||||
|
private String channelId;
|
||||||
|
private String channelName, text, id, parentId;
|
||||||
|
|
||||||
|
public Comment(String channelId, String channelName, String text, String id, String parentId) {
|
||||||
|
this.channelId = channelId;
|
||||||
|
this.channelName = channelName;
|
||||||
|
this.text = text;
|
||||||
|
this.id = id;
|
||||||
|
this.parentId = parentId;
|
||||||
|
|
||||||
|
this.replies = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Comment() {
|
||||||
|
replies = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addReply(Comment reply) {
|
||||||
|
if (replies == null) {
|
||||||
|
replies = new ArrayList<>();
|
||||||
|
}
|
||||||
|
if (!replies.contains(reply)) {
|
||||||
|
replies.add(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Comment fromJSONObject(JSONObject jsonObject) {
|
||||||
|
try {
|
||||||
|
String parentId = null;
|
||||||
|
if (jsonObject.has("parent_id")) {
|
||||||
|
parentId = jsonObject.getString("parent_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
Comment comment = new Comment(
|
||||||
|
Helper.getJSONString("channel_id", null, jsonObject),
|
||||||
|
jsonObject.getString("channel_name"),
|
||||||
|
jsonObject.getString("comment"),
|
||||||
|
jsonObject.getString("comment_id"),
|
||||||
|
parentId
|
||||||
|
);
|
||||||
|
comment.setClaimId(Helper.getJSONString("claim_id", null, jsonObject));
|
||||||
|
comment.setTimestamp(Helper.getJSONLong("timestamp", 0, jsonObject));
|
||||||
|
return comment;
|
||||||
|
} catch (JSONException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Comment comment) {
|
||||||
|
return (int)(this.getTimestamp() - comment.getTimestamp());
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,9 @@ import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class Language {
|
public class Language {
|
||||||
private String code;
|
private final String code;
|
||||||
private String name;
|
private final String name;
|
||||||
private int stringResourceId;
|
private final int stringResourceId;
|
||||||
|
|
||||||
public Language(String code, String name, int stringResourceId) {
|
public Language(String code, String name, int stringResourceId) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
|
|
|
@ -4,9 +4,9 @@ import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class License {
|
public class License {
|
||||||
private String name;
|
private final String name;
|
||||||
private String url;
|
private String url;
|
||||||
private int stringResourceId;
|
private final int stringResourceId;
|
||||||
|
|
||||||
public License(String name, int stringResourceId) {
|
public License(String name, int stringResourceId) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
|
@ -2,8 +2,6 @@ package io.lbry.browser.model;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.core.content.res.ResourcesCompat;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -20,6 +18,7 @@ public class NavMenuItem {
|
||||||
public static final int ID_ITEM_FOLLOWING = 101;
|
public static final int ID_ITEM_FOLLOWING = 101;
|
||||||
public static final int ID_ITEM_EDITORS_CHOICE = 102;
|
public static final int ID_ITEM_EDITORS_CHOICE = 102;
|
||||||
public static final int ID_ITEM_ALL_CONTENT = 103;
|
public static final int ID_ITEM_ALL_CONTENT = 103;
|
||||||
|
public static final int ID_ITEM_SHUFFLE = 104;
|
||||||
|
|
||||||
// Your Content
|
// Your Content
|
||||||
public static final int ID_ITEM_CHANNELS = 201;
|
public static final int ID_ITEM_CHANNELS = 201;
|
||||||
|
@ -36,8 +35,8 @@ public class NavMenuItem {
|
||||||
public static final int ID_ITEM_SETTINGS = 401;
|
public static final int ID_ITEM_SETTINGS = 401;
|
||||||
public static final int ID_ITEM_ABOUT = 402;
|
public static final int ID_ITEM_ABOUT = 402;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private int id;
|
private final int id;
|
||||||
private boolean group;
|
private boolean group;
|
||||||
private int icon;
|
private int icon;
|
||||||
private String title;
|
private String title;
|
||||||
|
|
11
app/src/main/java/io/lbry/browser/model/StartupStage.java
Normal file
11
app/src/main/java/io/lbry/browser/model/StartupStage.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
|
public class StartupStage {
|
||||||
|
public final Integer stage;
|
||||||
|
public final Boolean stageDone;
|
||||||
|
|
||||||
|
public StartupStage(Integer stage, Boolean stageDone) {
|
||||||
|
this.stage = stage;
|
||||||
|
this.stageDone = stageDone;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,9 @@ import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
import io.lbry.browser.exceptions.LbryUriException;
|
import io.lbry.browser.exceptions.LbryUriException;
|
||||||
|
@ -53,13 +55,22 @@ public class Transaction {
|
||||||
|
|
||||||
int descStringId = -1;
|
int descStringId = -1;
|
||||||
TransactionInfo info = null;
|
TransactionInfo info = null;
|
||||||
|
List<TransactionInfo> infos = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
if (jsonObject.has("abandon_info")) {
|
if (jsonObject.has("abandon_info")) {
|
||||||
JSONArray array = jsonObject.getJSONArray("abandon_info");
|
JSONArray array = jsonObject.getJSONArray("abandon_info");
|
||||||
if (array.length() > 0) {
|
if (array.length() > 0) {
|
||||||
info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
|
if (array.length() == 1) {
|
||||||
descStringId = R.string.abandon;
|
info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
|
||||||
transaction.setAbandonInfo(info);
|
descStringId = info.getBalanceDelta().doubleValue() == info.getAmount().doubleValue() ? R.string.unlock : R.string.abandon;
|
||||||
|
transaction.setAbandonInfo(info);
|
||||||
|
} else {
|
||||||
|
// multiple abandon infos (txo_spend unlock tip)
|
||||||
|
descStringId = R.string.unlock;
|
||||||
|
for (int i = 0; i < array.length(); i++) {
|
||||||
|
infos.add(TransactionInfo.fromJSONObject(array.getJSONObject(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info == null && jsonObject.has("claim_info")) {
|
if (info == null && jsonObject.has("claim_info")) {
|
||||||
|
@ -94,8 +105,18 @@ public class Transaction {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transaction.getValue().doubleValue() == 0 && info != null && info.getBalanceDelta().doubleValue() != 0) {
|
|
||||||
transaction.setValue(info.getBalanceDelta());
|
|
||||||
|
if (transaction.getValue().doubleValue() == 0) {
|
||||||
|
if (info != null && info.getBalanceDelta().doubleValue() != 0) {
|
||||||
|
transaction.setValue(info.getBalanceDelta());
|
||||||
|
} else if (infos.size() > 0) {
|
||||||
|
BigDecimal total = new BigDecimal(0);
|
||||||
|
for (TransactionInfo txInfo : infos) {
|
||||||
|
total = total.add(txInfo.getAmount());
|
||||||
|
}
|
||||||
|
transaction.setValue(total);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descStringId == -1) {
|
if (descStringId == -1) {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TwitterOauth {
|
||||||
|
private String oauthToken;
|
||||||
|
private String oauthTokenSecret;
|
||||||
|
}
|
|
@ -3,9 +3,7 @@ package io.lbry.browser.model;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import io.lbry.browser.exceptions.LbryUriException;
|
|
||||||
import io.lbry.browser.utils.LbryUri;
|
import io.lbry.browser.utils.LbryUri;
|
||||||
import io.lbry.browser.utils.Lbryio;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|
|
@ -1,16 +1,33 @@
|
||||||
package io.lbry.browser.model;
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class WalletBalance {
|
public class WalletBalance {
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private BigDecimal available;
|
private BigDecimal available;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private BigDecimal reserved;
|
private BigDecimal reserved;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private BigDecimal claims;
|
private BigDecimal claims;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private BigDecimal supports;
|
private BigDecimal supports;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private BigDecimal tips;
|
private BigDecimal tips;
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
private BigDecimal total;
|
private BigDecimal total;
|
||||||
|
|
||||||
public WalletBalance() {
|
public WalletBalance() {
|
||||||
|
@ -21,4 +38,18 @@ public class WalletBalance {
|
||||||
tips = new BigDecimal(0);
|
tips = new BigDecimal(0);
|
||||||
total = new BigDecimal(0);
|
total = new BigDecimal(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static WalletBalance fromJSONObject(JSONObject json) {
|
||||||
|
WalletBalance balance = new WalletBalance();
|
||||||
|
JSONObject reservedSubtotals = Helper.getJSONObject("reserved_subtotals", json);
|
||||||
|
balance.setAvailable(new BigDecimal(Helper.getJSONString("available", "0", json)));
|
||||||
|
balance.setReserved(new BigDecimal(Helper.getJSONString("reserved", "0", json)));
|
||||||
|
balance.setTotal(new BigDecimal(Helper.getJSONString("total", "0", json)));
|
||||||
|
if (reservedSubtotals != null) {
|
||||||
|
balance.setClaims(new BigDecimal(Helper.getJSONString("claims", "0", reservedSubtotals)));
|
||||||
|
balance.setSupports(new BigDecimal(Helper.getJSONString("supports", "0", reservedSubtotals)));
|
||||||
|
balance.setTips(new BigDecimal(Helper.getJSONString("tips", "0", reservedSubtotals)));
|
||||||
|
}
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
|
public class WalletDetailItem {
|
||||||
|
public String detail;
|
||||||
|
public String detailDesc;
|
||||||
|
public String detailAmount;
|
||||||
|
public boolean isUnlockable;
|
||||||
|
public boolean isInProgress;
|
||||||
|
|
||||||
|
public WalletDetailItem(String detail, String detailDesc, String detailAmount, boolean isUnlockable, boolean isInProgress) {
|
||||||
|
this.detail = detail;
|
||||||
|
this.detailDesc = detailDesc;
|
||||||
|
this.detailAmount = detailAmount;
|
||||||
|
this.isUnlockable = isUnlockable;
|
||||||
|
this.isInProgress = isInProgress;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
package io.lbry.browser.model;
|
package io.lbry.browser.model;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class WalletSync {
|
public class WalletSync {
|
||||||
private String hash;
|
@Getter
|
||||||
private String data;
|
private final String hash;
|
||||||
|
@Getter
|
||||||
|
private final String data;
|
||||||
|
@Getter
|
||||||
private boolean changed;
|
private boolean changed;
|
||||||
|
|
||||||
public WalletSync(String hash, String data) {
|
public WalletSync(String hash, String data) {
|
||||||
|
@ -17,4 +21,5 @@ public class WalletSync {
|
||||||
this(hash, data);
|
this(hash, data);
|
||||||
this.changed = changed;
|
this.changed = changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package io.lbry.browser.model.lbryinc;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import io.lbry.browser.model.Claim;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
|
||||||
|
public class LbryNotification implements Comparator<LbryNotification> {
|
||||||
|
private long id;
|
||||||
|
@EqualsAndHashCode.Include
|
||||||
|
private long remoteId;
|
||||||
|
private String title;
|
||||||
|
private String description;
|
||||||
|
private String thumbnailUrl;
|
||||||
|
private String rule;
|
||||||
|
private String targetUrl;
|
||||||
|
private boolean read;
|
||||||
|
private boolean seen;
|
||||||
|
private Date timestamp;
|
||||||
|
|
||||||
|
// only for comment notifications
|
||||||
|
private String authorUrl;
|
||||||
|
private Claim commentAuthor;
|
||||||
|
|
||||||
|
public int compare(LbryNotification a, LbryNotification b) {
|
||||||
|
long t1 = a.getTimestamp() != null ? a.getTimestamp().getTime() : 0;
|
||||||
|
long t2 = b.getTimestamp() != null ? b.getTimestamp().getTime() : 0;
|
||||||
|
if (t1 < t2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (t1 > t2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import org.json.JSONObject;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
import io.lbry.browser.model.Claim;
|
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.lbry.browser.model.lbryinc;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RewardVerified {
|
||||||
|
private long userId;
|
||||||
|
private boolean isRewardApproved;
|
||||||
|
}
|
|
@ -11,17 +11,21 @@ public class Subscription {
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private String url;
|
private String url;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private boolean isNotificationsDisabled;
|
||||||
|
|
||||||
public Subscription() {
|
public Subscription() {
|
||||||
|
|
||||||
}
|
}
|
||||||
public Subscription(String channelName, String url) {
|
public Subscription(String channelName, String url, boolean isNotificationsDisabled) {
|
||||||
this.channelName = channelName;
|
this.channelName = channelName;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
this.isNotificationsDisabled = isNotificationsDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Subscription fromClaim(Claim claim) {
|
public static Subscription fromClaim(Claim claim) {
|
||||||
return new Subscription(claim.getName(), claim.getPermanentUrl());
|
return new Subscription(claim.getName(), claim.getPermanentUrl(), false);
|
||||||
}
|
}
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return url;
|
return url;
|
||||||
|
|
70
app/src/main/java/io/lbry/browser/tasks/BufferEventTask.java
Normal file
70
app/src/main/java/io/lbry/browser/tasks/BufferEventTask.java
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package io.lbry.browser.tasks;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
|
||||||
|
public class BufferEventTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
private static final String TAG = "LbryBufferEvent";
|
||||||
|
private static final String ENDPOINT = "https://collector-service.api.lbry.tv/api/v1/events/video";
|
||||||
|
|
||||||
|
private final String streamUrl;
|
||||||
|
private final String userIdHash;
|
||||||
|
private final long streamDuration;
|
||||||
|
private final long streamPosition;
|
||||||
|
private final long bufferDuration;
|
||||||
|
|
||||||
|
public BufferEventTask(String streamUrl, long streamDuration, long streamPosition, long bufferDuration, String userIdHash) {
|
||||||
|
this.streamUrl = streamUrl;
|
||||||
|
this.bufferDuration = bufferDuration;
|
||||||
|
this.streamDuration = streamDuration;
|
||||||
|
this.streamPosition = streamPosition;
|
||||||
|
this.userIdHash = userIdHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
JSONObject requestBody = new JSONObject();
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
try {
|
||||||
|
data.put("url", streamUrl);
|
||||||
|
data.put("position", streamPosition);
|
||||||
|
data.put("stream_duration", streamDuration);
|
||||||
|
//data.put("duration", bufferDuration);
|
||||||
|
|
||||||
|
requestBody.put("device", "android");
|
||||||
|
requestBody.put("type", "buffering");
|
||||||
|
requestBody.put("client", userIdHash);
|
||||||
|
requestBody.put("data", data);
|
||||||
|
|
||||||
|
RequestBody body = RequestBody.create(requestBody.toString(), Helper.JSON_MEDIA_TYPE);
|
||||||
|
Request request = new Request.Builder().url(ENDPOINT).post(body).build();
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder().
|
||||||
|
writeTimeout(60, TimeUnit.SECONDS).
|
||||||
|
readTimeout(60, TimeUnit.SECONDS).
|
||||||
|
build();
|
||||||
|
|
||||||
|
Response response = client.newCall(request).execute();
|
||||||
|
ResponseBody resBody = response.body();
|
||||||
|
String responseString = "";
|
||||||
|
if (resBody != null) {
|
||||||
|
responseString = response.body().string();
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format("buffer event sent: %s", responseString));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// we don't want to fail if a buffer event fails to register
|
||||||
|
Log.d(TAG, String.format("buffer event log failed: %s", ex.getMessage()), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package io.lbry.browser.tasks;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
|
import io.lbry.browser.model.Comment;
|
||||||
|
import io.lbry.browser.utils.Comments;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class CommentCreateTask extends AsyncTask<Void, Void, Comment> {
|
||||||
|
private final Comment comment;
|
||||||
|
private final View progressView;
|
||||||
|
private final CommentCreateWithTipHandler handler;
|
||||||
|
private Exception error;
|
||||||
|
|
||||||
|
public CommentCreateTask(Comment comment, View progressView, CommentCreateWithTipHandler handler) {
|
||||||
|
this.comment = comment;
|
||||||
|
this.progressView = progressView;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPreExecute() {
|
||||||
|
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Comment doInBackground(Void... params) {
|
||||||
|
Comment createdComment = null;
|
||||||
|
try {
|
||||||
|
// check comments status endpoint
|
||||||
|
Comments.checkCommentsEndpointStatus();
|
||||||
|
|
||||||
|
JSONObject comment_body = new JSONObject();
|
||||||
|
comment_body.put("comment", comment.getText());
|
||||||
|
comment_body.put("claim_id", comment.getClaimId());
|
||||||
|
if (!Helper.isNullOrEmpty(comment.getParentId())) {
|
||||||
|
comment_body.put("parent_id", comment.getParentId());
|
||||||
|
}
|
||||||
|
comment_body.put("channel_id", comment.getChannelId());
|
||||||
|
comment_body.put("channel_name", comment.getChannelName());
|
||||||
|
|
||||||
|
JSONObject jsonChannelSign = Comments.channelSign(comment_body, comment.getChannelId(), comment.getChannelName());
|
||||||
|
|
||||||
|
if (jsonChannelSign.has("signature") && jsonChannelSign.has("signing_ts")) {
|
||||||
|
comment_body.put("signature", jsonChannelSign.getString("signature"));
|
||||||
|
comment_body.put("signing_ts", jsonChannelSign.getString("signing_ts"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Response resp = Comments.performRequest(comment_body, "comment.Create");
|
||||||
|
String responseString = Objects.requireNonNull(resp.body()).string();
|
||||||
|
resp.close();
|
||||||
|
JSONObject jsonResponse = new JSONObject(responseString);
|
||||||
|
|
||||||
|
if (jsonResponse.has("result"))
|
||||||
|
createdComment = Comment.fromJSONObject(jsonResponse.getJSONObject("result"));
|
||||||
|
} catch (ApiCallException | ClassCastException | IOException | JSONException ex) {
|
||||||
|
error = ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createdComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(Comment createdComment) {
|
||||||
|
Helper.setViewVisibility(progressView, View.GONE);
|
||||||
|
if (handler != null) {
|
||||||
|
if (createdComment != null) {
|
||||||
|
handler.onSuccess(createdComment);
|
||||||
|
} else {
|
||||||
|
handler.onError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface CommentCreateWithTipHandler {
|
||||||
|
void onSuccess(Comment createdComment);
|
||||||
|
void onError(Exception error);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.lbry.browser.tasks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.lbry.browser.model.Comment;
|
||||||
|
|
||||||
|
public interface CommentListHandler {
|
||||||
|
void onSuccess(List<Comment> comments, boolean hasReachedEnd);
|
||||||
|
void onError(Exception error);
|
||||||
|
}
|
99
app/src/main/java/io/lbry/browser/tasks/CommentListTask.java
Normal file
99
app/src/main/java/io/lbry/browser/tasks/CommentListTask.java
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package io.lbry.browser.tasks;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.lbry.browser.model.Comment;
|
||||||
|
import io.lbry.browser.utils.Comments;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
|
public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
|
||||||
|
private final int page;
|
||||||
|
private final int pageSize;
|
||||||
|
private final String claim;
|
||||||
|
private final ProgressBar progressBar;
|
||||||
|
private final CommentListHandler handler;
|
||||||
|
private Exception error;
|
||||||
|
|
||||||
|
public CommentListTask(int page, int pageSize, String claim, ProgressBar progressBar, CommentListHandler handler) {
|
||||||
|
this.page = page;
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
this.claim = claim;
|
||||||
|
this.progressBar = progressBar;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPreExecute() {
|
||||||
|
Helper.setViewVisibility(progressBar, View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Comment> doInBackground(Void... voids) {
|
||||||
|
List<Comment> comments = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> options = new HashMap<>();
|
||||||
|
|
||||||
|
options.put("claim_id", claim);
|
||||||
|
options.put("page", page);
|
||||||
|
options.put("page_size", pageSize);
|
||||||
|
options.put("hidden", false);
|
||||||
|
options.put("include_replies", false);
|
||||||
|
options.put("is_channel_signature_valid", true);
|
||||||
|
options.put("skip_validation", true);
|
||||||
|
options.put("visible", true);
|
||||||
|
|
||||||
|
JSONObject result = (JSONObject) Lbry.parseResponse(Comments.performRequest(Lbry.buildJsonParams(options), "comment.List"));
|
||||||
|
JSONArray items = result.getJSONArray("items");
|
||||||
|
|
||||||
|
List<Comment> children = new ArrayList<>();
|
||||||
|
comments = new ArrayList<>();
|
||||||
|
for (int i = 0; i < items.length(); i++) {
|
||||||
|
Comment comment = Comment.fromJSONObject(items.getJSONObject(i));
|
||||||
|
if (comment != null) {
|
||||||
|
if (!Helper.isNullOrEmpty(comment.getParentId())) {
|
||||||
|
children.add(comment);
|
||||||
|
} else {
|
||||||
|
comments.add(comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort all replies from oldest to newest at once
|
||||||
|
Collections.sort(children);
|
||||||
|
|
||||||
|
for (Comment child : children) {
|
||||||
|
for (Comment parent : comments) {
|
||||||
|
if (parent.getId().equalsIgnoreCase(child.getParentId())) {
|
||||||
|
parent.addReply(child);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
error = ex;
|
||||||
|
}
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(List<Comment> comments) {
|
||||||
|
Helper.setViewVisibility(progressBar, View.GONE);
|
||||||
|
if (handler != null) {
|
||||||
|
if (comments != null) {
|
||||||
|
handler.onSuccess(comments, comments.size() < pageSize);
|
||||||
|
} else {
|
||||||
|
handler.onError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,10 @@ import io.lbry.browser.model.Tag;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class FollowUnfollowTagTask extends AsyncTask<Void, Void, Boolean> {
|
public class FollowUnfollowTagTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private Tag tag;
|
private final Tag tag;
|
||||||
private boolean unfollowing;
|
private final boolean unfollowing;
|
||||||
private Context context;
|
private final Context context;
|
||||||
private FollowUnfollowTagHandler handler;
|
private final FollowUnfollowTagHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public FollowUnfollowTagTask(Tag tag, boolean unfollowing, Context context, FollowUnfollowTagHandler handler) {
|
public FollowUnfollowTagTask(Tag tag, boolean unfollowing, Context context, FollowUnfollowTagHandler handler) {
|
||||||
|
|
|
@ -12,9 +12,9 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lighthouse;
|
import io.lbry.browser.utils.Lighthouse;
|
||||||
|
|
||||||
public class LighthouseAutoCompleteTask extends AsyncTask<Void, Void, List<UrlSuggestion>> {
|
public class LighthouseAutoCompleteTask extends AsyncTask<Void, Void, List<UrlSuggestion>> {
|
||||||
private String text;
|
private final String text;
|
||||||
private AutoCompleteResultHandler handler;
|
private final AutoCompleteResultHandler handler;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public LighthouseAutoCompleteTask(String text, View progressView, AutoCompleteResultHandler handler) {
|
public LighthouseAutoCompleteTask(String text, View progressView, AutoCompleteResultHandler handler) {
|
||||||
|
|
|
@ -14,13 +14,13 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lighthouse;
|
import io.lbry.browser.utils.Lighthouse;
|
||||||
|
|
||||||
public class LighthouseSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
public class LighthouseSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
private String rawQuery;
|
private final String rawQuery;
|
||||||
private int size;
|
private final int size;
|
||||||
private int from;
|
private final int from;
|
||||||
private boolean nsfw;
|
private final boolean nsfw;
|
||||||
private String relatedTo;
|
private final String relatedTo;
|
||||||
private ClaimSearchResultHandler handler;
|
private final ClaimSearchResultHandler handler;
|
||||||
private ProgressBar progressBar;
|
private final ProgressBar progressBar;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public LighthouseSearchTask(String rawQuery, int size, int from, boolean nsfw, String relatedTo, ProgressBar progressBar, ClaimSearchResultHandler handler) {
|
public LighthouseSearchTask(String rawQuery, int size, int from, boolean nsfw, String relatedTo, ProgressBar progressBar, ClaimSearchResultHandler handler) {
|
||||||
|
|
|
@ -4,22 +4,16 @@ import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
import io.lbry.browser.MainActivity;
|
||||||
import io.lbry.browser.data.DatabaseHelper;
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.exceptions.LbryRequestException;
|
|
||||||
import io.lbry.browser.exceptions.LbryResponseException;
|
|
||||||
import io.lbry.browser.model.Claim;
|
|
||||||
import io.lbry.browser.model.Tag;
|
import io.lbry.browser.model.Tag;
|
||||||
import io.lbry.browser.utils.Helper;
|
|
||||||
|
|
||||||
public class LoadTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
public class LoadTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
private LoadTagsHandler handler;
|
private final LoadTagsHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public LoadTagsTask(Context context, LoadTagsHandler handler) {
|
public LoadTagsTask(Context context, LoadTagsHandler handler) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
@ -17,26 +16,25 @@ import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
import io.lbry.browser.MainActivity;
|
||||||
import io.lbry.browser.data.DatabaseHelper;
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.exceptions.LbryUriException;
|
|
||||||
import io.lbry.browser.exceptions.LbryioRequestException;
|
import io.lbry.browser.exceptions.LbryioRequestException;
|
||||||
import io.lbry.browser.exceptions.LbryioResponseException;
|
import io.lbry.browser.exceptions.LbryioResponseException;
|
||||||
import io.lbry.browser.model.lbryinc.Subscription;
|
import io.lbry.browser.model.lbryinc.Subscription;
|
||||||
import io.lbry.browser.utils.Helper;
|
|
||||||
import io.lbry.browser.utils.LbryUri;
|
import io.lbry.browser.utils.LbryUri;
|
||||||
import io.lbry.browser.utils.Lbryio;
|
import io.lbry.browser.utils.Lbryio;
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
// background task to create a diff of local and remote subscriptions and try to merge
|
// background task to create a diff of local and remote subscriptions and try to merge
|
||||||
public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscription>> {
|
public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscription>> {
|
||||||
private static final String TAG = "MergeSubscriptionsTask";
|
private static final String TAG = "MergeSubscriptionsTask";
|
||||||
private Context context;
|
private final Context context;
|
||||||
private List<Subscription> base;
|
private final List<Subscription> base;
|
||||||
private List<Subscription> diff;
|
private List<Subscription> diff;
|
||||||
private MergeSubscriptionsHandler handler;
|
private final MergeSubscriptionsHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
private final boolean replaceLocal;
|
||||||
|
|
||||||
public MergeSubscriptionsTask(List<Subscription> base, Context context, MergeSubscriptionsHandler handler) {
|
public MergeSubscriptionsTask(List<Subscription> base, boolean replaceLocal, Context context, MergeSubscriptionsHandler handler) {
|
||||||
this.base = base;
|
this.base = base;
|
||||||
|
this.replaceLocal = replaceLocal;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
|
@ -53,10 +51,17 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
|
||||||
db = ((MainActivity) context).getDbHelper().getWritableDatabase();
|
db = ((MainActivity) context).getDbHelper().getWritableDatabase();
|
||||||
}
|
}
|
||||||
if (db != null) {
|
if (db != null) {
|
||||||
localSubs = DatabaseHelper.getSubscriptions(db);
|
if (replaceLocal) {
|
||||||
for (Subscription sub : localSubs) {
|
DatabaseHelper.clearSubscriptions(db);
|
||||||
if (!combined.contains(sub)) {
|
for (Subscription sub : base) {
|
||||||
combined.add(sub);
|
DatabaseHelper.createOrUpdateSubscription(sub, db);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
localSubs = DatabaseHelper.getSubscriptions(db);
|
||||||
|
for (Subscription sub : localSubs) {
|
||||||
|
if (!combined.contains(sub)) {
|
||||||
|
combined.add(sub);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,48 +69,55 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
|
||||||
// fetch remote subscriptions
|
// fetch remote subscriptions
|
||||||
JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("subscription", "list", context));
|
JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("subscription", "list", context));
|
||||||
if (array != null) {
|
if (array != null) {
|
||||||
|
// check for any remote subs that may have been removed, and unsubscribe from them
|
||||||
for (int i = 0; i < array.length(); i++) {
|
for (int i = 0; i < array.length(); i++) {
|
||||||
JSONObject item = array.getJSONObject(i);
|
JSONObject item = array.getJSONObject(i);
|
||||||
|
// TODO: Refactor by creating static Subscription.fromJSON method
|
||||||
String claimId = item.getString("claim_id");
|
String claimId = item.getString("claim_id");
|
||||||
String channelName = item.getString("channel_name");
|
String channelName = item.getString("channel_name");
|
||||||
|
boolean isNotificationsDisabled = item.getBoolean("is_notifications_disabled");
|
||||||
|
|
||||||
LbryUri url = new LbryUri();
|
LbryUri url = new LbryUri();
|
||||||
url.setChannelName(channelName);
|
url.setChannelName(channelName);
|
||||||
url.setClaimId(claimId);
|
url.setClaimId(claimId);
|
||||||
Subscription subscription = new Subscription(channelName, url.toString());
|
Subscription subscription = new Subscription(channelName, url.toString(), isNotificationsDisabled);
|
||||||
remoteSubs.add(subscription);
|
remoteSubs.add(subscription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < combined.size(); i++) {
|
List<Subscription> remoteUnsubs = new ArrayList<>();
|
||||||
Subscription local = combined.get(i);
|
List<Subscription> finalRemoteSubs = new ArrayList<>();
|
||||||
if (!remoteSubs.contains(local)) {
|
if (remoteSubs.size() > 0) {
|
||||||
// add to remote subscriptions
|
for (int i = 0; i < remoteSubs.size(); i++) {
|
||||||
try {
|
Subscription sub = remoteSubs.get(i);
|
||||||
LbryUri uri = LbryUri.parse(local.getUrl());
|
if (!combined.contains(sub)) {
|
||||||
Map<String, String> options = new HashMap<>();
|
Map<String, String> options = new HashMap<>();
|
||||||
options.put("claim_id", uri.getChannelClaimId());
|
LbryUri uri = LbryUri.tryParse(sub.getUrl());
|
||||||
options.put("channel_name", Helper.normalizeChannelName(local.getChannelName()));
|
if (uri != null) {
|
||||||
Lbryio.parseResponse(Lbryio.call("subscription", "new", options, context));
|
options.put("claim_id", uri.getChannelClaimId());
|
||||||
} catch (LbryUriException | LbryioRequestException | LbryioResponseException ex) {
|
Lbryio.parseResponse(Lbryio.call("subscription", "delete", options, context));
|
||||||
// pass
|
remoteUnsubs.add(sub);
|
||||||
Log.e(TAG, String.format("subscription/new failed: %s", ex.getMessage()), ex);
|
} else {
|
||||||
|
finalRemoteSubs.add(sub);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < localSubs.size(); i++) {
|
if (!replaceLocal) {
|
||||||
Subscription local = localSubs.get(i);
|
for (int i = 0; i < localSubs.size(); i++) {
|
||||||
if (!base.contains(local) && !diff.contains(local)) {
|
Subscription local = localSubs.get(i);
|
||||||
diff.add(local);
|
if (!base.contains(local) && !diff.contains(local)) {
|
||||||
|
diff.add(local);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
for (int i = 0; i < finalRemoteSubs.size(); i++) {
|
||||||
for (int i = 0; i < remoteSubs.size(); i++) {
|
Subscription remote = finalRemoteSubs.get(i);
|
||||||
Subscription remote = remoteSubs.get(i);
|
if (!combined.contains(remote)) {
|
||||||
if (!combined.contains(remote)) {
|
combined.add(remote);
|
||||||
combined.add(remote);
|
if (!diff.contains(remote)) {
|
||||||
if (!diff.contains(remote)) {
|
diff.add(remote);
|
||||||
diff.add(remote);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,15 @@ import android.os.AsyncTask;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.Buffer;
|
|
||||||
|
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
|
|
||||||
public class ReadTextFileTask extends AsyncTask<Void, Void, String> {
|
public class ReadTextFileTask extends AsyncTask<Void, Void, String> {
|
||||||
private String filePath;
|
private final String filePath;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
private ReadTextFileHandler handler;
|
private final ReadTextFileHandler handler;
|
||||||
public ReadTextFileTask(String filePath, ReadTextFileHandler handler) {
|
public ReadTextFileTask(String filePath, ReadTextFileHandler handler) {
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package io.lbry.browser.tasks;
|
||||||
|
|
||||||
|
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||||
|
|
||||||
|
public interface RewardVerifiedHandler {
|
||||||
|
void onSuccess(RewardVerified rewardVerified);
|
||||||
|
void onError(Exception error);
|
||||||
|
}
|
|
@ -9,9 +9,9 @@ import io.lbry.browser.exceptions.ApiCallException;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class SetSdkSettingTask extends AsyncTask<Void, Void, Boolean> {
|
public class SetSdkSettingTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private String key;
|
private final String key;
|
||||||
private String value;
|
private final String value;
|
||||||
private GenericTaskHandler handler;
|
private final GenericTaskHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
public SetSdkSettingTask(String key, String value, GenericTaskHandler handler) {
|
public SetSdkSettingTask(String key, String value, GenericTaskHandler handler) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package io.lbry.browser.tasks;
|
||||||
|
|
||||||
|
import io.lbry.browser.model.TwitterOauth;
|
||||||
|
|
||||||
|
public interface TwitterOauthHandler {
|
||||||
|
void onSuccess(TwitterOauth twitterOauth);
|
||||||
|
void onError(Exception error);
|
||||||
|
}
|
|
@ -13,13 +13,13 @@ import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
||||||
|
|
||||||
private boolean clearPrevious;
|
private final boolean clearPrevious;
|
||||||
private boolean excludeMature;
|
private final boolean excludeMature;
|
||||||
private int limit;
|
private final int limit;
|
||||||
private String filter;
|
private final String filter;
|
||||||
private TagListAdapter addedTagsAdapter;
|
private final TagListAdapter addedTagsAdapter;
|
||||||
private TagListAdapter suggestedTagsAdapter;
|
private final TagListAdapter suggestedTagsAdapter;
|
||||||
private KnownTagsHandler handler;
|
private final KnownTagsHandler handler;
|
||||||
|
|
||||||
public UpdateSuggestedTagsTask(
|
public UpdateSuggestedTagsTask(
|
||||||
String filter,
|
String filter,
|
||||||
|
@ -45,13 +45,15 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
||||||
if (suggestedTagsAdapter != null && !clearPrevious) {
|
if (suggestedTagsAdapter != null && !clearPrevious) {
|
||||||
tags = new ArrayList<>(suggestedTagsAdapter.getTags());
|
tags = new ArrayList<>(suggestedTagsAdapter.getTags());
|
||||||
}
|
}
|
||||||
while (tags.size() < limit) {
|
if (Lbry.knownTags.size() > 0) {
|
||||||
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
|
while (tags.size() < limit) {
|
||||||
if (excludeMature && randomTag.isMature()) {
|
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
|
||||||
continue;
|
if (excludeMature && randomTag.isMature()) {
|
||||||
}
|
continue;
|
||||||
if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) {
|
}
|
||||||
tags.add(randomTag);
|
if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) {
|
||||||
|
tags.add(randomTag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,10 +66,15 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
||||||
if (excludeMature && knownTag.isMature()) {
|
if (excludeMature && knownTag.isMature()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((knownTag.getLowercaseName().startsWith(filter) || knownTag.getLowercaseName().matches(filter)) &&
|
try {
|
||||||
(!tags.contains(knownTag) &&
|
if ((knownTag.getLowercaseName().startsWith(filter) ||
|
||||||
!Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag)))) {
|
knownTag.getLowercaseName().matches(filter)) &&
|
||||||
tags.add(knownTag);
|
(!tags.contains(knownTag) && !Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag)))
|
||||||
|
) {
|
||||||
|
tags.add(knownTag);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class UploadImageTask extends AsyncTask<Void, Void, String> {
|
public class UploadImageTask extends AsyncTask<Void, Void, String> {
|
||||||
private String filePath;
|
private final String filePath;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private UploadThumbnailHandler handler;
|
private final UploadThumbnailHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public UploadImageTask(String filePath, View progressView, UploadThumbnailHandler handler) {
|
public UploadImageTask(String filePath, View progressView, UploadThumbnailHandler handler) {
|
||||||
|
|
|
@ -11,17 +11,16 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.exceptions.ApiCallException;
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class AbandonChannelTask extends AsyncTask<Void, Void, Boolean> {
|
public class AbandonChannelTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private List<String> claimIds;
|
private final List<String> claimIds;
|
||||||
private List<String> successfulClaimIds;
|
private List<String> successfulClaimIds;
|
||||||
private List<String> failedClaimIds;
|
private List<String> failedClaimIds;
|
||||||
private List<Exception> failedExceptions;
|
private List<Exception> failedExceptions;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private AbandonHandler handler;
|
private final AbandonHandler handler;
|
||||||
|
|
||||||
public AbandonChannelTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
public AbandonChannelTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
||||||
this.claimIds = claimIds;
|
this.claimIds = claimIds;
|
||||||
|
|
|
@ -11,17 +11,16 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.exceptions.ApiCallException;
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class AbandonStreamTask extends AsyncTask<Void, Void, Boolean> {
|
public class AbandonStreamTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private List<String> claimIds;
|
private final List<String> claimIds;
|
||||||
private List<String> successfulClaimIds;
|
private List<String> successfulClaimIds;
|
||||||
private List<String> failedClaimIds;
|
private List<String> failedClaimIds;
|
||||||
private List<Exception> failedExceptions;
|
private List<Exception> failedExceptions;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private AbandonHandler handler;
|
private final AbandonHandler handler;
|
||||||
|
|
||||||
public AbandonStreamTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
public AbandonStreamTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
||||||
this.claimIds = claimIds;
|
this.claimIds = claimIds;
|
||||||
|
|
|
@ -21,12 +21,12 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Claim> {
|
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Claim> {
|
||||||
private Claim claim;
|
private final Claim claim;
|
||||||
private BigDecimal deposit;
|
private final BigDecimal deposit;
|
||||||
private boolean update;
|
private final boolean update;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
private ClaimResultHandler handler;
|
private final ClaimResultHandler handler;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
|
|
||||||
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, ClaimResultHandler handler) {
|
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, ClaimResultHandler handler) {
|
||||||
this.claim = claim;
|
this.claim = claim;
|
||||||
|
|
|
@ -19,9 +19,9 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
|
public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
private List<String> types;
|
private final List<String> types;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private ClaimListResultHandler handler;
|
private final ClaimListResultHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public ClaimListTask(String type, View progressView, ClaimListResultHandler handler) {
|
public ClaimListTask(String type, View progressView, ClaimListResultHandler handler) {
|
||||||
|
@ -62,7 +62,8 @@ public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
Helper.setViewVisibility(progressView, View.GONE);
|
Helper.setViewVisibility(progressView, View.GONE);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if (claims != null) {
|
if (claims != null) {
|
||||||
handler.onSuccess(claims);
|
// TODO: Add fix for handling invalid reposts in ClaimListAdapter
|
||||||
|
handler.onSuccess(Helper.filterInvalidReposts(claims));
|
||||||
} else {
|
} else {
|
||||||
handler.onError(error);
|
handler.onError(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
private Map<String, Object> options;
|
private final Map<String, Object> options;
|
||||||
private String connectionString;
|
private final String connectionString;
|
||||||
private ClaimSearchResultHandler handler;
|
private final ClaimSearchResultHandler handler;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private ApiCallException error;
|
private ApiCallException error;
|
||||||
|
|
||||||
public ClaimSearchTask(Map<String, Object> options, String connectionString, View progressView, ClaimSearchResultHandler handler) {
|
public ClaimSearchTask(Map<String, Object> options, String connectionString, View progressView, ClaimSearchResultHandler handler) {
|
||||||
|
@ -29,7 +29,7 @@ public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
}
|
}
|
||||||
protected List<Claim> doInBackground(Void... params) {
|
protected List<Claim> doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
return Helper.filterInvalidReposts(Lbry.claimSearch(options, connectionString));
|
return Lbry.claimSearch(options, connectionString);
|
||||||
} catch (ApiCallException ex) {
|
} catch (ApiCallException ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
return null;
|
return null;
|
||||||
|
@ -39,7 +39,7 @@ public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
Helper.setViewVisibility(progressView, View.GONE);
|
Helper.setViewVisibility(progressView, View.GONE);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if (claims != null) {
|
if (claims != null) {
|
||||||
handler.onSuccess(claims, claims.size() < Helper.parseInt(options.get("page_size"), 0));
|
handler.onSuccess(Helper.filterInvalidReposts(claims), claims.size() < Helper.parseInt(options.get("page_size"), 0));
|
||||||
} else {
|
} else {
|
||||||
handler.onError(error);
|
handler.onError(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,10 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
|
public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
|
||||||
private Claim claim;
|
private final Claim claim;
|
||||||
private String filePath;
|
private final String filePath;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private ClaimResultHandler handler;
|
private final ClaimResultHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
public PublishClaimTask(Claim claim, String filePath, View progressView, ClaimResultHandler handler) {
|
public PublishClaimTask(Claim claim, String filePath, View progressView, ClaimResultHandler handler) {
|
||||||
this.claim = claim;
|
this.claim = claim;
|
||||||
|
@ -73,6 +73,14 @@ public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
|
||||||
options.put("license_url", metadata.getLicenseUrl());
|
options.put("license_url", metadata.getLicenseUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (metadata.getReleaseTime() > 0) {
|
||||||
|
options.put("release_time", metadata.getReleaseTime());
|
||||||
|
} else if (claim.getTimestamp() > 0) {
|
||||||
|
options.put("release_time", claim.getTimestamp());
|
||||||
|
} else {
|
||||||
|
options.put("release_time", Double.valueOf(Math.floor(System.currentTimeMillis() / 1000.0)).intValue());
|
||||||
|
}
|
||||||
|
|
||||||
Claim claimResult = null;
|
Claim claimResult = null;
|
||||||
try {
|
try {
|
||||||
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PUBLISH, options);
|
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PUBLISH, options);
|
||||||
|
|
|
@ -18,12 +18,19 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
|
public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
|
private String claimId;
|
||||||
private int page;
|
private int page;
|
||||||
private int pageSize;
|
private int pageSize;
|
||||||
private ClaimSearchResultHandler handler;
|
private final ClaimSearchResultHandler handler;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
|
public PurchaseListTask(String claimId, View progressView, ClaimSearchResultHandler handler) {
|
||||||
|
this.claimId = claimId;
|
||||||
|
this.progressView = progressView;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
public PurchaseListTask(int page, int pageSize, View progressView, ClaimSearchResultHandler handler) {
|
public PurchaseListTask(int page, int pageSize, View progressView, ClaimSearchResultHandler handler) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
this.pageSize = pageSize;
|
this.pageSize = pageSize;
|
||||||
|
@ -38,8 +45,15 @@ public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
List<Claim> claims = null;
|
List<Claim> claims = null;
|
||||||
try {
|
try {
|
||||||
Map<String, Object> options = new HashMap<>();
|
Map<String, Object> options = new HashMap<>();
|
||||||
options.put("page", page);
|
if (!Helper.isNullOrEmpty(claimId)) {
|
||||||
options.put("page_size", pageSize);
|
options.put("claim_id", claimId);
|
||||||
|
}
|
||||||
|
if (page > 0) {
|
||||||
|
options.put("page", page);
|
||||||
|
}
|
||||||
|
if (pageSize > 0) {
|
||||||
|
options.put("page_size", pageSize);
|
||||||
|
}
|
||||||
options.put("resolve", true);
|
options.put("resolve", true);
|
||||||
|
|
||||||
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PURCHASE_LIST, options);
|
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PURCHASE_LIST, options);
|
||||||
|
@ -47,9 +61,10 @@ public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
claims = new ArrayList<>();
|
claims = new ArrayList<>();
|
||||||
for (int i = 0; i < items.length(); i++) {
|
for (int i = 0; i < items.length(); i++) {
|
||||||
Claim claim = Claim.fromJSONObject(items.getJSONObject(i).getJSONObject("claim"));
|
Claim claim = Claim.fromJSONObject(items.getJSONObject(i).getJSONObject("claim"));
|
||||||
claims.add(claim);
|
if (!Helper.isNullOrEmpty(claim.getClaimId())) {
|
||||||
|
claims.add(claim);
|
||||||
Lbry.addClaimToCache(claim);
|
Lbry.addClaimToCache(claim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (ApiCallException | JSONException | ClassCastException ex) {
|
} catch (ApiCallException | JSONException | ClassCastException ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
|
|
|
@ -13,10 +13,10 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
|
public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
private List<String> urls;
|
private final List<String> urls;
|
||||||
private String connectionString;
|
private final String connectionString;
|
||||||
private ClaimListResultHandler handler;
|
private final ClaimListResultHandler handler;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private ApiCallException error;
|
private ApiCallException error;
|
||||||
|
|
||||||
public ResolveTask(String url, String connectionString, View progressView, ClaimListResultHandler handler) {
|
public ResolveTask(String url, String connectionString, View progressView, ClaimListResultHandler handler) {
|
||||||
|
|
|
@ -20,12 +20,12 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class StreamRepostTask extends AsyncTask<Void, Void, Claim> {
|
public class StreamRepostTask extends AsyncTask<Void, Void, Claim> {
|
||||||
private String name;
|
private final String name;
|
||||||
private BigDecimal bid;
|
private final BigDecimal bid;
|
||||||
private String claimId;
|
private final String claimId;
|
||||||
private String channelId;
|
private final String channelId;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private ClaimResultHandler handler;
|
private final ClaimResultHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public StreamRepostTask(String name, BigDecimal bid, String claimId, String channelId, View progressView, ClaimResultHandler handler) {
|
public StreamRepostTask(String name, BigDecimal bid, String claimId, String channelId, View progressView, ClaimResultHandler handler) {
|
||||||
|
|
|
@ -7,12 +7,11 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.exceptions.ApiCallException;
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
// Just run delete on the specified claim IDs (no need for a handler)
|
// Just run delete on the specified claim IDs (no need for a handler)
|
||||||
public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> {
|
public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private List<String> claimIds;
|
private final List<String> claimIds;
|
||||||
public BulkDeleteFilesTask(List<String> claimIds) {
|
public BulkDeleteFilesTask(List<String> claimIds) {
|
||||||
this.claimIds = claimIds;
|
this.claimIds = claimIds;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ import io.lbry.browser.tasks.GenericTaskHandler;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class DeleteFileTask extends AsyncTask<Void, Void, Boolean> {
|
public class DeleteFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private String claimId;
|
private final String claimId;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
private GenericTaskHandler handler;
|
private final GenericTaskHandler handler;
|
||||||
|
|
||||||
public DeleteFileTask(String claimId, GenericTaskHandler handler) {
|
public DeleteFileTask(String claimId, GenericTaskHandler handler) {
|
||||||
this.claimId = claimId;
|
this.claimId = claimId;
|
||||||
|
|
|
@ -11,12 +11,12 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
||||||
private String claimId;
|
private final String claimId;
|
||||||
private boolean downloads;
|
private boolean downloads;
|
||||||
private int page;
|
private int page;
|
||||||
private int pageSize;
|
private int pageSize;
|
||||||
private FileListResultHandler handler;
|
private final FileListResultHandler handler;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private ApiCallException error;
|
private ApiCallException error;
|
||||||
|
|
||||||
public FileListTask(int page, int pageSize, boolean downloads, View progressView, FileListResultHandler handler) {
|
public FileListTask(int page, int pageSize, boolean downloads, View progressView, FileListResultHandler handler) {
|
||||||
|
|
|
@ -14,10 +14,10 @@ import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
public class GetFileTask extends AsyncTask<Void, Void, LbryFile> {
|
public class GetFileTask extends AsyncTask<Void, Void, LbryFile> {
|
||||||
private String uri;
|
private final String uri;
|
||||||
private boolean saveFile;
|
private final boolean saveFile;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private GetFileHandler handler;
|
private final GetFileHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public GetFileTask(String uri, boolean saveFile, View progressView, GetFileHandler handler) {
|
public GetFileTask(String uri, boolean saveFile, View progressView, GetFileHandler handler) {
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package io.lbry.browser.tasks.lbryinc;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.google.gson.FieldNamingPolicy;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||||
|
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import io.lbry.browser.utils.Lbryio;
|
||||||
|
|
||||||
|
public class AndroidPurchaseTask extends AsyncTask<Void, Void, RewardVerified> {
|
||||||
|
private final Context context;
|
||||||
|
private final View progressView;
|
||||||
|
private final String purchaseToken;
|
||||||
|
private final RewardVerifiedHandler handler;
|
||||||
|
private Exception error;
|
||||||
|
|
||||||
|
public AndroidPurchaseTask(String purchaseToken, View progressView, Context context, RewardVerifiedHandler handler) {
|
||||||
|
this.purchaseToken = purchaseToken;
|
||||||
|
this.progressView = progressView;
|
||||||
|
this.context = context;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPreExecute() {
|
||||||
|
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RewardVerified doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
Map<String, String> options = new HashMap<>();
|
||||||
|
options.put("purchase_token", purchaseToken);
|
||||||
|
|
||||||
|
JSONObject object = (JSONObject) Lbryio.parseResponse(Lbryio.call("verification", "android_purchase", options, context));
|
||||||
|
Type type = new TypeToken<RewardVerified>(){}.getType();
|
||||||
|
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||||
|
return gson.fromJson(object.toString(), type);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
error = ex;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(RewardVerified result) {
|
||||||
|
Helper.setViewVisibility(progressView, View.GONE);
|
||||||
|
if (handler != null) {
|
||||||
|
if (result != null) {
|
||||||
|
handler.onSuccess(result);
|
||||||
|
} else {
|
||||||
|
handler.onError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,16 +13,15 @@ import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.exceptions.LbryioRequestException;
|
import io.lbry.browser.exceptions.LbryioRequestException;
|
||||||
import io.lbry.browser.exceptions.LbryioResponseException;
|
import io.lbry.browser.exceptions.LbryioResponseException;
|
||||||
import io.lbry.browser.model.lbryinc.Subscription;
|
import io.lbry.browser.model.lbryinc.Subscription;
|
||||||
import io.lbry.browser.utils.Helper;
|
|
||||||
import io.lbry.browser.utils.Lbryio;
|
import io.lbry.browser.utils.Lbryio;
|
||||||
|
|
||||||
public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
|
public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private Context context;
|
private final Context context;
|
||||||
private String channelClaimId;
|
private final String channelClaimId;
|
||||||
private Subscription subscription;
|
private final Subscription subscription;
|
||||||
private ChannelSubscribeHandler handler;
|
private final ChannelSubscribeHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
private boolean isUnsubscribing;
|
private final boolean isUnsubscribing;
|
||||||
|
|
||||||
public ChannelSubscribeTask(Context context, String channelClaimId, Subscription subscription, boolean isUnsubscribing, ChannelSubscribeHandler handler) {
|
public ChannelSubscribeTask(Context context, String channelClaimId, Subscription subscription, boolean isUnsubscribing, ChannelSubscribeHandler handler) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -51,11 +50,11 @@ public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
options.put("claim_id", channelClaimId);
|
options.put("claim_id", channelClaimId);
|
||||||
if (!isUnsubscribing) {
|
if (!isUnsubscribing) {
|
||||||
options.put("channel_name", subscription.getChannelName());
|
options.put("channel_name", subscription.getChannelName());
|
||||||
|
options.put("notifications_disabled", String.valueOf(subscription.isNotificationsDisabled()).toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
String action = isUnsubscribing ? "delete" : "new";
|
String action = isUnsubscribing ? "delete" : "new";
|
||||||
Lbryio.call("subscription", action, options, context);
|
Object response = Lbryio.parseResponse(Lbryio.call("subscription", action, options, context));
|
||||||
|
|
||||||
if (!isUnsubscribing) {
|
if (!isUnsubscribing) {
|
||||||
Lbryio.addSubscription(subscription);
|
Lbryio.addSubscription(subscription);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,6 +4,8 @@ import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
@ -14,23 +16,25 @@ import io.lbry.browser.R;
|
||||||
import io.lbry.browser.exceptions.ApiCallException;
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
import io.lbry.browser.exceptions.LbryioRequestException;
|
import io.lbry.browser.exceptions.LbryioRequestException;
|
||||||
import io.lbry.browser.exceptions.LbryioResponseException;
|
import io.lbry.browser.exceptions.LbryioResponseException;
|
||||||
|
import io.lbry.browser.model.Claim;
|
||||||
|
import io.lbry.browser.model.lbryinc.Reward;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
import io.lbry.browser.utils.Lbryio;
|
import io.lbry.browser.utils.Lbryio;
|
||||||
|
|
||||||
public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
private String type;
|
private final String type;
|
||||||
private String claimCode;
|
private final String rewardCode;
|
||||||
private View progressView;
|
private final View progressView;
|
||||||
private double amountClaimed;
|
private double amountClaimed;
|
||||||
private ClaimRewardHandler handler;
|
private final ClaimRewardHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public ClaimRewardTask(String type, String claimCode, View progressView, Context context, ClaimRewardHandler handler) {
|
public ClaimRewardTask(String type, String rewardCode, View progressView, Context context, ClaimRewardHandler handler) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.claimCode = claimCode;
|
this.rewardCode = rewardCode;
|
||||||
this.progressView = progressView;
|
this.progressView = progressView;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
@ -43,15 +47,27 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
||||||
public String doInBackground(Void... params) {
|
public String doInBackground(Void... params) {
|
||||||
String message = null;
|
String message = null;
|
||||||
try {
|
try {
|
||||||
|
String txid = null;
|
||||||
|
if (Reward.TYPE_FIRST_CHANNEL.equalsIgnoreCase(type)) {
|
||||||
|
// fetch a channel
|
||||||
|
txid = fetchSingleClaimTxid(Claim.TYPE_CHANNEL);
|
||||||
|
} else if (Reward.TYPE_FIRST_PUBLISH.equalsIgnoreCase(type)) {
|
||||||
|
// fetch a publish
|
||||||
|
txid = fetchSingleClaimTxid(Claim.TYPE_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
// Get a new wallet address for the reward
|
// Get a new wallet address for the reward
|
||||||
String address = (String) Lbry.genericApiCall(Lbry.METHOD_ADDRESS_UNUSED);
|
String address = (String) Lbry.genericApiCall(Lbry.METHOD_ADDRESS_UNUSED);
|
||||||
Map<String, String> options = new HashMap<>();
|
Map<String, String> options = new HashMap<>();
|
||||||
options.put("reward_type", type);
|
options.put("reward_type", type);
|
||||||
options.put("wallet_address", address);
|
options.put("wallet_address", address);
|
||||||
if (!Helper.isNullOrEmpty(claimCode)) {
|
if (!Helper.isNullOrEmpty(rewardCode)) {
|
||||||
options.put("claim_code", claimCode);
|
options.put("code", rewardCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (!Helper.isNullOrEmpty(txid)) {
|
||||||
|
options.put("transaction_id", txid);
|
||||||
|
}
|
||||||
|
|
||||||
JSONObject reward = (JSONObject) Lbryio.parseResponse(
|
JSONObject reward = (JSONObject) Lbryio.parseResponse(
|
||||||
Lbryio.call("reward", "claim", options, Helper.METHOD_POST, null));
|
Lbryio.call("reward", "claim", options, Helper.METHOD_POST, null));
|
||||||
amountClaimed = Helper.getJSONDouble("reward_amount", 0, reward);
|
amountClaimed = Helper.getJSONDouble("reward_amount", 0, reward);
|
||||||
|
@ -61,7 +77,7 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
||||||
amountClaimed == 1 ? 1 : 2,
|
amountClaimed == 1 ? 1 : 2,
|
||||||
new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed)) : "";
|
new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed)) : "";
|
||||||
message = Helper.getJSONString("reward_notification", defaultMessage, reward);
|
message = Helper.getJSONString("reward_notification", defaultMessage, reward);
|
||||||
} catch (ApiCallException | LbryioRequestException | LbryioResponseException ex) {
|
} catch (ApiCallException | JSONException | LbryioRequestException | LbryioResponseException ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +95,23 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String fetchSingleClaimTxid(String claimType) throws ApiCallException, JSONException {
|
||||||
|
Map<String, Object> options = new HashMap<>();
|
||||||
|
options.put("claim_type", claimType);
|
||||||
|
options.put("page", 1);
|
||||||
|
options.put("page_size", 1);
|
||||||
|
options.put("resolve", true);
|
||||||
|
|
||||||
|
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_CLAIM_LIST, options);
|
||||||
|
JSONArray items = result.getJSONArray("items");
|
||||||
|
if (items.length() > 0) {
|
||||||
|
Claim claim = Claim.fromJSONObject(items.getJSONObject(0));
|
||||||
|
return claim.getTxid();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public interface ClaimRewardHandler {
|
public interface ClaimRewardHandler {
|
||||||
void onSuccess(double amountClaimed, String message);
|
void onSuccess(double amountClaimed, String message);
|
||||||
void onError(Exception error);
|
void onError(Exception error);
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
package io.lbry.browser.tasks.lbryinc;
|
package io.lbry.browser.tasks.lbryinc;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import io.lbry.browser.model.lbryinc.User;
|
import io.lbry.browser.model.lbryinc.User;
|
||||||
import io.lbry.browser.utils.Lbryio;
|
import io.lbry.browser.utils.Lbryio;
|
||||||
|
|
||||||
public class FetchCurrentUserTask extends AsyncTask<Void, Void, User> {
|
public class FetchCurrentUserTask extends AsyncTask<Void, Void, User> {
|
||||||
|
private final Context context;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
private FetchUserTaskHandler handler;
|
private final FetchUserTaskHandler handler;
|
||||||
|
|
||||||
public FetchCurrentUserTask(FetchUserTaskHandler handler) {
|
public FetchCurrentUserTask(Context context, FetchUserTaskHandler handler) {
|
||||||
|
this.context = context;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
protected User doInBackground(Void... params) {
|
protected User doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
return Lbryio.fetchCurrentUser(null);
|
return Lbryio.fetchCurrentUser(context);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
return null;
|
return null;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue