Compare commits
321 commits
dark-theme
...
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 |
306 changed files with 26520 additions and 3477 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
|
||||
app/google-services.json
|
||||
app/twitter.properties
|
||||
*.log
|
||||
.vagrant
|
||||
*.hprof
|
||||
app/build
|
||||
bin
|
||||
app/debuglib
|
||||
|
|
|
@ -8,10 +8,13 @@ build apk:
|
|||
stage: build
|
||||
image: lbry/android-base:platform-28
|
||||
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
|
||||
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
|
||||
- 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)
|
||||
artifacts:
|
||||
paths:
|
||||
- bin/browser-*-release__arm.apk
|
||||
|
@ -19,12 +22,7 @@ build apk:
|
|||
expire_in: 1 week
|
||||
script:
|
||||
- export PATH=/usr/bin:$PATH
|
||||
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
|
||||
- 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
|
||||
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
|
||||
- chmod u+x ./release.sh
|
||||
- ./release.sh
|
||||
- cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null
|
||||
|
@ -36,10 +34,15 @@ deploy build.lbry.io:
|
|||
dependencies:
|
||||
- build apk
|
||||
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
|
||||
- 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__64=browser-$BUILD_VERSION-release__arm64.apk
|
||||
script:
|
||||
|
@ -55,10 +58,15 @@ release apk:
|
|||
dependencies:
|
||||
- build apk
|
||||
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
|
||||
- git secret reveal
|
||||
- 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__64=browser-$BUILD_VERSION-release__arm64.apk
|
||||
script:
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,2 +1,3 @@
|
|||
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
|
||||
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)
|
||||
[![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" />
|
||||
|
@ -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.
|
||||
|
||||
## 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
|
||||
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).
|
||||
|
||||
## 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
|
||||
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'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.1"
|
||||
buildToolsVersion "29.0.2"
|
||||
flavorDimensions "default"
|
||||
|
||||
compileOptions {
|
||||
|
@ -14,12 +16,16 @@ android {
|
|||
applicationId "io.lbry.browser"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 1503
|
||||
versionName "0.15.3"
|
||||
|
||||
versionCode 1701
|
||||
versionName "0.17.1"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
exclude 'lib/x86_64/darwin/libscrypt.dylib'
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
__32bit {
|
||||
versionCode android.defaultConfig.versionCode * 10 + 1
|
||||
|
@ -36,7 +42,17 @@ android {
|
|||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
@ -49,36 +65,49 @@ task printVersionName {
|
|||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
all {
|
||||
exclude module: 'httpclient'
|
||||
exclude module: 'commons-logging'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
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 '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.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.navigation:navigation-fragment:2.2.2'
|
||||
implementation 'androidx.navigation:navigation-ui:2.2.2'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation 'androidx.navigation:navigation-fragment:2.3.1'
|
||||
implementation 'androidx.navigation:navigation-ui:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'androidx.webkit:webkit:1.3.0-alpha02'
|
||||
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-lifecycle:1.0.0-beta03'
|
||||
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.squareup.okhttp3:okhttp:4.4.1'
|
||||
implementation 'com.google.firebase:firebase-analytics:17.4.0'
|
||||
implementation 'com.google.android.gms:play-services-base:17.2.1'
|
||||
implementation 'com.google.firebase:firebase-messaging:20.1.6'
|
||||
implementation 'com.google.firebase:firebase-analytics:18.0.0'
|
||||
implementation 'com.google.android.gms:play-services-base:17.5.0'
|
||||
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.android.exoplayer:exoplayer-core:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-dash:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:extension-cast:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:extension-mediasession:2.11.4'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.2'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.2'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.2'
|
||||
implementation 'com.google.android.exoplayer:extension-cast:2.12.2'
|
||||
implementation 'com.google.android.exoplayer:extension-mediasession:2.12.2'
|
||||
|
||||
implementation 'com.google.android:flexbox:2.0.1'
|
||||
|
||||
|
@ -89,17 +118,27 @@ dependencies {
|
|||
|
||||
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'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.10'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.3.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')
|
||||
__64bitImplementation files('libs/lbrysdk-0.74.0-release__arm64.aar')
|
||||
__32bitImplementation 'io.lbry:lbrysdk32:0.102.0'
|
||||
__64bitImplementation 'io.lbry:lbrysdk64:0.102.0'
|
||||
//__64bitImplementation(name: 'lbrysdk', ext: 'aar')
|
||||
}
|
||||
|
||||
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"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.lbry.browser"
|
||||
android:installLocation="auto">
|
||||
|
||||
|
@ -10,6 +11,10 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_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
|
||||
android:allowBackup="true"
|
||||
|
@ -50,12 +55,38 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</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>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="lbry" />
|
||||
</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
|
||||
|
@ -70,6 +101,11 @@
|
|||
android:theme="@style/AppTheme.NoActionBarTranslucent"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
||||
android:screenOrientation="fullSensor"
|
||||
tools:replace="screenOrientation" />
|
||||
|
||||
<service
|
||||
android:name="io.lbry.browser.LbrynetMessagingService"
|
||||
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.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
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.Lbry;
|
||||
import io.lbry.browser.utils.LbryAnalytics;
|
||||
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 {
|
||||
|
||||
private BroadcastReceiver sdkReadyReceiver;
|
||||
private BroadcastReceiver sdkReceiver;
|
||||
private BroadcastReceiver authReceiver;
|
||||
|
||||
@Override
|
||||
|
@ -43,21 +54,51 @@ public class FirstRunActivity extends AppCompatActivity {
|
|||
});
|
||||
|
||||
registerAuthReceiver();
|
||||
if (!Lbry.SDK_READY) {
|
||||
findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(MainActivity.ACTION_SDK_READY);
|
||||
sdkReadyReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(MainActivity.ACTION_SDK_READY);
|
||||
filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
|
||||
sdkReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
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();
|
||||
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
|
||||
finish();
|
||||
if (MainActivity.instance != null) {
|
||||
MainActivity.instance.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
registerReceiver(sdkReadyReceiver, filter);
|
||||
} else {
|
||||
authenticate();
|
||||
}
|
||||
}
|
||||
};
|
||||
registerReceiver(sdkReceiver, filter);
|
||||
|
||||
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() {
|
||||
|
@ -97,7 +138,8 @@ public class FirstRunActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -121,17 +163,89 @@ public class FirstRunActivity extends AppCompatActivity {
|
|||
@Override
|
||||
protected void onDestroy() {
|
||||
Helper.unregisterReceiver(authReceiver, this);
|
||||
Helper.unregisterReceiver(sdkReadyReceiver, this);
|
||||
Helper.unregisterReceiver(sdkReceiver, this);
|
||||
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 Context context;
|
||||
private final Context context;
|
||||
public AuthenticateTask(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
protected Void doInBackground(Void... params) {
|
||||
Lbryio.authenticate(context);
|
||||
try {
|
||||
Lbryio.authenticate(context);
|
||||
} catch (AuthTokenInvalidatedException ex) {
|
||||
// pass
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.app.PendingIntent;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
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.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.lbrysdk.LbrynetService;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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 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_REWARD = "reward";
|
||||
private static final String TYPE_INTERESTS = "interests";
|
||||
|
@ -52,12 +56,9 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
String title = payload.get("title");
|
||||
String body = payload.get("body");
|
||||
String name = payload.get("name"); // notification name
|
||||
String contentTitle = payload.get("content_title");
|
||||
String channelUrl = payload.get("channel_url");
|
||||
//String publishTime = payload.get("publish_time");
|
||||
String publishTime = null;
|
||||
String hash = payload.get("hash"); // comment hash
|
||||
|
||||
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
|
||||
if (firebaseAnalytics != null) {
|
||||
Bundle bundle = new Bundle();
|
||||
|
@ -65,14 +66,41 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
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
|
||||
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
|
||||
// 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.
|
||||
*/
|
||||
private void sendNotification(String title, String messageBody, String type, String url, String name,
|
||||
String contentTitle, String channelUrl, String publishTime) {
|
||||
private void sendNotification(String title, String messageBody, String type, String url, String name) {
|
||||
//Intent intent = new Intent(this, MainActivity.class);
|
||||
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
if (url == null) {
|
||||
|
@ -143,6 +170,9 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
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)) {
|
||||
enabledTypes.add(TYPE_SUBSCRIPTION);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,25 +1,47 @@
|
|||
package io.lbry.browser;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.adapter.VerificationPagerAdapter;
|
||||
import io.lbry.browser.listener.SdkStatusListener;
|
||||
import io.lbry.browser.listener.SignInListener;
|
||||
import io.lbry.browser.listener.WalletSyncListener;
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
import io.lbry.browser.model.lbryinc.User;
|
||||
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryAnalytics;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import io.lbry.lbrysdk.LbrynetService;
|
||||
|
||||
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_WALLET = 3;
|
||||
|
||||
private List<SdkStatusListener> sdkStatusListeners;
|
||||
private BillingClient billingClient;
|
||||
private BroadcastReceiver sdkReceiver;
|
||||
private String email;
|
||||
private boolean signedIn;
|
||||
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
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
sdkStatusListeners = new ArrayList<>();
|
||||
|
||||
signedIn = Lbryio.isSignedIn();
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
|
@ -54,6 +128,32 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
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);
|
||||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||
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() {
|
||||
super.onResume();
|
||||
LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
|
||||
|
@ -85,14 +203,17 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
flowHandled = true;
|
||||
} else if (flow == VERIFICATION_FLOW_REWARDS) {
|
||||
User user = Lbryio.currentUser;
|
||||
// disable phone verification for now
|
||||
if (!user.isIdentityVerified()) {
|
||||
// phone number verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||
flowHandled = true;
|
||||
} else if (!user.isRewardApproved()) {
|
||||
// manual verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||
flowHandled = true;
|
||||
} else {
|
||||
if (!user.isRewardApproved()) {
|
||||
// manual verification required
|
||||
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() {
|
||||
findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE);
|
||||
|
@ -118,8 +244,12 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// ignore back press
|
||||
return;
|
||||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||
|
||||
if (viewPager.getCurrentItem() != VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL)
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL);
|
||||
else
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
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
|
||||
showLoading();
|
||||
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||
@Override
|
||||
public void onSuccess(User user) {
|
||||
Lbryio.currentUser = user;
|
||||
|
@ -158,7 +288,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
showFetchUserError(error.getMessage());
|
||||
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
|
@ -166,7 +296,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
} else {
|
||||
// change pager view depending on flow
|
||||
showLoading();
|
||||
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||
@Override
|
||||
public void onSuccess(User user) {
|
||||
hideLoading();
|
||||
|
@ -179,13 +309,15 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
if (!user.isIdentityVerified()) {
|
||||
// phone number verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||
} else if (!user.isRewardApproved()) {
|
||||
// manual verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||
} else {
|
||||
// fully verified
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
if (!user.isRewardApproved()) {
|
||||
// manual verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||
} else {
|
||||
// fully verified
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
} else if (flow == VERIFICATION_FLOW_WALLET) {
|
||||
// for wallet sync, if password unlock is required, show password entry page
|
||||
|
@ -194,7 +326,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
}
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
showFetchUserError(error.getMessage());
|
||||
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
|
@ -210,7 +342,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
@Override
|
||||
public void onPhoneVerified() {
|
||||
showLoading();
|
||||
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() {
|
||||
@Override
|
||||
public void onSuccess(User user) {
|
||||
Lbryio.currentUser = user;
|
||||
|
@ -223,6 +355,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
return;
|
||||
}
|
||||
|
||||
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
||||
// show manual verification page if the user is still not reward approved
|
||||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||
|
@ -231,7 +364,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
showFetchUserError(error.getMessage());
|
||||
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error));
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
|
@ -269,4 +402,68 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
public void onWalletSyncFailed(Exception error) {
|
||||
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;
|
||||
|
||||
public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilterListAdapter.ViewHolder> {
|
||||
private Context context;
|
||||
private final Context context;
|
||||
private List<Claim> items;
|
||||
@Getter
|
||||
@Setter
|
||||
|
@ -42,12 +42,12 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected View mediaContainer;
|
||||
protected View alphaContainer;
|
||||
protected View allView;
|
||||
protected ImageView thumbnailView;
|
||||
protected TextView alphaView;
|
||||
protected TextView titleView;
|
||||
protected final View mediaContainer;
|
||||
protected final View alphaContainer;
|
||||
protected final View allView;
|
||||
protected final ImageView thumbnailView;
|
||||
protected final TextView alphaView;
|
||||
protected final TextView titleView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
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.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) {
|
||||
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.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());
|
||||
Helper.setIconViewBackgroundColor(vh.alphaContainer, bgColor, claim.isPlaceholder(), context);
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.view.ViewGroup;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -22,7 +21,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.MainActivity;
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.listener.SelectionModeListener;
|
||||
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_FEATURED = 3; // featured search result
|
||||
|
||||
private Map<String, Claim> quickClaimIdMap;
|
||||
private Map<String, Claim> quickClaimUrlMap;
|
||||
private Map<String, Boolean> notFoundClaimIdMap;
|
||||
private Map<String, Boolean> notFoundClaimUrlMap;
|
||||
private final Map<String, Claim> quickClaimIdMap;
|
||||
private final Map<String, Claim> quickClaimUrlMap;
|
||||
private final Map<String, Boolean> notFoundClaimIdMap;
|
||||
private final Map<String, Boolean> notFoundClaimUrlMap;
|
||||
|
||||
@Setter
|
||||
private boolean hideFee;
|
||||
@Setter
|
||||
private boolean canEnterSelectionMode;
|
||||
private Context context;
|
||||
private final Context context;
|
||||
private List<Claim> items;
|
||||
private List<Claim> selectedItems;
|
||||
private final List<Claim> selectedItems;
|
||||
@Setter
|
||||
private ClaimListItemListener listener;
|
||||
@Getter
|
||||
|
@ -61,7 +59,13 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
|
||||
public ClaimListAdapter(List<Claim> items, 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<>();
|
||||
quickClaimIdMap = new HashMap<>();
|
||||
quickClaimUrlMap = new HashMap<>();
|
||||
|
@ -140,7 +144,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
|
||||
public void addItems(List<Claim> claims) {
|
||||
for (Claim claim : claims) {
|
||||
if (!items.contains(claim)) {
|
||||
if (claim != null && !items.contains(claim)) {
|
||||
items.add(claim);
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +154,12 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
public void setItems(List<Claim> claims) {
|
||||
items = new ArrayList<>(claims);
|
||||
items = new ArrayList<>();
|
||||
for (Claim claim : claims) {
|
||||
if (claim != null) {
|
||||
items.add(claim);
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
@ -166,23 +175,27 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected View feeContainer;
|
||||
protected TextView feeView;
|
||||
protected ImageView thumbnailView;
|
||||
protected View noThumbnailView;
|
||||
protected TextView alphaView;
|
||||
protected TextView vanityUrlView;
|
||||
protected TextView durationView;
|
||||
protected TextView titleView;
|
||||
protected TextView publisherView;
|
||||
protected TextView publishTimeView;
|
||||
protected TextView pendingTextView;
|
||||
protected View repostInfoView;
|
||||
protected TextView repostChannelView;
|
||||
protected View selectedOverlayView;
|
||||
protected TextView fileSizeView;
|
||||
protected ProgressBar downloadProgressView;
|
||||
protected TextView deviceView;
|
||||
protected final View feeContainer;
|
||||
protected final TextView feeView;
|
||||
protected final ImageView thumbnailView;
|
||||
protected final View noThumbnailView;
|
||||
protected final TextView alphaView;
|
||||
protected final TextView vanityUrlView;
|
||||
protected final TextView durationView;
|
||||
protected final TextView titleView;
|
||||
protected final TextView publisherView;
|
||||
protected final TextView publishTimeView;
|
||||
protected final TextView pendingTextView;
|
||||
protected final View repostInfoView;
|
||||
protected final TextView repostChannelView;
|
||||
protected final View selectedOverlayView;
|
||||
protected final TextView fileSizeView;
|
||||
protected final ProgressBar downloadProgressView;
|
||||
protected final TextView deviceView;
|
||||
|
||||
protected final View loadingImagePlaceholder;
|
||||
protected final View loadingTextPlaceholder1;
|
||||
protected final View loadingTextPlaceholder2;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
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);
|
||||
downloadProgressView = v.findViewById(R.id.claim_download_progress);
|
||||
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);
|
||||
}
|
||||
|
||||
public int getScaledValue(int value) {
|
||||
return (int) (value * scale + 0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
|
||||
int type = getItemViewType(position);
|
||||
int paddingTop = position == 0 ? 16 : 8;
|
||||
int paddingBottom = position == getItemCount() - 1 ? 16 : 8;
|
||||
int paddingTopScaled = getScaledValue(paddingTop);
|
||||
int paddingBottomScaled = getScaledValue(paddingBottom);
|
||||
vh.itemView.setPadding(vh.itemView.getPaddingLeft(), paddingTopScaled, vh.itemView.getPaddingRight(), paddingBottomScaled);
|
||||
int paddingTopScaled = Helper.getScaledValue(paddingTop, scale);
|
||||
int paddingBottomScaled = Helper.getScaledValue(paddingBottom, scale);
|
||||
vh.itemView.setPadding(vh.itemView.getPaddingStart(), paddingTopScaled, vh.itemView.getPaddingEnd(), paddingBottomScaled);
|
||||
|
||||
Claim original = items.get(position);
|
||||
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 signingChannel = item.getSigningChannel();
|
||||
Claim.StreamMetadata streamMetadata = null;
|
||||
if (metadata instanceof Claim.StreamMetadata) {
|
||||
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;
|
||||
int bgColor = Helper.generateRandomColorForValue(item.getClaimId());
|
||||
if (bgColor == 0) {
|
||||
|
@ -328,14 +343,17 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
}
|
||||
|
||||
boolean isPending = item.getConfirmations() == 0;
|
||||
boolean isSelected = isClaimSelected(item);
|
||||
boolean isSelected = isClaimSelected(original);
|
||||
vh.itemView.setSelected(isSelected);
|
||||
vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE);
|
||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -356,7 +374,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -381,9 +402,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
});
|
||||
|
||||
vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE);
|
||||
vh.pendingTextView.setVisibility(isPending ? View.VISIBLE : View.GONE);
|
||||
vh.repostInfoView.setVisibility(isRepost ? View.VISIBLE : View.GONE);
|
||||
vh.repostChannelView.setText(isRepost ? original.getSigningChannel().getName() : null);
|
||||
vh.pendingTextView.setVisibility(isPending && !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
|
||||
vh.repostInfoView.setVisibility(isRepost && type != VIEW_TYPE_FEATURED ? View.VISIBLE : View.GONE);
|
||||
vh.repostChannelView.setText(isRepost && original.getSigningChannel() != null ? original.getSigningChannel().getName() : null);
|
||||
vh.repostChannelView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
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);
|
||||
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()) {
|
||||
vh.durationView.setVisibility(View.GONE);
|
||||
vh.titleView.setText("Nothing here. Publish something!");
|
||||
|
@ -413,6 +441,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
long duration = item.getDuration();
|
||||
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
|
||||
Glide.with(context.getApplicationContext()).
|
||||
asBitmap().
|
||||
load(thumbnailUrl).
|
||||
centerCrop().
|
||||
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_CONTENT = 2;
|
||||
|
||||
private Context context;
|
||||
private List<EditorsChoiceItem> items;
|
||||
private final Context context;
|
||||
private final List<EditorsChoiceItem> items;
|
||||
@Setter
|
||||
private EditorsChoiceItemListener listener;
|
||||
|
||||
|
@ -48,11 +48,11 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected ImageView thumbnailView;
|
||||
protected TextView descriptionView;
|
||||
protected TextView headerView;
|
||||
protected TextView titleView;
|
||||
protected View cardView;
|
||||
protected final ImageView thumbnailView;
|
||||
protected final TextView descriptionView;
|
||||
protected final TextView headerView;
|
||||
protected final TextView titleView;
|
||||
protected final View cardView;
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
|
@ -95,6 +95,7 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
|
|||
vh.descriptionView.setText(item.getDescription());
|
||||
if (!Helper.isNullOrEmpty(item.getThumbnailUrl())) {
|
||||
Glide.with(context.getApplicationContext()).
|
||||
asBitmap().
|
||||
load(item.getThumbnailUrl()).
|
||||
centerCrop().
|
||||
placeholder(R.drawable.bg_thumbnail_placeholder).
|
||||
|
|
|
@ -21,8 +21,8 @@ import io.lbry.browser.utils.Helper;
|
|||
import lombok.Setter;
|
||||
|
||||
public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> {
|
||||
private Context context;
|
||||
private List<GalleryItem> items;
|
||||
private final Context context;
|
||||
private final List<GalleryItem> items;
|
||||
@Setter
|
||||
private GalleryItemClickListener listener;
|
||||
|
||||
|
@ -32,8 +32,8 @@ public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected ImageView thumbnailView;
|
||||
protected TextView durationView;
|
||||
protected final ImageView thumbnailView;
|
||||
protected final TextView durationView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
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 {
|
||||
|
||||
private int spanCount;
|
||||
private int spacing;
|
||||
private final int spanCount;
|
||||
private final int spacing;
|
||||
|
||||
public GalleryGridItemDecoration(int spanCount, int spacing) {
|
||||
this.spanCount = spanCount;
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package io.lbry.browser.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObserver;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.SpinnerAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
|
@ -17,9 +16,9 @@ import io.lbry.browser.model.Claim;
|
|||
|
||||
public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
|
||||
|
||||
private List<Claim> channels;
|
||||
private int layoutResourceId;
|
||||
private LayoutInflater inflater;
|
||||
private final List<Claim> channels;
|
||||
private final int layoutResourceId;
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
public InlineChannelSpinnerAdapter(Context context, int resource, List<Claim> channels) {
|
||||
super(context, resource, 0, channels);
|
||||
|
@ -40,11 +39,30 @@ public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
|
|||
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) {
|
||||
for (int i = 0; i < channels.size(); i++) {
|
||||
Claim channel = channels.get(i);
|
||||
if (item.getClaimId().equalsIgnoreCase(channel.getClaimId())) {
|
||||
if (item.getClaimId() != null && item.getClaimId().equalsIgnoreCase(channel.getClaimId())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package io.lbry.browser.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -11,21 +9,16 @@ import android.widget.TextView;
|
|||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
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> {
|
||||
|
||||
private Context context;
|
||||
private List<Invitee> items;
|
||||
private final Context context;
|
||||
private final List<Invitee> items;
|
||||
|
||||
public InviteeListAdapter(List<Invitee> invitees, Context context) {
|
||||
this.context = context;
|
||||
|
@ -80,8 +73,8 @@ public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected TextView emailView;
|
||||
protected TextView rewardView;
|
||||
protected final TextView emailView;
|
||||
protected final TextView rewardView;
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
|
|
|
@ -10,13 +10,12 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.Language;
|
||||
import io.lbry.browser.utils.Predefined;
|
||||
|
||||
public class LanguageSpinnerAdapter extends ArrayAdapter<Language> {
|
||||
private int layoutResourceId;
|
||||
private LayoutInflater inflater;
|
||||
private final int layoutResourceId;
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
public LanguageSpinnerAdapter(Context context, int resource) {
|
||||
super(context, resource, 0, Predefined.PUBLISH_LANGUAGES);
|
||||
|
|
|
@ -10,13 +10,12 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.model.Language;
|
||||
import io.lbry.browser.model.License;
|
||||
import io.lbry.browser.utils.Predefined;
|
||||
|
||||
public class LicenseSpinnerAdapter extends ArrayAdapter<License> {
|
||||
private int layoutResourceId;
|
||||
private LayoutInflater inflater;
|
||||
private final int layoutResourceId;
|
||||
private final LayoutInflater inflater;
|
||||
|
||||
public LicenseSpinnerAdapter(Context context, int resource) {
|
||||
super(context, resource, 0, Predefined.LICENSES);
|
||||
|
|
|
@ -2,10 +2,8 @@ package io.lbry.browser.adapter;
|
|||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -17,15 +15,14 @@ import io.lbry.browser.R;
|
|||
import io.lbry.browser.model.NavMenuItem;
|
||||
import io.lbry.browser.ui.controls.SolidIconView;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> {
|
||||
private static final int TYPE_GROUP = 1;
|
||||
private static final int TYPE_ITEM = 2;
|
||||
|
||||
private Context context;
|
||||
private List<NavMenuItem> menuItems;
|
||||
private final Context context;
|
||||
private final List<NavMenuItem> menuItems;
|
||||
private NavMenuItem currentItem;
|
||||
@Setter
|
||||
private NavigationMenuItemClickListener listener;
|
||||
|
@ -65,8 +62,8 @@ public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAd
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected SolidIconView iconView;
|
||||
protected TextView titleView;
|
||||
protected final SolidIconView iconView;
|
||||
protected final TextView titleView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
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_UNCLAIMED = 2;
|
||||
|
||||
private Context context;
|
||||
private final Context context;
|
||||
@Setter
|
||||
private List<Reward> all;
|
||||
private List<Reward> items;
|
||||
|
@ -85,16 +85,16 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected View iconClaimed;
|
||||
protected View loading;
|
||||
protected View upTo;
|
||||
protected TextView textTitle;
|
||||
protected TextView textDescription;
|
||||
protected TextView textLbcValue;
|
||||
protected TextView textUsdValue;
|
||||
protected TextView textLinkTransaction;
|
||||
protected EditText inputCustomCode;
|
||||
protected MaterialButton buttonClaimCustom;
|
||||
protected final View iconClaimed;
|
||||
protected final View loading;
|
||||
protected final View upTo;
|
||||
protected final TextView textTitle;
|
||||
protected final TextView textDescription;
|
||||
protected final TextView textLbcValue;
|
||||
protected final TextView textUsdValue;
|
||||
protected final TextView textLinkTransaction;
|
||||
protected final EditText inputCustomCode;
|
||||
protected final MaterialButton buttonClaimCustom;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
|
||||
|
@ -168,6 +168,10 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
|
|||
return;
|
||||
}
|
||||
|
||||
if (vh.inputCustomCode != null && !vh.inputCustomCode.hasFocus()) {
|
||||
vh.inputCustomCode.requestFocus();
|
||||
}
|
||||
|
||||
if (clickListener != null) {
|
||||
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;
|
||||
|
||||
public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> {
|
||||
private Context context;
|
||||
private List<Claim> items;
|
||||
private List<Claim> selectedItems;
|
||||
private final Context context;
|
||||
private final List<Claim> items;
|
||||
private final List<Claim> selectedItems;
|
||||
@Setter
|
||||
private ChannelItemSelectionListener listener;
|
||||
|
||||
|
@ -35,11 +35,11 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected View noThumbnailView;
|
||||
protected ImageView thumbnailView;
|
||||
protected TextView alphaView;
|
||||
protected TextView titleView;
|
||||
protected TextView tagView;
|
||||
protected final View noThumbnailView;
|
||||
protected final ImageView thumbnailView;
|
||||
protected final TextView alphaView;
|
||||
protected final TextView titleView;
|
||||
protected final TextView tagView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
|
||||
|
@ -89,7 +89,8 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
|
|||
@Override
|
||||
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int 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());
|
||||
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_REMOVE = 2;
|
||||
|
||||
private Context context;
|
||||
private final Context context;
|
||||
private List<Tag> items;
|
||||
@Setter
|
||||
private TagClickListener clickListener;
|
||||
@Getter
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
private int customizeMode;
|
||||
|
||||
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 {
|
||||
protected ImageView iconView;
|
||||
protected TextView nameView;
|
||||
protected final ImageView iconView;
|
||||
protected final TextView nameView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
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 SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
|
||||
|
||||
private Context context;
|
||||
private List<Transaction> items;
|
||||
private final Context context;
|
||||
private final List<Transaction> items;
|
||||
@Setter
|
||||
private TransactionClickListener listener;
|
||||
|
||||
|
@ -72,7 +72,9 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
|||
vh.claimView.setText(item.getClaim());
|
||||
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.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 ?
|
||||
View.VISIBLE : View.GONE);
|
||||
|
@ -105,13 +107,14 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected TextView descView;
|
||||
protected TextView amountView;
|
||||
protected TextView claimView;
|
||||
protected TextView feeView;
|
||||
protected TextView txidLinkView;
|
||||
protected TextView dateView;
|
||||
protected View infoFeeContainer;
|
||||
protected final TextView descView;
|
||||
protected final TextView amountView;
|
||||
protected final TextView claimView;
|
||||
protected final TextView feeView;
|
||||
protected final TextView txidLinkView;
|
||||
protected final TextView dateView;
|
||||
protected final TextView pendingView;
|
||||
protected final View infoFeeContainer;
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
|
@ -121,6 +124,7 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
|
|||
feeView = v.findViewById(R.id.transaction_fee);
|
||||
txidLinkView = v.findViewById(R.id.transaction_id_link);
|
||||
dateView = v.findViewById(R.id.transaction_date);
|
||||
pendingView = v.findViewById(R.id.transaction_pending_text);
|
||||
infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ import io.lbry.browser.utils.LbryUri;
|
|||
import lombok.Setter;
|
||||
|
||||
public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestionListAdapter.ViewHolder> {
|
||||
private Context context;
|
||||
private List<UrlSuggestion> items;
|
||||
private final Context context;
|
||||
private final List<UrlSuggestion> items;
|
||||
@Setter
|
||||
private UrlSuggestionClickListener listener;
|
||||
|
||||
|
@ -130,9 +130,9 @@ public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestion
|
|||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected SolidIconView iconView;
|
||||
protected TextView titleView;
|
||||
protected TextView descView;
|
||||
protected final SolidIconView iconView;
|
||||
protected final TextView titleView;
|
||||
protected final TextView descView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
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_MANUAL = 3;
|
||||
|
||||
private FragmentActivity activity;
|
||||
private final FragmentActivity activity;
|
||||
|
||||
public VerificationPagerAdapter(FragmentActivity 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.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.opengl.Visibility;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
|
@ -13,22 +12,22 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.exceptions.LbryUriException;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.model.UrlSuggestion;
|
||||
import io.lbry.browser.model.ViewHistory;
|
||||
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
|
||||
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";
|
||||
private static DatabaseHelper instance;
|
||||
|
||||
private static final String[] SQL_CREATE_TABLES = {
|
||||
// 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
|
||||
"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)
|
||||
|
@ -48,7 +47,20 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
", thumbnail_url TEXT" +
|
||||
", release_time INTEGER " +
|
||||
", 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 = {
|
||||
"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_tag_name ON tags (name)",
|
||||
"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 = {
|
||||
"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_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_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_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 =
|
||||
"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 =
|
||||
|
@ -110,6 +169,36 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
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) {
|
||||
|
||||
|
@ -126,6 +215,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
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()) });
|
||||
}
|
||||
|
||||
// History items are essentially url suggestions
|
||||
public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) {
|
||||
List<UrlSuggestion> suggestions = new ArrayList<>();
|
||||
|
@ -225,11 +315,21 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
List<Subscription> subscriptions = new ArrayList<>();
|
||||
Cursor cursor = null;
|
||||
|
@ -239,6 +339,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
Subscription subscription = new Subscription();
|
||||
subscription.setChannelName(cursor.getString(0));
|
||||
subscription.setUrl(cursor.getString(1));
|
||||
subscription.setNotificationsDisabled(cursor.getInt(2) == 1);
|
||||
subscriptions.add(subscription);
|
||||
}
|
||||
} finally {
|
||||
|
@ -247,4 +348,112 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
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_all_time_item
|
||||
};
|
||||
private BottomSheetDialogFragment dialog;
|
||||
private ContentFromListener listener;
|
||||
private final BottomSheetDialogFragment dialog;
|
||||
private final ContentFromListener listener;
|
||||
|
||||
public ContentFromItemClickListener(BottomSheetDialogFragment dialog, ContentFromListener listener) {
|
||||
this.dialog = dialog;
|
||||
|
|
|
@ -54,8 +54,8 @@ public class ContentScopeDialogFragment extends BottomSheetDialogFragment {
|
|||
private final int[] checkViewIds = {
|
||||
R.id.content_scope_everyone_item_selected, R.id.content_scope_tags_item_selected
|
||||
};
|
||||
private BottomSheetDialogFragment dialog;
|
||||
private ContentScopeListener listener;
|
||||
private final BottomSheetDialogFragment dialog;
|
||||
private final ContentScopeListener listener;
|
||||
|
||||
public ContentScopeItemClickListener(BottomSheetDialogFragment dialog, ContentScopeListener listener) {
|
||||
this.dialog = dialog;
|
||||
|
|
|
@ -57,8 +57,8 @@ public class ContentSortDialogFragment extends BottomSheetDialogFragment {
|
|||
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
|
||||
};
|
||||
private BottomSheetDialogFragment dialog;
|
||||
private SortByListener listener;
|
||||
private final BottomSheetDialogFragment dialog;
|
||||
private final SortByListener listener;
|
||||
|
||||
public SortByItemClickListener(BottomSheetDialogFragment dialog, SortByListener listener) {
|
||||
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;
|
||||
}
|
||||
|
||||
private TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
|
||||
private final TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
|
||||
@Override
|
||||
public void onTagClicked(Tag tag, int customizeMode) {
|
||||
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
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.Lbry;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import lombok.Setter;
|
||||
|
||||
public class RepostClaimDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener {
|
||||
public static final String TAG = "RepostClaimDialog";
|
||||
|
@ -57,13 +56,17 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
|||
private TextView linkToggleAdvanced;
|
||||
private View advancedContainer;
|
||||
|
||||
@Setter
|
||||
private RepostClaimListener listener;
|
||||
@Setter
|
||||
private Claim claim;
|
||||
private final RepostClaimListener listener;
|
||||
private final Claim claim;
|
||||
|
||||
public static RepostClaimDialogFragment newInstance() {
|
||||
return new RepostClaimDialogFragment();
|
||||
private RepostClaimDialogFragment(Claim claim, RepostClaimListener listener) {
|
||||
super();
|
||||
this.listener = listener;
|
||||
this.claim = claim;
|
||||
}
|
||||
|
||||
public static RepostClaimDialogFragment newInstance(Claim claim, RepostClaimListener listener) {
|
||||
return new RepostClaimDialogFragment(claim, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -192,14 +195,16 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
|||
private void loadChannels(List<Claim> channels) {
|
||||
if (channelSpinnerAdapter == null) {
|
||||
Context context = getContext();
|
||||
channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels);
|
||||
channelSpinnerAdapter.notifyDataSetChanged();
|
||||
if (context != null) {
|
||||
channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels);
|
||||
channelSpinnerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
channelSpinnerAdapter.clear();
|
||||
channelSpinnerAdapter.addAll(channels);
|
||||
channelSpinnerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (channelSpinner != null) {
|
||||
if (channelSpinner != null && channelSpinnerAdapter != null) {
|
||||
channelSpinner.setAdapter(channelSpinnerAdapter);
|
||||
}
|
||||
}
|
||||
|
@ -229,8 +234,18 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
|||
showError(getString(R.string.insufficient_balance));
|
||||
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();
|
||||
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() {
|
||||
@Override
|
||||
public void beforeStart() {
|
||||
|
@ -256,10 +271,13 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
|
|||
}
|
||||
|
||||
private void showError(String message) {
|
||||
Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
|
||||
setBackgroundTint(Color.RED).
|
||||
setTextColor(Color.WHITE).
|
||||
show();
|
||||
View view = getView();
|
||||
if (view != null && !Helper.isNullOrEmpty(message)) {
|
||||
Snackbar.make(view, message, Snackbar.LENGTH_LONG).
|
||||
setBackgroundTint(Color.RED).
|
||||
setTextColor(Color.WHITE).
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
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 onPhoneVerified();
|
||||
void onManualVerifyContinue();
|
||||
void onSkipQueueAction();
|
||||
void onTwitterVerified();
|
||||
void onManualProgress(boolean progress);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.lbry.browser.model;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
@ -15,7 +17,6 @@ import java.text.SimpleDateFormat;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
|
@ -54,6 +55,7 @@ public class Claim {
|
|||
@EqualsAndHashCode.Include
|
||||
private boolean placeholder;
|
||||
private boolean placeholderAnonymous;
|
||||
private boolean loadingPlaceholder;
|
||||
private boolean featured;
|
||||
private boolean unresolved; // used for featured
|
||||
private String address;
|
||||
|
@ -137,6 +139,14 @@ public class Claim {
|
|||
return null;
|
||||
}
|
||||
|
||||
public boolean hasSource() {
|
||||
if (value instanceof StreamMetadata) {
|
||||
StreamMetadata metadata = (StreamMetadata) value;
|
||||
return metadata.getSource() != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isPlayable() {
|
||||
if (value instanceof StreamMetadata) {
|
||||
StreamMetadata metadata = (StreamMetadata) value;
|
||||
|
@ -176,6 +186,21 @@ public class Claim {
|
|||
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() {
|
||||
if (TYPE_CHANNEL.equals(valueType) && value != null && value instanceof ChannelMetadata && ((ChannelMetadata) value).getCover() != null) {
|
||||
return ((ChannelMetadata) value).getCover().getUrl();
|
||||
|
@ -289,6 +314,9 @@ public class Claim {
|
|||
Claim signingChannel = new Claim();
|
||||
signingChannel.setClaimId(viewHistory.getPublisherClaimId());
|
||||
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())) {
|
||||
GenericMetadata channelValue = new GenericMetadata();
|
||||
channelValue.setTitle(viewHistory.getPublisherTitle());
|
||||
|
@ -480,6 +508,30 @@ public class Claim {
|
|||
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
|
||||
public static class StreamInfo {
|
||||
private long duration; // video / audio
|
||||
|
|
|
@ -40,7 +40,7 @@ public class ClaimCacheKey {
|
|||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == null || !(obj instanceof ClaimCacheKey)) {
|
||||
if (!(obj instanceof ClaimCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
ClaimCacheKey key = (ClaimCacheKey) obj;
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
package io.lbry.browser.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ClaimSearchCacheValue {
|
||||
@Getter
|
||||
@Setter
|
||||
private List<Claim> claims;
|
||||
private final List<Claim> claims;
|
||||
@Getter
|
||||
@Setter
|
||||
private long timestamp;
|
||||
private final long timestamp;
|
||||
|
||||
public ClaimSearchCacheValue(List<Claim> claims, long timestamp) {
|
||||
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
|
||||
public class Language {
|
||||
private String code;
|
||||
private String name;
|
||||
private int stringResourceId;
|
||||
private final String code;
|
||||
private final String name;
|
||||
private final int stringResourceId;
|
||||
|
||||
public Language(String code, String name, int stringResourceId) {
|
||||
this.code = code;
|
||||
|
|
|
@ -4,9 +4,9 @@ import lombok.Data;
|
|||
|
||||
@Data
|
||||
public class License {
|
||||
private String name;
|
||||
private final String name;
|
||||
private String url;
|
||||
private int stringResourceId;
|
||||
private final int stringResourceId;
|
||||
|
||||
public License(String name, int stringResourceId) {
|
||||
this.name = name;
|
||||
|
|
|
@ -2,8 +2,6 @@ package io.lbry.browser.model;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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_EDITORS_CHOICE = 102;
|
||||
public static final int ID_ITEM_ALL_CONTENT = 103;
|
||||
public static final int ID_ITEM_SHUFFLE = 104;
|
||||
|
||||
// Your Content
|
||||
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_ABOUT = 402;
|
||||
|
||||
private Context context;
|
||||
private int id;
|
||||
private final Context context;
|
||||
private final int id;
|
||||
private boolean group;
|
||||
private int icon;
|
||||
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 java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.exceptions.LbryUriException;
|
||||
|
@ -53,13 +55,22 @@ public class Transaction {
|
|||
|
||||
int descStringId = -1;
|
||||
TransactionInfo info = null;
|
||||
List<TransactionInfo> infos = new ArrayList<>();
|
||||
try {
|
||||
if (jsonObject.has("abandon_info")) {
|
||||
JSONArray array = jsonObject.getJSONArray("abandon_info");
|
||||
if (array.length() > 0) {
|
||||
info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
|
||||
descStringId = R.string.abandon;
|
||||
transaction.setAbandonInfo(info);
|
||||
if (array.length() == 1) {
|
||||
info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
|
||||
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")) {
|
||||
|
@ -94,8 +105,18 @@ public class Transaction {
|
|||
// 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) {
|
||||
|
|
|
@ -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.util.Date;
|
||||
|
||||
import io.lbry.browser.exceptions.LbryUriException;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
|
|
|
@ -1,16 +1,33 @@
|
|||
package io.lbry.browser.model;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
public class WalletBalance {
|
||||
@Setter
|
||||
@Getter
|
||||
private BigDecimal available;
|
||||
@Setter
|
||||
@Getter
|
||||
private BigDecimal reserved;
|
||||
@Setter
|
||||
@Getter
|
||||
private BigDecimal claims;
|
||||
@Setter
|
||||
@Getter
|
||||
private BigDecimal supports;
|
||||
@Setter
|
||||
@Getter
|
||||
private BigDecimal tips;
|
||||
@Setter
|
||||
@Getter
|
||||
private BigDecimal total;
|
||||
|
||||
public WalletBalance() {
|
||||
|
@ -21,4 +38,18 @@ public class WalletBalance {
|
|||
tips = 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;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
@Data
|
||||
public class WalletSync {
|
||||
private String hash;
|
||||
private String data;
|
||||
@Getter
|
||||
private final String hash;
|
||||
@Getter
|
||||
private final String data;
|
||||
@Getter
|
||||
private boolean changed;
|
||||
|
||||
public WalletSync(String hash, String data) {
|
||||
|
@ -17,4 +21,5 @@ public class WalletSync {
|
|||
this(hash, data);
|
||||
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 io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
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
|
||||
@Setter
|
||||
private String url;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean isNotificationsDisabled;
|
||||
|
||||
public Subscription() {
|
||||
|
||||
}
|
||||
public Subscription(String channelName, String url) {
|
||||
public Subscription(String channelName, String url, boolean isNotificationsDisabled) {
|
||||
this.channelName = channelName;
|
||||
this.url = url;
|
||||
this.isNotificationsDisabled = isNotificationsDisabled;
|
||||
}
|
||||
|
||||
public static Subscription fromClaim(Claim claim) {
|
||||
return new Subscription(claim.getName(), claim.getPermanentUrl());
|
||||
return new Subscription(claim.getName(), claim.getPermanentUrl(), false);
|
||||
}
|
||||
public String toString() {
|
||||
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;
|
||||
|
||||
public class FollowUnfollowTagTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private Tag tag;
|
||||
private boolean unfollowing;
|
||||
private Context context;
|
||||
private FollowUnfollowTagHandler handler;
|
||||
private final Tag tag;
|
||||
private final boolean unfollowing;
|
||||
private final Context context;
|
||||
private final FollowUnfollowTagHandler handler;
|
||||
private Exception error;
|
||||
|
||||
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;
|
||||
|
||||
public class LighthouseAutoCompleteTask extends AsyncTask<Void, Void, List<UrlSuggestion>> {
|
||||
private String text;
|
||||
private AutoCompleteResultHandler handler;
|
||||
private View progressView;
|
||||
private final String text;
|
||||
private final AutoCompleteResultHandler handler;
|
||||
private final View progressView;
|
||||
private Exception error;
|
||||
|
||||
public LighthouseAutoCompleteTask(String text, View progressView, AutoCompleteResultHandler handler) {
|
||||
|
|
|
@ -14,13 +14,13 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lighthouse;
|
||||
|
||||
public class LighthouseSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||
private String rawQuery;
|
||||
private int size;
|
||||
private int from;
|
||||
private boolean nsfw;
|
||||
private String relatedTo;
|
||||
private ClaimSearchResultHandler handler;
|
||||
private ProgressBar progressBar;
|
||||
private final String rawQuery;
|
||||
private final int size;
|
||||
private final int from;
|
||||
private final boolean nsfw;
|
||||
private final String relatedTo;
|
||||
private final ClaimSearchResultHandler handler;
|
||||
private final ProgressBar progressBar;
|
||||
private Exception error;
|
||||
|
||||
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.SQLiteException;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.MainActivity;
|
||||
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.utils.Helper;
|
||||
|
||||
public class LoadTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
||||
private Context context;
|
||||
private LoadTagsHandler handler;
|
||||
private final Context context;
|
||||
private final LoadTagsHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public LoadTagsTask(Context context, LoadTagsHandler handler) {
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.Context;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
@ -17,26 +16,25 @@ import java.util.Map;
|
|||
|
||||
import io.lbry.browser.MainActivity;
|
||||
import io.lbry.browser.data.DatabaseHelper;
|
||||
import io.lbry.browser.exceptions.LbryUriException;
|
||||
import io.lbry.browser.exceptions.LbryioRequestException;
|
||||
import io.lbry.browser.exceptions.LbryioResponseException;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import okhttp3.Response;
|
||||
|
||||
// background task to create a diff of local and remote subscriptions and try to merge
|
||||
public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscription>> {
|
||||
private static final String TAG = "MergeSubscriptionsTask";
|
||||
private Context context;
|
||||
private List<Subscription> base;
|
||||
private final Context context;
|
||||
private final List<Subscription> base;
|
||||
private List<Subscription> diff;
|
||||
private MergeSubscriptionsHandler handler;
|
||||
private final MergeSubscriptionsHandler handler;
|
||||
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.replaceLocal = replaceLocal;
|
||||
this.context = context;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
@ -53,10 +51,17 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
|
|||
db = ((MainActivity) context).getDbHelper().getWritableDatabase();
|
||||
}
|
||||
if (db != null) {
|
||||
localSubs = DatabaseHelper.getSubscriptions(db);
|
||||
for (Subscription sub : localSubs) {
|
||||
if (!combined.contains(sub)) {
|
||||
combined.add(sub);
|
||||
if (replaceLocal) {
|
||||
DatabaseHelper.clearSubscriptions(db);
|
||||
for (Subscription sub : base) {
|
||||
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
|
||||
JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("subscription", "list", context));
|
||||
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++) {
|
||||
JSONObject item = array.getJSONObject(i);
|
||||
// TODO: Refactor by creating static Subscription.fromJSON method
|
||||
String claimId = item.getString("claim_id");
|
||||
String channelName = item.getString("channel_name");
|
||||
boolean isNotificationsDisabled = item.getBoolean("is_notifications_disabled");
|
||||
|
||||
LbryUri url = new LbryUri();
|
||||
url.setChannelName(channelName);
|
||||
url.setClaimId(claimId);
|
||||
Subscription subscription = new Subscription(channelName, url.toString());
|
||||
Subscription subscription = new Subscription(channelName, url.toString(), isNotificationsDisabled);
|
||||
remoteSubs.add(subscription);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < combined.size(); i++) {
|
||||
Subscription local = combined.get(i);
|
||||
if (!remoteSubs.contains(local)) {
|
||||
// add to remote subscriptions
|
||||
try {
|
||||
LbryUri uri = LbryUri.parse(local.getUrl());
|
||||
List<Subscription> remoteUnsubs = new ArrayList<>();
|
||||
List<Subscription> finalRemoteSubs = new ArrayList<>();
|
||||
if (remoteSubs.size() > 0) {
|
||||
for (int i = 0; i < remoteSubs.size(); i++) {
|
||||
Subscription sub = remoteSubs.get(i);
|
||||
if (!combined.contains(sub)) {
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put("claim_id", uri.getChannelClaimId());
|
||||
options.put("channel_name", Helper.normalizeChannelName(local.getChannelName()));
|
||||
Lbryio.parseResponse(Lbryio.call("subscription", "new", options, context));
|
||||
} catch (LbryUriException | LbryioRequestException | LbryioResponseException ex) {
|
||||
// pass
|
||||
Log.e(TAG, String.format("subscription/new failed: %s", ex.getMessage()), ex);
|
||||
LbryUri uri = LbryUri.tryParse(sub.getUrl());
|
||||
if (uri != null) {
|
||||
options.put("claim_id", uri.getChannelClaimId());
|
||||
Lbryio.parseResponse(Lbryio.call("subscription", "delete", options, context));
|
||||
remoteUnsubs.add(sub);
|
||||
} else {
|
||||
finalRemoteSubs.add(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < localSubs.size(); i++) {
|
||||
Subscription local = localSubs.get(i);
|
||||
if (!base.contains(local) && !diff.contains(local)) {
|
||||
diff.add(local);
|
||||
if (!replaceLocal) {
|
||||
for (int i = 0; i < localSubs.size(); i++) {
|
||||
Subscription local = localSubs.get(i);
|
||||
if (!base.contains(local) && !diff.contains(local)) {
|
||||
diff.add(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < remoteSubs.size(); i++) {
|
||||
Subscription remote = remoteSubs.get(i);
|
||||
if (!combined.contains(remote)) {
|
||||
combined.add(remote);
|
||||
if (!diff.contains(remote)) {
|
||||
diff.add(remote);
|
||||
for (int i = 0; i < finalRemoteSubs.size(); i++) {
|
||||
Subscription remote = finalRemoteSubs.get(i);
|
||||
if (!combined.contains(remote)) {
|
||||
combined.add(remote);
|
||||
if (!diff.contains(remote)) {
|
||||
diff.add(remote);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,15 @@ import android.os.AsyncTask;
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.Buffer;
|
||||
|
||||
import io.lbry.browser.utils.Helper;
|
||||
|
||||
public class ReadTextFileTask extends AsyncTask<Void, Void, String> {
|
||||
private String filePath;
|
||||
private final String filePath;
|
||||
private Exception error;
|
||||
private ReadTextFileHandler handler;
|
||||
private final ReadTextFileHandler handler;
|
||||
public ReadTextFileTask(String filePath, ReadTextFileHandler handler) {
|
||||
this.filePath = filePath;
|
||||
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;
|
||||
|
||||
public class SetSdkSettingTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private String key;
|
||||
private String value;
|
||||
private GenericTaskHandler handler;
|
||||
private final String key;
|
||||
private final String value;
|
||||
private final GenericTaskHandler handler;
|
||||
private Exception error;
|
||||
public SetSdkSettingTask(String key, String value, GenericTaskHandler handler) {
|
||||
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>> {
|
||||
|
||||
private boolean clearPrevious;
|
||||
private boolean excludeMature;
|
||||
private int limit;
|
||||
private String filter;
|
||||
private TagListAdapter addedTagsAdapter;
|
||||
private TagListAdapter suggestedTagsAdapter;
|
||||
private KnownTagsHandler handler;
|
||||
private final boolean clearPrevious;
|
||||
private final boolean excludeMature;
|
||||
private final int limit;
|
||||
private final String filter;
|
||||
private final TagListAdapter addedTagsAdapter;
|
||||
private final TagListAdapter suggestedTagsAdapter;
|
||||
private final KnownTagsHandler handler;
|
||||
|
||||
public UpdateSuggestedTagsTask(
|
||||
String filter,
|
||||
|
@ -45,13 +45,15 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
|||
if (suggestedTagsAdapter != null && !clearPrevious) {
|
||||
tags = new ArrayList<>(suggestedTagsAdapter.getTags());
|
||||
}
|
||||
while (tags.size() < limit) {
|
||||
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
|
||||
if (excludeMature && randomTag.isMature()) {
|
||||
continue;
|
||||
}
|
||||
if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) {
|
||||
tags.add(randomTag);
|
||||
if (Lbry.knownTags.size() > 0) {
|
||||
while (tags.size() < limit) {
|
||||
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
|
||||
if (excludeMature && randomTag.isMature()) {
|
||||
continue;
|
||||
}
|
||||
if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) {
|
||||
tags.add(randomTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -64,10 +66,15 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
|||
if (excludeMature && knownTag.isMature()) {
|
||||
continue;
|
||||
}
|
||||
if ((knownTag.getLowercaseName().startsWith(filter) || knownTag.getLowercaseName().matches(filter)) &&
|
||||
(!tags.contains(knownTag) &&
|
||||
!Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag)))) {
|
||||
tags.add(knownTag);
|
||||
try {
|
||||
if ((knownTag.getLowercaseName().startsWith(filter) ||
|
||||
knownTag.getLowercaseName().matches(filter)) &&
|
||||
(!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;
|
||||
|
||||
public class UploadImageTask extends AsyncTask<Void, Void, String> {
|
||||
private String filePath;
|
||||
private View progressView;
|
||||
private UploadThumbnailHandler handler;
|
||||
private final String filePath;
|
||||
private final View progressView;
|
||||
private final UploadThumbnailHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public UploadImageTask(String filePath, View progressView, UploadThumbnailHandler handler) {
|
||||
|
|
|
@ -11,17 +11,16 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.exceptions.ApiCallException;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class AbandonChannelTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private List<String> claimIds;
|
||||
private final List<String> claimIds;
|
||||
private List<String> successfulClaimIds;
|
||||
private List<String> failedClaimIds;
|
||||
private List<Exception> failedExceptions;
|
||||
private View progressView;
|
||||
private AbandonHandler handler;
|
||||
private final View progressView;
|
||||
private final AbandonHandler handler;
|
||||
|
||||
public AbandonChannelTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
||||
this.claimIds = claimIds;
|
||||
|
|
|
@ -11,17 +11,16 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.exceptions.ApiCallException;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class AbandonStreamTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private List<String> claimIds;
|
||||
private final List<String> claimIds;
|
||||
private List<String> successfulClaimIds;
|
||||
private List<String> failedClaimIds;
|
||||
private List<Exception> failedExceptions;
|
||||
private View progressView;
|
||||
private AbandonHandler handler;
|
||||
private final View progressView;
|
||||
private final AbandonHandler handler;
|
||||
|
||||
public AbandonStreamTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
||||
this.claimIds = claimIds;
|
||||
|
|
|
@ -21,12 +21,12 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Claim> {
|
||||
private Claim claim;
|
||||
private BigDecimal deposit;
|
||||
private boolean update;
|
||||
private final Claim claim;
|
||||
private final BigDecimal deposit;
|
||||
private final boolean update;
|
||||
private Exception error;
|
||||
private ClaimResultHandler handler;
|
||||
private View progressView;
|
||||
private final ClaimResultHandler handler;
|
||||
private final View progressView;
|
||||
|
||||
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, ClaimResultHandler handler) {
|
||||
this.claim = claim;
|
||||
|
|
|
@ -19,9 +19,9 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||
private List<String> types;
|
||||
private View progressView;
|
||||
private ClaimListResultHandler handler;
|
||||
private final List<String> types;
|
||||
private final View progressView;
|
||||
private final ClaimListResultHandler handler;
|
||||
private Exception error;
|
||||
|
||||
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);
|
||||
if (handler != null) {
|
||||
if (claims != null) {
|
||||
handler.onSuccess(claims);
|
||||
// TODO: Add fix for handling invalid reposts in ClaimListAdapter
|
||||
handler.onSuccess(Helper.filterInvalidReposts(claims));
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||
private Map<String, Object> options;
|
||||
private String connectionString;
|
||||
private ClaimSearchResultHandler handler;
|
||||
private View progressView;
|
||||
private final Map<String, Object> options;
|
||||
private final String connectionString;
|
||||
private final ClaimSearchResultHandler handler;
|
||||
private final View progressView;
|
||||
private ApiCallException error;
|
||||
|
||||
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) {
|
||||
try {
|
||||
return Helper.filterInvalidReposts(Lbry.claimSearch(options, connectionString));
|
||||
return Lbry.claimSearch(options, connectionString);
|
||||
} catch (ApiCallException ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
|
@ -39,7 +39,7 @@ public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
|||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != 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 {
|
||||
handler.onError(error);
|
||||
}
|
||||
|
|
|
@ -21,10 +21,10 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
|
||||
private Claim claim;
|
||||
private String filePath;
|
||||
private View progressView;
|
||||
private ClaimResultHandler handler;
|
||||
private final Claim claim;
|
||||
private final String filePath;
|
||||
private final View progressView;
|
||||
private final ClaimResultHandler handler;
|
||||
private Exception error;
|
||||
public PublishClaimTask(Claim claim, String filePath, View progressView, ClaimResultHandler handler) {
|
||||
this.claim = claim;
|
||||
|
@ -73,6 +73,14 @@ public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
|
|||
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;
|
||||
try {
|
||||
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;
|
||||
|
||||
public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||
private String claimId;
|
||||
private int page;
|
||||
private int pageSize;
|
||||
private ClaimSearchResultHandler handler;
|
||||
private View progressView;
|
||||
private final ClaimSearchResultHandler handler;
|
||||
private final View progressView;
|
||||
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) {
|
||||
this.page = page;
|
||||
this.pageSize = pageSize;
|
||||
|
@ -38,8 +45,15 @@ public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
|
|||
List<Claim> claims = null;
|
||||
try {
|
||||
Map<String, Object> options = new HashMap<>();
|
||||
options.put("page", page);
|
||||
options.put("page_size", pageSize);
|
||||
if (!Helper.isNullOrEmpty(claimId)) {
|
||||
options.put("claim_id", claimId);
|
||||
}
|
||||
if (page > 0) {
|
||||
options.put("page", page);
|
||||
}
|
||||
if (pageSize > 0) {
|
||||
options.put("page_size", pageSize);
|
||||
}
|
||||
options.put("resolve", true);
|
||||
|
||||
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<>();
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
Claim claim = Claim.fromJSONObject(items.getJSONObject(i).getJSONObject("claim"));
|
||||
claims.add(claim);
|
||||
|
||||
Lbry.addClaimToCache(claim);
|
||||
if (!Helper.isNullOrEmpty(claim.getClaimId())) {
|
||||
claims.add(claim);
|
||||
Lbry.addClaimToCache(claim);
|
||||
}
|
||||
}
|
||||
} catch (ApiCallException | JSONException | ClassCastException ex) {
|
||||
error = ex;
|
||||
|
|
|
@ -13,10 +13,10 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||
private List<String> urls;
|
||||
private String connectionString;
|
||||
private ClaimListResultHandler handler;
|
||||
private View progressView;
|
||||
private final List<String> urls;
|
||||
private final String connectionString;
|
||||
private final ClaimListResultHandler handler;
|
||||
private final View progressView;
|
||||
private ApiCallException error;
|
||||
|
||||
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;
|
||||
|
||||
public class StreamRepostTask extends AsyncTask<Void, Void, Claim> {
|
||||
private String name;
|
||||
private BigDecimal bid;
|
||||
private String claimId;
|
||||
private String channelId;
|
||||
private View progressView;
|
||||
private ClaimResultHandler handler;
|
||||
private final String name;
|
||||
private final BigDecimal bid;
|
||||
private final String claimId;
|
||||
private final String channelId;
|
||||
private final View progressView;
|
||||
private final ClaimResultHandler handler;
|
||||
private Exception error;
|
||||
|
||||
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 io.lbry.browser.exceptions.ApiCallException;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
// Just run delete on the specified claim IDs (no need for a handler)
|
||||
public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private List<String> claimIds;
|
||||
private final List<String> claimIds;
|
||||
public BulkDeleteFilesTask(List<String> claimIds) {
|
||||
this.claimIds = claimIds;
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import io.lbry.browser.tasks.GenericTaskHandler;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class DeleteFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private String claimId;
|
||||
private final String claimId;
|
||||
private Exception error;
|
||||
private GenericTaskHandler handler;
|
||||
private final GenericTaskHandler handler;
|
||||
|
||||
public DeleteFileTask(String claimId, GenericTaskHandler handler) {
|
||||
this.claimId = claimId;
|
||||
|
|
|
@ -11,12 +11,12 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
||||
private String claimId;
|
||||
private final String claimId;
|
||||
private boolean downloads;
|
||||
private int page;
|
||||
private int pageSize;
|
||||
private FileListResultHandler handler;
|
||||
private View progressView;
|
||||
private final FileListResultHandler handler;
|
||||
private final View progressView;
|
||||
private ApiCallException error;
|
||||
|
||||
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;
|
||||
|
||||
public class GetFileTask extends AsyncTask<Void, Void, LbryFile> {
|
||||
private String uri;
|
||||
private boolean saveFile;
|
||||
private View progressView;
|
||||
private GetFileHandler handler;
|
||||
private final String uri;
|
||||
private final boolean saveFile;
|
||||
private final View progressView;
|
||||
private final GetFileHandler handler;
|
||||
private Exception error;
|
||||
|
||||
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.LbryioResponseException;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
|
||||
public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private Context context;
|
||||
private String channelClaimId;
|
||||
private Subscription subscription;
|
||||
private ChannelSubscribeHandler handler;
|
||||
private final Context context;
|
||||
private final String channelClaimId;
|
||||
private final Subscription subscription;
|
||||
private final ChannelSubscribeHandler handler;
|
||||
private Exception error;
|
||||
private boolean isUnsubscribing;
|
||||
private final boolean isUnsubscribing;
|
||||
|
||||
public ChannelSubscribeTask(Context context, String channelClaimId, Subscription subscription, boolean isUnsubscribing, ChannelSubscribeHandler handler) {
|
||||
this.context = context;
|
||||
|
@ -51,11 +50,11 @@ public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
|
|||
options.put("claim_id", channelClaimId);
|
||||
if (!isUnsubscribing) {
|
||||
options.put("channel_name", subscription.getChannelName());
|
||||
options.put("notifications_disabled", String.valueOf(subscription.isNotificationsDisabled()).toLowerCase());
|
||||
}
|
||||
|
||||
String action = isUnsubscribing ? "delete" : "new";
|
||||
Lbryio.call("subscription", action, options, context);
|
||||
|
||||
Object response = Lbryio.parseResponse(Lbryio.call("subscription", action, options, context));
|
||||
if (!isUnsubscribing) {
|
||||
Lbryio.addSubscription(subscription);
|
||||
} else {
|
||||
|
|
|
@ -4,6 +4,8 @@ import android.content.Context;
|
|||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
@ -14,23 +16,25 @@ import io.lbry.browser.R;
|
|||
import io.lbry.browser.exceptions.ApiCallException;
|
||||
import io.lbry.browser.exceptions.LbryioRequestException;
|
||||
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.Lbry;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
|
||||
public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
||||
|
||||
private Context context;
|
||||
private String type;
|
||||
private String claimCode;
|
||||
private View progressView;
|
||||
private final Context context;
|
||||
private final String type;
|
||||
private final String rewardCode;
|
||||
private final View progressView;
|
||||
private double amountClaimed;
|
||||
private ClaimRewardHandler handler;
|
||||
private final ClaimRewardHandler handler;
|
||||
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.claimCode = claimCode;
|
||||
this.rewardCode = rewardCode;
|
||||
this.progressView = progressView;
|
||||
this.context = context;
|
||||
this.handler = handler;
|
||||
|
@ -43,15 +47,27 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
|||
public String doInBackground(Void... params) {
|
||||
String message = null;
|
||||
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
|
||||
String address = (String) Lbry.genericApiCall(Lbry.METHOD_ADDRESS_UNUSED);
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put("reward_type", type);
|
||||
options.put("wallet_address", address);
|
||||
if (!Helper.isNullOrEmpty(claimCode)) {
|
||||
options.put("claim_code", claimCode);
|
||||
|
||||
if (!Helper.isNullOrEmpty(rewardCode)) {
|
||||
options.put("code", rewardCode);
|
||||
}
|
||||
if (!Helper.isNullOrEmpty(txid)) {
|
||||
options.put("transaction_id", txid);
|
||||
}
|
||||
|
||||
JSONObject reward = (JSONObject) Lbryio.parseResponse(
|
||||
Lbryio.call("reward", "claim", options, Helper.METHOD_POST, null));
|
||||
amountClaimed = Helper.getJSONDouble("reward_amount", 0, reward);
|
||||
|
@ -61,7 +77,7 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
|
|||
amountClaimed == 1 ? 1 : 2,
|
||||
new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed)) : "";
|
||||
message = Helper.getJSONString("reward_notification", defaultMessage, reward);
|
||||
} catch (ApiCallException | LbryioRequestException | LbryioResponseException ex) {
|
||||
} catch (ApiCallException | JSONException | LbryioRequestException | LbryioResponseException 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 {
|
||||
void onSuccess(double amountClaimed, String message);
|
||||
void onError(Exception error);
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
package io.lbry.browser.tasks.lbryinc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import io.lbry.browser.model.lbryinc.User;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
|
||||
public class FetchCurrentUserTask extends AsyncTask<Void, Void, User> {
|
||||
private final Context context;
|
||||
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;
|
||||
}
|
||||
protected User doInBackground(Void... params) {
|
||||
try {
|
||||
return Lbryio.fetchCurrentUser(null);
|
||||
return Lbryio.fetchCurrentUser(context);
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue