Compare commits

..

No commits in common. "master" and "dark-theme-fix" have entirely different histories.

306 changed files with 3474 additions and 26517 deletions

View file

@ -1 +0,0 @@

2
.gitignore vendored
View file

@ -60,10 +60,8 @@ buck-out/
# Other Files # Other Files
app/google-services.json app/google-services.json
app/twitter.properties
*.log *.log
.vagrant .vagrant
*.hprof *.hprof
app/build app/build
bin bin
app/debuglib

View file

@ -8,13 +8,10 @@ build apk:
stage: build stage: build
image: lbry/android-base:platform-28 image: lbry/android-base:platform-28
before_script: before_script:
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import - 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 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
- apt-get -y update && apt-get -y install build-essential ca-certificates curl git gpg-agent openjdk-8-jdk software-properties-common wget zipalign git-secret
- git secret reveal
- chmod u+x $CI_PROJECT_DIR/gradlew - chmod u+x $CI_PROJECT_DIR/gradlew
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1) - export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
artifacts: artifacts:
paths: paths:
- bin/browser-*-release__arm.apk - bin/browser-*-release__arm.apk
@ -22,7 +19,12 @@ build apk:
expire_in: 1 week expire_in: 1 week
script: script:
- export PATH=/usr/bin:$PATH - export PATH=/usr/bin:$PATH
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23 - 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
- chmod u+x ./release.sh - chmod u+x ./release.sh
- ./release.sh - ./release.sh
- cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null - cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null
@ -34,15 +36,10 @@ deploy build.lbry.io:
dependencies: dependencies:
- build apk - build apk
before_script: before_script:
- apt-get -y update && apt-get -y install apt-transport-https - apt-get -y update && apt-get -y install openjdk-8-jdk
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
- apt-get -y update && apt-get -y install openjdk-8-jdk git git-secret
- pip install awscli - pip install awscli
- chmod u+x $CI_PROJECT_DIR/gradlew - chmod u+x $CI_PROJECT_DIR/gradlew
- git secret reveal - export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk - export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk - export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
script: script:
@ -58,15 +55,10 @@ release apk:
dependencies: dependencies:
- build apk - build apk
before_script: before_script:
- apt-get -y update && apt-get -y install apt-transport-https - apt-get -y update && apt-get -y install openjdk-8-jdk
- echo "$PGP_PRIVATE_KEY" | gpg --batch --import
- echo 'deb https://gitsecret.jfrog.io/artifactory/git-secret-deb git-secret main' >> /etc/apt/sources.list
- wget -qO - 'https://gitsecret.jfrog.io/artifactory/api/gpg/key/public' | apt-key add -
- apt-get -y update && apt-get -y install openjdk-8-jdk git git-secret
- pip install awscli githubrelease - pip install awscli githubrelease
- git secret reveal
- chmod u+x $CI_PROJECT_DIR/gradlew - chmod u+x $CI_PROJECT_DIR/gradlew
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1) - export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk - export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk - export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
script: script:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,3 +1,2 @@
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65 lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
app/google-services.json:896a0bee8294a36d061f10fa926129d8a780528b34d0a2f03113400c4246d67c app/google-services.json:896a0bee8294a36d061f10fa926129d8a780528b34d0a2f03113400c4246d67c
app/twitter.properties:01212d70712f2041efb5c814bf30ecbf6f72e1ca5179c7647c4f8cbd995dd033

View file

@ -2,7 +2,7 @@
[![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master) [![pipeline status](https://ci.lbry.tech/lbry/lbry-android/badges/master/pipeline.svg)](https://ci.lbry.tech/lbry/lbry-android/commits/master)
[![GitHub license](https://img.shields.io/github/license/lbryio/lbry-android)](https://github.com/lbryio/lbry-android/blob/master/LICENSE) [![GitHub license](https://img.shields.io/github/license/lbryio/lbry-android)](https://github.com/lbryio/lbry-android/blob/master/LICENSE)
An Android browser and wallet for the [LBRY](https://lbry.com) network. 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.
<img src="https://spee.ch/@lbry:3f/android-08-homepage.gif" alt="LBRY Android GIF" width="384px" /> <img src="https://spee.ch/@lbry:3f/android-08-homepage.gif" alt="LBRY Android GIF" width="384px" />
@ -18,19 +18,7 @@ The minimum supported Android version is 5.0 Lollipop. There are two ways to ins
The app can be launched by opening **LBRY** from the device's app drawer or via the shortcut on the home screen if that was created upon installation. The app can be launched by opening **LBRY** from the device's app drawer or via the shortcut on the home screen if that was created upon installation.
## Running from Source ## Running from Source
Clone the repository and open the project in Android Studio. Android Studio will automatically run the initial build process. Please refer to https://github.com/lbryio/lbry-react-native/blob/master/README.md
Create file 'twitter.properties' in app/ folder with the following content:
```
twitterConsumerKey=XXXXXX
twitterConsumerSecret=XXXXXX
```
Copy the file 'google-services.sample.json' to 'google-services.json' in the app/ folder.
Click the Sync button and when process finishes, the Run button to launch the app on your simulator or connected debugging device after the build process is complete.
## Contributing ## Contributing
Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.io/faq/contributing
@ -39,7 +27,7 @@ Contributions to this project are welcome, encouraged, and compensated. For more
This project is MIT licensed. For the full license, see [LICENSE](LICENSE). This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
## Security ## Security
We take security seriously. Please contact security@lbry.com regarding any security issues. Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it. 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.
## Contact ## Contact
The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com) The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com)

View file

@ -1,10 +1,8 @@
import com.google.gms.googleservices.GoogleServicesPlugin
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion "29.0.2" buildToolsVersion "29.0.1"
flavorDimensions "default" flavorDimensions "default"
compileOptions { compileOptions {
@ -16,14 +14,10 @@ android {
applicationId "io.lbry.browser" applicationId "io.lbry.browser"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 1701 versionCode 1503
versionName "0.17.1" versionName "0.15.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
exclude 'META-INF/DEPENDENCIES'
exclude 'lib/x86_64/darwin/libscrypt.dylib'
} }
productFlavors { productFlavors {
@ -42,17 +36,7 @@ android {
} }
buildTypes { buildTypes {
debug {
Properties twitterProps = new Properties()
twitterProps.load(project.file('twitter.properties').newDataInputStream())
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
}
release { release {
Properties twitterProps = new Properties()
twitterProps.load(project.file('twitter.properties').newDataInputStream())
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
@ -65,49 +49,36 @@ task printVersionName {
} }
} }
configurations {
all {
exclude module: 'httpclient'
exclude module: 'commons-logging'
}
}
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' implementation 'androidx.appcompat:appcompat:1.2.0-rc01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.3.0-alpha01' implementation 'com.google.android.material:material:1.2.0-alpha06'
implementation "androidx.cardview:cardview:1.0.0" implementation "androidx.cardview:cardview:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.3.1' implementation 'androidx.navigation:navigation-fragment:2.2.2'
implementation 'androidx.navigation:navigation-ui:2.3.1' implementation 'androidx.navigation:navigation-ui:2.2.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.preference:preference:1.1.1' implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.webkit:webkit:1.4.0-rc01' implementation 'androidx.webkit:webkit:1.3.0-alpha02'
implementation 'androidx.camera:camera-core:1.0.0-beta03'
implementation 'androidx.camera:camera-camera2:1.0.0-beta03' implementation 'androidx.camera:camera-camera2:1.0.0-beta03'
implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03' implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03'
implementation 'androidx.camera:camera-view:1.0.0-alpha10' implementation 'androidx.camera:camera-view:1.0.0-alpha10'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.squareup.okhttp3:okhttp:4.4.1' implementation 'com.squareup.okhttp3:okhttp:4.4.1'
implementation 'com.google.firebase:firebase-analytics:18.0.0' implementation 'com.google.firebase:firebase-analytics:17.4.0'
implementation 'com.google.android.gms:play-services-base:17.5.0' implementation 'com.google.android.gms:play-services-base:17.2.1'
implementation 'com.google.firebase:firebase-messaging:21.0.0' implementation 'com.google.firebase:firebase-messaging:20.1.6'
implementation 'com.google.oauth-client:google-oauth-client:1.30.4'
implementation 'com.android.billingclient:billing:3.0.2'
implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.2' implementation 'com.google.android.exoplayer:exoplayer-core:2.11.4'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.2' implementation 'com.google.android.exoplayer:exoplayer-dash:2.11.4'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.2' implementation 'com.google.android.exoplayer:exoplayer-ui:2.11.4'
implementation 'com.google.android.exoplayer:extension-cast:2.12.2' implementation 'com.google.android.exoplayer:extension-cast:2.11.4'
implementation 'com.google.android.exoplayer:extension-mediasession:2.12.2' implementation 'com.google.android.exoplayer:extension-mediasession:2.11.4'
implementation 'com.google.android:flexbox:2.0.1' implementation 'com.google.android:flexbox:2.0.1'
@ -118,27 +89,17 @@ dependencies {
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS' implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS'
implementation 'commons-codec:commons-codec:1.15'
implementation 'org.bitcoinj:bitcoinj-tools:0.14.7'
implementation 'org.java-websocket:Java-WebSocket:1.5.1'
implementation ('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
implementation 'com.google.zxing:core:3.3.0'
compileOnly 'org.projectlombok:lombok:1.18.10' compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.3.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
__32bitImplementation 'io.lbry:lbrysdk32:0.102.0' __32bitImplementation files('libs/lbrysdk-0.74.0-release__arm.aar')
__64bitImplementation 'io.lbry:lbrysdk64:0.102.0' __64bitImplementation files('libs/lbrysdk-0.74.0-release__arm64.aar')
//__64bitImplementation(name: 'lbrysdk', ext: 'aar')
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
GoogleServicesPlugin.config.disableVersionCheck = true com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,12 +0,0 @@
package io.lbry.browser.utils;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@SmallTest
public class HelperTest {
}

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="io.lbry.browser" package="io.lbry.browser"
android:installLocation="auto"> android:installLocation="auto">
@ -11,10 +10,6 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
<application <application
android:allowBackup="true" android:allowBackup="true"
@ -55,38 +50,12 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="video/*" />
<data android:mimeType="image/*" />
<data android:mimeType="text/*" />
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="lbry" /> <data android:scheme="lbry" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="open.lbry.com"/>
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*#.*" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity> </activity>
<activity <activity
@ -101,11 +70,6 @@
android:theme="@style/AppTheme.NoActionBarTranslucent" android:theme="@style/AppTheme.NoActionBarTranslucent"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
<service <service
android:name="io.lbry.browser.LbrynetMessagingService" android:name="io.lbry.browser.LbrynetMessagingService"
android:exported="false"> android:exported="false">

View file

@ -10,31 +10,20 @@ import android.os.Bundle;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.text.HtmlCompat; import androidx.core.text.HtmlCompat;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import io.lbry.browser.exceptions.AuthTokenInvalidatedException;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryAnalytics; import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio; import io.lbry.browser.utils.Lbryio;
import io.lbry.lbrysdk.LbrynetService;
import io.lbry.lbrysdk.ServiceHelper;
import io.lbry.lbrysdk.Utils;
public class FirstRunActivity extends AppCompatActivity { public class FirstRunActivity extends AppCompatActivity {
private BroadcastReceiver sdkReceiver; private BroadcastReceiver sdkReadyReceiver;
private BroadcastReceiver authReceiver; private BroadcastReceiver authReceiver;
@Override @Override
@ -54,51 +43,21 @@ public class FirstRunActivity extends AppCompatActivity {
}); });
registerAuthReceiver(); registerAuthReceiver();
findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE); if (!Lbry.SDK_READY) {
IntentFilter filter = new IntentFilter(); findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE);
filter.addAction(MainActivity.ACTION_SDK_READY); IntentFilter filter = new IntentFilter();
filter.addAction(LbrynetService.ACTION_STOP_SERVICE); filter.addAction(MainActivity.ACTION_SDK_READY);
sdkReceiver = new BroadcastReceiver() { sdkReadyReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MainActivity.ACTION_SDK_READY.equals(action)) {
// authenticate after we receive the sdk ready event // authenticate after we receive the sdk ready event
authenticate(); authenticate();
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
finish();
if (MainActivity.instance != null) {
MainActivity.instance.finish();
}
} }
} };
}; registerReceiver(sdkReadyReceiver, filter);
registerReceiver(sdkReceiver, filter); } else {
authenticate();
CheckInstallIdTask task = new CheckInstallIdTask(this, new CheckInstallIdTask.InstallIdHandler() { }
@Override
public void onInstallIdChecked(boolean result) {
// start the sdk from FirstRun
boolean serviceRunning = MainActivity.isServiceRunning(MainActivity.instance, LbrynetService.class);
if (!serviceRunning) {
Lbry.SDK_READY = false;
ServiceHelper.start(MainActivity.instance, "", LbrynetService.class, "lbrynetservice");
}
if (result) {
// install_id generated and validated, authenticate now
authenticate();
return;
}
// we weren't able to generate the install_id ourselves, depend on the sdk for that
if (Lbry.SDK_READY) {
authenticate();
return;
}
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
public void onResume() { public void onResume() {
@ -138,8 +97,7 @@ public class FirstRunActivity extends AppCompatActivity {
} }
private void handleAuthenticationFailed() { private void handleAuthenticationFailed() {
findViewById(R.id.welcome_progress_bar).setVisibility(View.GONE); Toast.makeText(this, "Authentication failed.", Toast.LENGTH_LONG).show();
((TextView) findViewById(R.id.welcome_wait_text)).setText(R.string.startup_failed);
} }
private void authenticate() { private void authenticate() {
@ -163,89 +121,17 @@ public class FirstRunActivity extends AppCompatActivity {
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Helper.unregisterReceiver(authReceiver, this); Helper.unregisterReceiver(authReceiver, this);
Helper.unregisterReceiver(sdkReceiver, this); Helper.unregisterReceiver(sdkReadyReceiver, this);
super.onDestroy(); super.onDestroy();
} }
private void generateIdAndAuthenticate() {
}
private static class CheckInstallIdTask extends AsyncTask<Void, Void, Boolean> {
private final Context context;
private final InstallIdHandler handler;
public CheckInstallIdTask(Context context, InstallIdHandler handler) {
this.context = context;
this.handler = handler;
}
protected Boolean doInBackground(Void... params) {
// Load the installation id from the file system
String lbrynetDir = String.format("%s/%s", Utils.getAppInternalStorageDir(context), "lbrynet");
File dir = new File(lbrynetDir);
boolean dirExists = dir.isDirectory();
if (!dirExists) {
dirExists = dir.mkdirs();
}
if (!dirExists) {
return false;
}
String installIdPath = String.format("%s/install_id", lbrynetDir);
File file = new File(installIdPath);
String installId = null;
if (!file.exists()) {
// generate the install_id
installId = Lbry.generateId();
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.write(installId);
} catch (IOException ex) {
return false;
} finally {
Helper.closeCloseable(writer);
}
} else {
// read the installation id from the file
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(installIdPath)));
installId = reader.readLine();
} catch (IOException ex) {
return false;
} finally {
Helper.closeCloseable(reader);
}
}
if (!Helper.isNullOrEmpty(installId)) {
Lbry.INSTALLATION_ID = installId;
}
return !Helper.isNullOrEmpty(installId);
}
protected void onPostExecute(Boolean result) {
if (handler != null) {
handler.onInstallIdChecked(result);
}
}
public interface InstallIdHandler {
void onInstallIdChecked(boolean result);
}
}
private static class AuthenticateTask extends AsyncTask<Void, Void, Void> { private static class AuthenticateTask extends AsyncTask<Void, Void, Void> {
private final Context context; private Context context;
public AuthenticateTask(Context context) { public AuthenticateTask(Context context) {
this.context = context; this.context = context;
} }
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
try { Lbryio.authenticate(context);
Lbryio.authenticate(context);
} catch (AuthTokenInvalidatedException ex) {
// pass
}
return null; return null;
} }
} }

View file

@ -6,7 +6,6 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.media.RingtoneManager; import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
@ -21,22 +20,19 @@ import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage; import com.google.firebase.messaging.RemoteMessage;
import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.model.lbryinc.LbryNotification;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryAnalytics; import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.lbrysdk.LbrynetService;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class LbrynetMessagingService extends FirebaseMessagingService { public class LbrynetMessagingService extends FirebaseMessagingService {
public static final String ACTION_NOTIFICATION_RECEIVED = "io.lbry.browser.Broadcast.NotificationReceived";
private static final String TAG = "LbrynetMessagingService"; private static final String TAG = "LbrynetMessagingService";
private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL"; private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
private static final String TYPE_COMMENT = "comment";
private static final String TYPE_SUBSCRIPTION = "subscription"; private static final String TYPE_SUBSCRIPTION = "subscription";
private static final String TYPE_REWARD = "reward"; private static final String TYPE_REWARD = "reward";
private static final String TYPE_INTERESTS = "interests"; private static final String TYPE_INTERESTS = "interests";
@ -56,9 +52,12 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
String title = payload.get("title"); String title = payload.get("title");
String body = payload.get("body"); String body = payload.get("body");
String name = payload.get("name"); // notification name String name = payload.get("name"); // notification name
String hash = payload.get("hash"); // comment hash String contentTitle = payload.get("content_title");
String channelUrl = payload.get("channel_url");
//String publishTime = payload.get("publish_time");
String publishTime = null;
if (type != null && getEnabledTypes().contains(type) && body != null && body.trim().length() > 0) { if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) {
// only log the receive event for valid notifications received // only log the receive event for valid notifications received
if (firebaseAnalytics != null) { if (firebaseAnalytics != null) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
@ -66,41 +65,14 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle); firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
} }
if (!Helper.isNullOrEmpty(hash)) { sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime);
url = String.format("%s?comment_hash=%s", url, hash);
}
sendNotification(title, body, type, url, name);
}
// persist the notification data
try {
DatabaseHelper helper = DatabaseHelper.getInstance();
SQLiteDatabase db = helper.getWritableDatabase();
LbryNotification lnotification = new LbryNotification();
lnotification.setTitle(title);
lnotification.setDescription(body);
lnotification.setTargetUrl(url);
lnotification.setTimestamp(new Date());
DatabaseHelper.createOrUpdateNotification(lnotification, db);
// send a broadcast
Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED);
intent.putExtra("title", title);
intent.putExtra("body", body);
intent.putExtra("url", url);
intent.putExtra("timestamp", lnotification.getTimestamp().getTime());
sendBroadcast(intent);
} catch (Exception ex) {
// don't fail if any error occurs while saving a notification
Log.e(TAG, "could not save notification", ex);
} }
} }
} }
@Override @Override
public void onNewToken(String token) { public void onNewToken(String token) {
//Log.d(TAG, "Refreshed token: " + token); Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or // If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the // manage this apps subscriptions on the server side, send the
@ -125,7 +97,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
* *
* @param messageBody FCM message body received. * @param messageBody FCM message body received.
*/ */
private void sendNotification(String title, String messageBody, String type, String url, String name) { private void sendNotification(String title, String messageBody, String type, String url, String name,
String contentTitle, String channelUrl, String publishTime) {
//Intent intent = new Intent(this, MainActivity.class); //Intent intent = new Intent(this, MainActivity.class);
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (url == null) { if (url == null) {
@ -170,9 +143,6 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
List<String> enabledTypes = new ArrayList<String>(); List<String> enabledTypes = new ArrayList<String>();
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_COMMENTS, true)) {
enabledTypes.add(TYPE_COMMENT);
}
if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) { if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) {
enabledTypes.add(TYPE_SUBSCRIPTION); enabledTypes.add(TYPE_SUBSCRIPTION);
} }

File diff suppressed because it is too large Load diff

View file

@ -1,47 +1,25 @@
package io.lbry.browser; package io.lbry.browser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color; import android.graphics.Color;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.widget.ViewPager2; import androidx.viewpager2.widget.ViewPager2;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import io.lbry.browser.adapter.VerificationPagerAdapter; import io.lbry.browser.adapter.VerificationPagerAdapter;
import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.listener.SignInListener; import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.listener.WalletSyncListener; import io.lbry.browser.listener.WalletSyncListener;
import io.lbry.browser.model.lbryinc.RewardVerified;
import io.lbry.browser.model.lbryinc.User; import io.lbry.browser.model.lbryinc.User;
import io.lbry.browser.tasks.RewardVerifiedHandler;
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask; import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryAnalytics; import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio; import io.lbry.browser.utils.Lbryio;
import io.lbry.lbrysdk.LbrynetService;
public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener { public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener {
@ -49,66 +27,14 @@ public class VerificationActivity extends FragmentActivity implements SignInList
public static final int VERIFICATION_FLOW_REWARDS = 2; public static final int VERIFICATION_FLOW_REWARDS = 2;
public static final int VERIFICATION_FLOW_WALLET = 3; public static final int VERIFICATION_FLOW_WALLET = 3;
private List<SdkStatusListener> sdkStatusListeners;
private BillingClient billingClient;
private BroadcastReceiver sdkReceiver;
private String email; private String email;
private boolean signedIn; private boolean signedIn;
private int flow; private int flow;
private final PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
int responseCode = billingResult.getResponseCode();
if (responseCode == BillingClient.BillingResponseCode.OK && purchases != null)
{
for (Purchase purchase : purchases) {
if (MainActivity.SKU_SKIP.equalsIgnoreCase(purchase.getSku())) {
showLoading();
MainActivity.handleBillingPurchase(
purchase,
billingClient,
VerificationActivity.this, null, new RewardVerifiedHandler() {
@Override
public void onSuccess(RewardVerified rewardVerified) {
if (Lbryio.currentUser != null) {
Lbryio.currentUser.setRewardApproved(rewardVerified.isRewardApproved());
}
if (!rewardVerified.isRewardApproved()) {
// show pending purchase message (possible slow card tx)
Snackbar.make(findViewById(R.id.verification_pager), R.string.purchase_request_pending, Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
}
setResult(RESULT_OK);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}
@Override
public void onError(Exception error) {
showFetchUserError(getString(R.string.purchase_request_failed_error));
hideLoading();
}
});
}
}
}
}
};
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
sdkStatusListeners = new ArrayList<>();
signedIn = Lbryio.isSignedIn(); signedIn = Lbryio.isSignedIn();
Intent intent = getIntent(); Intent intent = getIntent();
if (intent != null) { if (intent != null) {
@ -128,32 +54,6 @@ public class VerificationActivity extends FragmentActivity implements SignInList
return; return;
} }
IntentFilter filter = new IntentFilter();
filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
filter.addAction(MainActivity.ACTION_SDK_READY);
sdkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MainActivity.ACTION_SDK_READY.equals(action)) {
for (SdkStatusListener listener : sdkStatusListeners) {
if (listener != null) {
listener.onSdkReady();
}
}
} else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) {
finish();
}
}
};
registerReceiver(sdkReceiver, filter);
billingClient = BillingClient.newBuilder(this)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
establishBillingClientConnection();
setContentView(R.layout.activity_verification); setContentView(R.layout.activity_verification);
ViewPager2 viewPager = findViewById(R.id.verification_pager); ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setUserInputEnabled(false); viewPager.setUserInputEnabled(false);
@ -170,24 +70,6 @@ public class VerificationActivity extends FragmentActivity implements SignInList
}); });
} }
private void establishBillingClientConnection() {
if (billingClient != null) {
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// no need to do anything here. purchases are always checked server-side
}
}
@Override
public void onBillingServiceDisconnected() {
establishBillingClientConnection();
}
});
}
}
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
LbryAnalytics.setCurrentScreen(this, "Verification", "Verification"); LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
@ -203,17 +85,14 @@ public class VerificationActivity extends FragmentActivity implements SignInList
flowHandled = true; flowHandled = true;
} else if (flow == VERIFICATION_FLOW_REWARDS) { } else if (flow == VERIFICATION_FLOW_REWARDS) {
User user = Lbryio.currentUser; User user = Lbryio.currentUser;
// disable phone verification for now
if (!user.isIdentityVerified()) { if (!user.isIdentityVerified()) {
// phone number verification required // phone number verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false); viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
flowHandled = true; flowHandled = true;
} else { } else if (!user.isRewardApproved()) {
if (!user.isRewardApproved()) { // manual verification required
// manual verification required viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false); flowHandled = true;
flowHandled = true;
}
} }
} }
@ -226,11 +105,6 @@ public class VerificationActivity extends FragmentActivity implements SignInList
} }
} }
public void showPhoneVerification() {
ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
}
public void showLoading() { public void showLoading() {
findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE); findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE);
findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE); findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE);
@ -244,12 +118,8 @@ public class VerificationActivity extends FragmentActivity implements SignInList
@Override @Override
public void onBackPressed() { public void onBackPressed() {
ViewPager2 viewPager = findViewById(R.id.verification_pager); // ignore back press
return;
if (viewPager.getCurrentItem() != VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL)
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL);
else
super.onBackPressed();
} }
public void onEmailAdded(String email) { public void onEmailAdded(String email) {
@ -278,7 +148,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
// only sign in required, don't do anything else // only sign in required, don't do anything else
showLoading(); showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() { FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override @Override
public void onSuccess(User user) { public void onSuccess(User user) {
Lbryio.currentUser = user; Lbryio.currentUser = user;
@ -288,7 +158,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
@Override @Override
public void onError(Exception error) { public void onError(Exception error) {
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error)); showFetchUserError(error.getMessage());
hideLoading(); hideLoading();
} }
}); });
@ -296,7 +166,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
} else { } else {
// change pager view depending on flow // change pager view depending on flow
showLoading(); showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() { FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override @Override
public void onSuccess(User user) { public void onSuccess(User user) {
hideLoading(); hideLoading();
@ -309,15 +179,13 @@ public class VerificationActivity extends FragmentActivity implements SignInList
if (!user.isIdentityVerified()) { if (!user.isIdentityVerified()) {
// phone number verification required // phone number verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false); viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
} else if (!user.isRewardApproved()) {
// manual verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
} else { } else {
if (!user.isRewardApproved()) { // fully verified
// manual verification required setResult(RESULT_OK);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false); finish();
} else {
// fully verified
setResult(RESULT_OK);
finish();
}
} }
} else if (flow == VERIFICATION_FLOW_WALLET) { } else if (flow == VERIFICATION_FLOW_WALLET) {
// for wallet sync, if password unlock is required, show password entry page // for wallet sync, if password unlock is required, show password entry page
@ -326,7 +194,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
} }
@Override @Override
public void onError(Exception error) { public void onError(Exception error) {
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error)); showFetchUserError(error.getMessage());
hideLoading(); hideLoading();
} }
}); });
@ -342,7 +210,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
@Override @Override
public void onPhoneVerified() { public void onPhoneVerified() {
showLoading(); showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(this, new FetchCurrentUserTask.FetchUserTaskHandler() { FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override @Override
public void onSuccess(User user) { public void onSuccess(User user) {
Lbryio.currentUser = user; Lbryio.currentUser = user;
@ -355,7 +223,6 @@ public class VerificationActivity extends FragmentActivity implements SignInList
return; return;
} }
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
// show manual verification page if the user is still not reward approved // show manual verification page if the user is still not reward approved
ViewPager2 viewPager = findViewById(R.id.verification_pager); ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false); viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
@ -364,7 +231,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
@Override @Override
public void onError(Exception error) { public void onError(Exception error) {
showFetchUserError(error != null ? error.getMessage() : getString(R.string.fetch_current_user_error)); showFetchUserError(error.getMessage());
hideLoading(); hideLoading();
} }
}); });
@ -402,68 +269,4 @@ public class VerificationActivity extends FragmentActivity implements SignInList
public void onWalletSyncFailed(Exception error) { public void onWalletSyncFailed(Exception error) {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE); findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
} }
@Override
public void onSkipQueueAction() {
if (billingClient != null) {
List<String> skuList = new ArrayList<>();
skuList.add(MainActivity.SKU_SKIP);
SkuDetailsParams detailsParams = SkuDetailsParams.newBuilder().
setType(BillingClient.SkuType.INAPP).
setSkusList(skuList).build();
billingClient.querySkuDetailsAsync(detailsParams, new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
if (list != null && list.size() > 0) {
// we only queried one product, so it should be the first item in the list
SkuDetails skuDetails = list.get(0);
// launch the billing flow for skip queue
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().
setSkuDetails(skuDetails).build();
billingClient.launchBillingFlow(VerificationActivity.this, billingFlowParams);
}
}
});
}
}
@Override
public void onTwitterVerified() {
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
setResult(RESULT_OK);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}
@Override
public void onManualProgress(boolean progress) {
if (progress) {
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
} else {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
}
}
@Override
public void onDestroy() {
Helper.unregisterReceiver(sdkReceiver, this);
super.onDestroy();
}
public void addSdkStatusListener(SdkStatusListener listener) {
if (!sdkStatusListeners.contains(listener)) {
sdkStatusListeners.add(listener);
}
}
public void removeSdkStatusListener(SdkStatusListener listener) {
sdkStatusListeners.remove(listener);
}
} }

View file

@ -23,7 +23,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilterListAdapter.ViewHolder> { public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilterListAdapter.ViewHolder> {
private final Context context; private Context context;
private List<Claim> items; private List<Claim> items;
@Getter @Getter
@Setter @Setter
@ -42,12 +42,12 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View mediaContainer; protected View mediaContainer;
protected final View alphaContainer; protected View alphaContainer;
protected final View allView; protected View allView;
protected final ImageView thumbnailView; protected ImageView thumbnailView;
protected final TextView alphaView; protected TextView alphaView;
protected final TextView titleView; protected TextView titleView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
mediaContainer = v.findViewById(R.id.channel_filter_media_container); mediaContainer = v.findViewById(R.id.channel_filter_media_container);
@ -95,13 +95,13 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
vh.allView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE); vh.allView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE);
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle()); vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
String thumbnailUrl = claim.getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85); String thumbnailUrl = claim.getThumbnailUrl();
if (!Helper.isNullOrEmpty(thumbnailUrl) && context != null) { if (!Helper.isNullOrEmpty(thumbnailUrl) && context != null) {
Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView); Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
} }
vh.alphaContainer.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE); vh.alphaContainer.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
vh.thumbnailView.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.GONE : View.VISIBLE); vh.thumbnailView.setVisibility(claim.isPlaceholder() || Helper.isNullOrEmpty(thumbnailUrl) ? View.GONE : View.VISIBLE);
vh.alphaView.setText(claim.isPlaceholder() ? null : claim.getName() != null ? claim.getName().substring(1, 2).toUpperCase() : ""); vh.alphaView.setText(claim.isPlaceholder() ? null : claim.getName() != null ? claim.getName().substring(1, 2) : "");
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId()); int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
Helper.setIconViewBackgroundColor(vh.alphaContainer, bgColor, claim.isPlaceholder(), context); Helper.setIconViewBackgroundColor(vh.alphaContainer, bgColor, claim.isPlaceholder(), context);

View file

@ -8,6 +8,7 @@ import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -21,6 +22,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R; import io.lbry.browser.R;
import io.lbry.browser.listener.SelectionModeListener; import io.lbry.browser.listener.SelectionModeListener;
import io.lbry.browser.model.Claim; import io.lbry.browser.model.Claim;
@ -36,18 +38,18 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
private static final int VIEW_TYPE_CHANNEL = 2; private static final int VIEW_TYPE_CHANNEL = 2;
private static final int VIEW_TYPE_FEATURED = 3; // featured search result private static final int VIEW_TYPE_FEATURED = 3; // featured search result
private final Map<String, Claim> quickClaimIdMap; private Map<String, Claim> quickClaimIdMap;
private final Map<String, Claim> quickClaimUrlMap; private Map<String, Claim> quickClaimUrlMap;
private final Map<String, Boolean> notFoundClaimIdMap; private Map<String, Boolean> notFoundClaimIdMap;
private final Map<String, Boolean> notFoundClaimUrlMap; private Map<String, Boolean> notFoundClaimUrlMap;
@Setter @Setter
private boolean hideFee; private boolean hideFee;
@Setter @Setter
private boolean canEnterSelectionMode; private boolean canEnterSelectionMode;
private final Context context; private Context context;
private List<Claim> items; private List<Claim> items;
private final List<Claim> selectedItems; private List<Claim> selectedItems;
@Setter @Setter
private ClaimListItemListener listener; private ClaimListItemListener listener;
@Getter @Getter
@ -59,13 +61,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
public ClaimListAdapter(List<Claim> items, Context context) { public ClaimListAdapter(List<Claim> items, Context context) {
this.context = context; this.context = context;
this.items = new ArrayList<>(); this.items = new ArrayList<>(items);
for (Claim item : items) {
if (item != null) {
this.items.add(item);
}
}
this.selectedItems = new ArrayList<>(); this.selectedItems = new ArrayList<>();
quickClaimIdMap = new HashMap<>(); quickClaimIdMap = new HashMap<>();
quickClaimUrlMap = new HashMap<>(); quickClaimUrlMap = new HashMap<>();
@ -144,7 +140,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
public void addItems(List<Claim> claims) { public void addItems(List<Claim> claims) {
for (Claim claim : claims) { for (Claim claim : claims) {
if (claim != null && !items.contains(claim)) { if (!items.contains(claim)) {
items.add(claim); items.add(claim);
} }
} }
@ -154,12 +150,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void setItems(List<Claim> claims) { public void setItems(List<Claim> claims) {
items = new ArrayList<>(); items = new ArrayList<>(claims);
for (Claim claim : claims) {
if (claim != null) {
items.add(claim);
}
}
notifyDataSetChanged(); notifyDataSetChanged();
} }
@ -175,27 +166,23 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View feeContainer; protected View feeContainer;
protected final TextView feeView; protected TextView feeView;
protected final ImageView thumbnailView; protected ImageView thumbnailView;
protected final View noThumbnailView; protected View noThumbnailView;
protected final TextView alphaView; protected TextView alphaView;
protected final TextView vanityUrlView; protected TextView vanityUrlView;
protected final TextView durationView; protected TextView durationView;
protected final TextView titleView; protected TextView titleView;
protected final TextView publisherView; protected TextView publisherView;
protected final TextView publishTimeView; protected TextView publishTimeView;
protected final TextView pendingTextView; protected TextView pendingTextView;
protected final View repostInfoView; protected View repostInfoView;
protected final TextView repostChannelView; protected TextView repostChannelView;
protected final View selectedOverlayView; protected View selectedOverlayView;
protected final TextView fileSizeView; protected TextView fileSizeView;
protected final ProgressBar downloadProgressView; protected ProgressBar downloadProgressView;
protected final TextView deviceView; protected TextView deviceView;
protected final View loadingImagePlaceholder;
protected final View loadingTextPlaceholder1;
protected final View loadingTextPlaceholder2;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
feeContainer = v.findViewById(R.id.claim_fee_container); feeContainer = v.findViewById(R.id.claim_fee_container);
@ -215,10 +202,6 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
fileSizeView = v.findViewById(R.id.claim_file_size); fileSizeView = v.findViewById(R.id.claim_file_size);
downloadProgressView = v.findViewById(R.id.claim_download_progress); downloadProgressView = v.findViewById(R.id.claim_download_progress);
deviceView = v.findViewById(R.id.claim_view_device); deviceView = v.findViewById(R.id.claim_view_device);
loadingImagePlaceholder = v.findViewById(R.id.claim_thumbnail_placeholder);
loadingTextPlaceholder1 = v.findViewById(R.id.claim_text_loading_placeholder_1);
loadingTextPlaceholder2 = v.findViewById(R.id.claim_text_loading_placeholder_2);
} }
} }
@ -315,27 +298,29 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
return new ClaimListAdapter.ViewHolder(v); return new ClaimListAdapter.ViewHolder(v);
} }
public int getScaledValue(int value) {
return (int) (value * scale + 0.5f);
}
@Override @Override
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) { public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
int type = getItemViewType(position); int type = getItemViewType(position);
int paddingTop = position == 0 ? 16 : 8; int paddingTop = position == 0 ? 16 : 8;
int paddingBottom = position == getItemCount() - 1 ? 16 : 8; int paddingBottom = position == getItemCount() - 1 ? 16 : 8;
int paddingTopScaled = Helper.getScaledValue(paddingTop, scale); int paddingTopScaled = getScaledValue(paddingTop);
int paddingBottomScaled = Helper.getScaledValue(paddingBottom, scale); int paddingBottomScaled = getScaledValue(paddingBottom);
vh.itemView.setPadding(vh.itemView.getPaddingStart(), paddingTopScaled, vh.itemView.getPaddingEnd(), paddingBottomScaled); vh.itemView.setPadding(vh.itemView.getPaddingLeft(), paddingTopScaled, vh.itemView.getPaddingRight(), paddingBottomScaled);
Claim original = items.get(position); Claim original = items.get(position);
boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType()); boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType());
final Claim item = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType()) ? final Claim item = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType()) ? original.getRepostedClaim() : original;
(original.getRepostedClaim() != null ? original.getRepostedClaim() : original): original;
Claim.GenericMetadata metadata = item.getValue(); Claim.GenericMetadata metadata = item.getValue();
Claim signingChannel = item.getSigningChannel(); Claim signingChannel = item.getSigningChannel();
Claim.StreamMetadata streamMetadata = null; Claim.StreamMetadata streamMetadata = null;
if (metadata instanceof Claim.StreamMetadata) { if (metadata instanceof Claim.StreamMetadata) {
streamMetadata = (Claim.StreamMetadata) metadata; streamMetadata = (Claim.StreamMetadata) metadata;
} }
String thumbnailUrl = item.getThumbnailUrl();
String thumbnailUrl = item.getThumbnailUrl(vh.thumbnailView.getLayoutParams().width, vh.thumbnailView.getLayoutParams().height, 85);
long publishTime = (streamMetadata != null && streamMetadata.getReleaseTime() > 0) ? streamMetadata.getReleaseTime() * 1000 : item.getTimestamp() * 1000; long publishTime = (streamMetadata != null && streamMetadata.getReleaseTime() > 0) ? streamMetadata.getReleaseTime() * 1000 : item.getTimestamp() * 1000;
int bgColor = Helper.generateRandomColorForValue(item.getClaimId()); int bgColor = Helper.generateRandomColorForValue(item.getClaimId());
if (bgColor == 0) { if (bgColor == 0) {
@ -343,17 +328,14 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
} }
boolean isPending = item.getConfirmations() == 0; boolean isPending = item.getConfirmations() == 0;
boolean isSelected = isClaimSelected(original); boolean isSelected = isClaimSelected(item);
vh.itemView.setSelected(isSelected); vh.itemView.setSelected(isSelected);
vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE); vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE);
vh.itemView.setOnClickListener(new View.OnClickListener() { vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (isPending) { if (isPending) {
Snackbar snackbar = Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG); Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG).show();
TextView snackbarText = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
snackbarText.setMaxLines(5);
snackbar.show();
return; return;
} }
@ -374,10 +356,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
} }
if (isPending) { if (isPending) {
Snackbar snackbar = Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG); Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG).show();
TextView snackbarText = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
snackbarText.setMaxLines(5);
snackbar.show();
return false; return false;
} }
@ -402,9 +381,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
}); });
vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE); vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE);
vh.pendingTextView.setVisibility(isPending && !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE); vh.pendingTextView.setVisibility(isPending ? View.VISIBLE : View.GONE);
vh.repostInfoView.setVisibility(isRepost && type != VIEW_TYPE_FEATURED ? View.VISIBLE : View.GONE); vh.repostInfoView.setVisibility(isRepost ? View.VISIBLE : View.GONE);
vh.repostChannelView.setText(isRepost && original.getSigningChannel() != null ? original.getSigningChannel().getName() : null); vh.repostChannelView.setText(isRepost ? original.getSigningChannel().getName() : null);
vh.repostChannelView.setOnClickListener(new View.OnClickListener() { vh.repostChannelView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
@ -425,13 +404,6 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE); vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context); Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
Helper.setViewVisibility(vh.loadingImagePlaceholder, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.loadingTextPlaceholder1, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.loadingTextPlaceholder2, item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.titleView, !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.publisherView, !item.isLoadingPlaceholder() ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(vh.publishTimeView, !item.isLoadingPlaceholder() && !isPending ? View.VISIBLE : View.GONE);
if (type == VIEW_TYPE_FEATURED && item.isUnresolved()) { if (type == VIEW_TYPE_FEATURED && item.isUnresolved()) {
vh.durationView.setVisibility(View.GONE); vh.durationView.setVisibility(View.GONE);
vh.titleView.setText("Nothing here. Publish something!"); vh.titleView.setText("Nothing here. Publish something!");
@ -441,7 +413,6 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
long duration = item.getDuration(); long duration = item.getDuration();
if (!Helper.isNullOrEmpty(thumbnailUrl)) { if (!Helper.isNullOrEmpty(thumbnailUrl)) {
Glide.with(context.getApplicationContext()). Glide.with(context.getApplicationContext()).
asBitmap().
load(thumbnailUrl). load(thumbnailUrl).
centerCrop(). centerCrop().
placeholder(R.drawable.bg_thumbnail_placeholder). placeholder(R.drawable.bg_thumbnail_placeholder).

View file

@ -1,228 +0,0 @@
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);
}
}

View file

@ -23,8 +23,8 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
private static final int VIEW_TYPE_HEADER = 1; private static final int VIEW_TYPE_HEADER = 1;
private static final int VIEW_TYPE_CONTENT = 2; private static final int VIEW_TYPE_CONTENT = 2;
private final Context context; private Context context;
private final List<EditorsChoiceItem> items; private List<EditorsChoiceItem> items;
@Setter @Setter
private EditorsChoiceItemListener listener; private EditorsChoiceItemListener listener;
@ -48,11 +48,11 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final ImageView thumbnailView; protected ImageView thumbnailView;
protected final TextView descriptionView; protected TextView descriptionView;
protected final TextView headerView; protected TextView headerView;
protected final TextView titleView; protected TextView titleView;
protected final View cardView; protected View cardView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
@ -95,7 +95,6 @@ public class EditorsChoiceItemAdapter extends RecyclerView.Adapter<EditorsChoice
vh.descriptionView.setText(item.getDescription()); vh.descriptionView.setText(item.getDescription());
if (!Helper.isNullOrEmpty(item.getThumbnailUrl())) { if (!Helper.isNullOrEmpty(item.getThumbnailUrl())) {
Glide.with(context.getApplicationContext()). Glide.with(context.getApplicationContext()).
asBitmap().
load(item.getThumbnailUrl()). load(item.getThumbnailUrl()).
centerCrop(). centerCrop().
placeholder(R.drawable.bg_thumbnail_placeholder). placeholder(R.drawable.bg_thumbnail_placeholder).

View file

@ -21,8 +21,8 @@ import io.lbry.browser.utils.Helper;
import lombok.Setter; import lombok.Setter;
public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> { public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> {
private final Context context; private Context context;
private final List<GalleryItem> items; private List<GalleryItem> items;
@Setter @Setter
private GalleryItemClickListener listener; private GalleryItemClickListener listener;
@ -32,8 +32,8 @@ public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final ImageView thumbnailView; protected ImageView thumbnailView;
protected final TextView durationView; protected TextView durationView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
thumbnailView = v.findViewById(R.id.gallery_item_thumbnail); thumbnailView = v.findViewById(R.id.gallery_item_thumbnail);
@ -96,8 +96,8 @@ public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.
public static class GalleryGridItemDecoration extends RecyclerView.ItemDecoration { public static class GalleryGridItemDecoration extends RecyclerView.ItemDecoration {
private final int spanCount; private int spanCount;
private final int spacing; private int spacing;
public GalleryGridItemDecoration(int spanCount, int spacing) { public GalleryGridItemDecoration(int spanCount, int spacing) {
this.spanCount = spanCount; this.spanCount = spanCount;

View file

@ -1,14 +1,15 @@
package io.lbry.browser.adapter; package io.lbry.browser.adapter;
import android.content.Context; import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.SpinnerAdapter;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import io.lbry.browser.R; import io.lbry.browser.R;
@ -16,9 +17,9 @@ import io.lbry.browser.model.Claim;
public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> { public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
private final List<Claim> channels; private List<Claim> channels;
private final int layoutResourceId; private int layoutResourceId;
private final LayoutInflater inflater; private LayoutInflater inflater;
public InlineChannelSpinnerAdapter(Context context, int resource, List<Claim> channels) { public InlineChannelSpinnerAdapter(Context context, int resource, List<Claim> channels) {
super(context, resource, 0, channels); super(context, resource, 0, channels);
@ -39,30 +40,11 @@ public class InlineChannelSpinnerAdapter extends ArrayAdapter<Claim> {
channels.add(1, anonymous); channels.add(1, anonymous);
} }
} }
public void addAnonymousPlaceholder() {
Claim anonymous = new Claim();
anonymous.setPlaceholderAnonymous(true);
insert(anonymous, 0);
channels.add(0, anonymous);
}
public void addAll(Collection<? extends Claim> collection) {
for (Claim claim : collection) {
if (!channels.contains(claim)) {
channels.add(claim);
}
}
super.addAll(collection);
}
public void clear() {
channels.clear();
super.clear();
}
public int getItemPosition(Claim item) { public int getItemPosition(Claim item) {
for (int i = 0; i < channels.size(); i++) { for (int i = 0; i < channels.size(); i++) {
Claim channel = channels.get(i); Claim channel = channels.get(i);
if (item.getClaimId() != null && item.getClaimId().equalsIgnoreCase(channel.getClaimId())) { if (item.getClaimId().equalsIgnoreCase(channel.getClaimId())) {
return i; return i;
} }
} }

View file

@ -1,7 +1,9 @@
package io.lbry.browser.adapter; package io.lbry.browser.adapter;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.net.Uri;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -9,16 +11,21 @@ import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.lbry.browser.R; import io.lbry.browser.R;
import io.lbry.browser.model.lbryinc.Invitee; import io.lbry.browser.model.lbryinc.Invitee;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri;
import lombok.Setter;
public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.ViewHolder> { public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.ViewHolder> {
private final Context context; private Context context;
private final List<Invitee> items; private List<Invitee> items;
public InviteeListAdapter(List<Invitee> invitees, Context context) { public InviteeListAdapter(List<Invitee> invitees, Context context) {
this.context = context; this.context = context;
@ -73,8 +80,8 @@ public class InviteeListAdapter extends RecyclerView.Adapter<InviteeListAdapter.
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final TextView emailView; protected TextView emailView;
protected final TextView rewardView; protected TextView rewardView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);

View file

@ -10,12 +10,13 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import io.lbry.browser.R; import io.lbry.browser.R;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.Language; import io.lbry.browser.model.Language;
import io.lbry.browser.utils.Predefined; import io.lbry.browser.utils.Predefined;
public class LanguageSpinnerAdapter extends ArrayAdapter<Language> { public class LanguageSpinnerAdapter extends ArrayAdapter<Language> {
private final int layoutResourceId; private int layoutResourceId;
private final LayoutInflater inflater; private LayoutInflater inflater;
public LanguageSpinnerAdapter(Context context, int resource) { public LanguageSpinnerAdapter(Context context, int resource) {
super(context, resource, 0, Predefined.PUBLISH_LANGUAGES); super(context, resource, 0, Predefined.PUBLISH_LANGUAGES);

View file

@ -10,12 +10,13 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import io.lbry.browser.R; import io.lbry.browser.R;
import io.lbry.browser.model.Language;
import io.lbry.browser.model.License; import io.lbry.browser.model.License;
import io.lbry.browser.utils.Predefined; import io.lbry.browser.utils.Predefined;
public class LicenseSpinnerAdapter extends ArrayAdapter<License> { public class LicenseSpinnerAdapter extends ArrayAdapter<License> {
private final int layoutResourceId; private int layoutResourceId;
private final LayoutInflater inflater; private LayoutInflater inflater;
public LicenseSpinnerAdapter(Context context, int resource) { public LicenseSpinnerAdapter(Context context, int resource) {
super(context, resource, 0, Predefined.LICENSES); super(context, resource, 0, Predefined.LICENSES);

View file

@ -2,8 +2,10 @@ package io.lbry.browser.adapter;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -15,14 +17,15 @@ import io.lbry.browser.R;
import io.lbry.browser.model.NavMenuItem; import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.ui.controls.SolidIconView; import io.lbry.browser.ui.controls.SolidIconView;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> { public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> {
private static final int TYPE_GROUP = 1; private static final int TYPE_GROUP = 1;
private static final int TYPE_ITEM = 2; private static final int TYPE_ITEM = 2;
private final Context context; private Context context;
private final List<NavMenuItem> menuItems; private List<NavMenuItem> menuItems;
private NavMenuItem currentItem; private NavMenuItem currentItem;
@Setter @Setter
private NavigationMenuItemClickListener listener; private NavigationMenuItemClickListener listener;
@ -62,8 +65,8 @@ public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAd
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final SolidIconView iconView; protected SolidIconView iconView;
protected final TextView titleView; protected TextView titleView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
titleView = v.findViewById(R.id.nav_menu_title); titleView = v.findViewById(R.id.nav_menu_title);

View file

@ -1,265 +0,0 @@
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);
}
}

View file

@ -32,7 +32,7 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
public static final int DISPLAY_MODE_ALL = 1; public static final int DISPLAY_MODE_ALL = 1;
public static final int DISPLAY_MODE_UNCLAIMED = 2; public static final int DISPLAY_MODE_UNCLAIMED = 2;
private final Context context; private Context context;
@Setter @Setter
private List<Reward> all; private List<Reward> all;
private List<Reward> items; private List<Reward> items;
@ -85,16 +85,16 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View iconClaimed; protected View iconClaimed;
protected final View loading; protected View loading;
protected final View upTo; protected View upTo;
protected final TextView textTitle; protected TextView textTitle;
protected final TextView textDescription; protected TextView textDescription;
protected final TextView textLbcValue; protected TextView textLbcValue;
protected final TextView textUsdValue; protected TextView textUsdValue;
protected final TextView textLinkTransaction; protected TextView textLinkTransaction;
protected final EditText inputCustomCode; protected EditText inputCustomCode;
protected final MaterialButton buttonClaimCustom; protected MaterialButton buttonClaimCustom;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon); iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
@ -168,10 +168,6 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
return; return;
} }
if (vh.inputCustomCode != null && !vh.inputCustomCode.hasFocus()) {
vh.inputCustomCode.requestFocus();
}
if (clickListener != null) { if (clickListener != null) {
clickListener.onRewardClicked(reward, vh.loading); clickListener.onRewardClicked(reward, vh.loading);
} }

View file

@ -1,70 +0,0 @@
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;
}
}

View file

@ -22,9 +22,9 @@ import io.lbry.browser.utils.Helper;
import lombok.Setter; import lombok.Setter;
public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> { public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> {
private final Context context; private Context context;
private final List<Claim> items; private List<Claim> items;
private final List<Claim> selectedItems; private List<Claim> selectedItems;
@Setter @Setter
private ChannelItemSelectionListener listener; private ChannelItemSelectionListener listener;
@ -35,11 +35,11 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View noThumbnailView; protected View noThumbnailView;
protected final ImageView thumbnailView; protected ImageView thumbnailView;
protected final TextView alphaView; protected TextView alphaView;
protected final TextView titleView; protected TextView titleView;
protected final TextView tagView; protected TextView tagView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail); noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
@ -89,8 +89,7 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
@Override @Override
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) { public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) {
Claim claim = items.get(position); Claim claim = items.get(position);
ViewGroup.LayoutParams lp = vh.thumbnailView.getLayoutParams(); String thumbnailUrl = claim.getThumbnailUrl();
String thumbnailUrl = claim.getThumbnailUrl(lp.width, lp.height, 85);
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId()); int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context); Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);

View file

@ -23,13 +23,12 @@ public class TagListAdapter extends RecyclerView.Adapter<TagListAdapter.ViewHold
public static final int CUSTOMIZE_MODE_ADD = 1; public static final int CUSTOMIZE_MODE_ADD = 1;
public static final int CUSTOMIZE_MODE_REMOVE = 2; public static final int CUSTOMIZE_MODE_REMOVE = 2;
private final Context context; private Context context;
private List<Tag> items; private List<Tag> items;
@Setter @Setter
private TagClickListener clickListener; private TagClickListener clickListener;
@Setter
@Getter @Getter
@Setter
private int customizeMode; private int customizeMode;
public TagListAdapter(List<Tag> tags, Context context) { public TagListAdapter(List<Tag> tags, Context context) {
@ -39,8 +38,8 @@ public class TagListAdapter extends RecyclerView.Adapter<TagListAdapter.ViewHold
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final ImageView iconView; protected ImageView iconView;
protected final TextView nameView; protected TextView nameView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
iconView = v.findViewById(R.id.tag_action); iconView = v.findViewById(R.id.tag_action);

View file

@ -26,8 +26,8 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
private static final DecimalFormat TX_LIST_AMOUNT_FORMAT = new DecimalFormat("#,##0.0000"); private static final DecimalFormat TX_LIST_AMOUNT_FORMAT = new DecimalFormat("#,##0.0000");
private static final SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d"); private static final SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
private final Context context; private Context context;
private final List<Transaction> items; private List<Transaction> items;
@Setter @Setter
private TransactionClickListener listener; private TransactionClickListener listener;
@ -72,9 +72,7 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
vh.claimView.setText(item.getClaim()); vh.claimView.setText(item.getClaim());
vh.feeView.setText(context.getString(R.string.tx_list_fee, TX_LIST_AMOUNT_FORMAT.format(item.getFee().doubleValue()))); vh.feeView.setText(context.getString(R.string.tx_list_fee, TX_LIST_AMOUNT_FORMAT.format(item.getFee().doubleValue())));
vh.txidLinkView.setText(item.getTxid().substring(0, 7)); vh.txidLinkView.setText(item.getTxid().substring(0, 7));
vh.dateView.setVisibility(item.getConfirmations() > 0 ? View.VISIBLE : View.GONE); vh.dateView.setText(TX_LIST_DATE_FORMAT.format(item.getTxDate()));
vh.dateView.setText(item.getConfirmations() > 0 ? TX_LIST_DATE_FORMAT.format(item.getTxDate()) : null);
vh.pendingView.setVisibility(item.getConfirmations() == 0 ? View.VISIBLE : View.GONE);
vh.infoFeeContainer.setVisibility(!Helper.isNullOrEmpty(item.getClaim()) || Math.abs(item.getFee().doubleValue()) > 0 ? vh.infoFeeContainer.setVisibility(!Helper.isNullOrEmpty(item.getClaim()) || Math.abs(item.getFee().doubleValue()) > 0 ?
View.VISIBLE : View.GONE); View.VISIBLE : View.GONE);
@ -107,14 +105,13 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final TextView descView; protected TextView descView;
protected final TextView amountView; protected TextView amountView;
protected final TextView claimView; protected TextView claimView;
protected final TextView feeView; protected TextView feeView;
protected final TextView txidLinkView; protected TextView txidLinkView;
protected final TextView dateView; protected TextView dateView;
protected final TextView pendingView; protected View infoFeeContainer;
protected final View infoFeeContainer;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
@ -124,7 +121,6 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
feeView = v.findViewById(R.id.transaction_fee); feeView = v.findViewById(R.id.transaction_fee);
txidLinkView = v.findViewById(R.id.transaction_id_link); txidLinkView = v.findViewById(R.id.transaction_id_link);
dateView = v.findViewById(R.id.transaction_date); dateView = v.findViewById(R.id.transaction_date);
pendingView = v.findViewById(R.id.transaction_pending_text);
infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container); infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container);
} }
} }

View file

@ -21,8 +21,8 @@ import io.lbry.browser.utils.LbryUri;
import lombok.Setter; import lombok.Setter;
public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestionListAdapter.ViewHolder> { public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestionListAdapter.ViewHolder> {
private final Context context; private Context context;
private final List<UrlSuggestion> items; private List<UrlSuggestion> items;
@Setter @Setter
private UrlSuggestionClickListener listener; private UrlSuggestionClickListener listener;
@ -130,9 +130,9 @@ public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestion
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected final SolidIconView iconView; protected SolidIconView iconView;
protected final TextView titleView; protected TextView titleView;
protected final TextView descView; protected TextView descView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
iconView = v.findViewById(R.id.url_suggestion_icon); iconView = v.findViewById(R.id.url_suggestion_icon);

View file

@ -25,7 +25,7 @@ public class VerificationPagerAdapter extends FragmentStateAdapter {
public static final int PAGE_VERIFICATION_WALLET = 2; public static final int PAGE_VERIFICATION_WALLET = 2;
public static final int PAGE_VERIFICATION_MANUAL = 3; public static final int PAGE_VERIFICATION_MANUAL = 3;
private final FragmentActivity activity; private FragmentActivity activity;
public VerificationPagerAdapter(FragmentActivity activity) { public VerificationPagerAdapter(FragmentActivity activity) {
super(activity); super(activity);

View file

@ -1,100 +0,0 @@
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();
}
}
}

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.opengl.Visibility;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.ParseException; import java.text.ParseException;
@ -12,22 +13,22 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Tag; import io.lbry.browser.model.Tag;
import io.lbry.browser.model.UrlSuggestion; import io.lbry.browser.model.UrlSuggestion;
import io.lbry.browser.model.ViewHistory; import io.lbry.browser.model.ViewHistory;
import io.lbry.browser.model.lbryinc.LbryNotification;
import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
public class DatabaseHelper extends SQLiteOpenHelper { public class DatabaseHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 8; public static final int DATABASE_VERSION = 2;
public static final String DATABASE_NAME = "LbryApp.db"; public static final String DATABASE_NAME = "LbryApp.db";
private static DatabaseHelper instance; private static DatabaseHelper instance;
private static final String[] SQL_CREATE_TABLES = { private static final String[] SQL_CREATE_TABLES = {
// local subscription store // local subscription store
"CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL, is_notifications_disabled INTEGER DEFAULT 0 NOT NULL)", "CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL)",
// url entry / suggestion history // url entry / suggestion history
"CREATE TABLE url_history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)", "CREATE TABLE url_history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)",
// tags (known and followed) // tags (known and followed)
@ -47,20 +48,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
", thumbnail_url TEXT" + ", thumbnail_url TEXT" +
", release_time INTEGER " + ", release_time INTEGER " +
", device TEXT" + ", device TEXT" +
", timestamp TEXT NOT NULL)", ", timestamp TEXT NOT NULL)"
"CREATE TABLE notifications (" +
" id INTEGER PRIMARY KEY NOT NULL" +
", remote_id INTEGER NOT NULL" +
", author_url TEXT" +
", title TEXT" +
", description TEXT" +
", thumbnail_url TEXT" +
", target_url TEXT" +
", rule TEXT" +
", is_read INTEGER DEFAULT 0 NOT NULL" +
", is_seen INTEGER DEFAULT 0 NOT NULL " +
", timestamp TEXT NOT NULL)",
"CREATE TABLE shuffle_watched (id INTEGER PRIMARY KEY NOT NULL, claim_id TEXT NOT NULL)"
}; };
private static final String[] SQL_CREATE_INDEXES = { private static final String[] SQL_CREATE_INDEXES = {
"CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)", "CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)",
@ -68,69 +56,22 @@ public class DatabaseHelper extends SQLiteOpenHelper {
"CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)", "CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)",
"CREATE UNIQUE INDEX idx_tag_name ON tags (name)", "CREATE UNIQUE INDEX idx_tag_name ON tags (name)",
"CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)", "CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)",
"CREATE INDEX idx_view_history_device ON view_history (device)", "CREATE INDEX idx_view_history_device ON view_history (device)"
"CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)",
"CREATE INDEX idx_notification_timestamp ON notifications (timestamp)",
"CREATE UNIQUE INDEX idx_shuffle_watched_claim ON shuffle_watched (claim_id)",
}; };
private static final String[] SQL_V1_V2_UPGRADE = { private static final String[] SQL_V1_V2_UPGRADE = {
"ALTER TABLE view_history ADD COLUMN currency TEXT" "ALTER TABLE view_history ADD COLUMN currency TEXT"
}; };
private static final String[] SQL_V2_V3_UPGRADE = { private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)";
"CREATE TABLE notifications (" +
" id INTEGER PRIMARY KEY NOT NULL" +
", title TEXT" +
", description TEXT" +
", thumbnail_url TEXT" +
", target_url TEXT" +
", is_read INTEGER DEFAULT 0 NOT NULL" +
", timestamp TEXT NOT NULL)",
"CREATE INDEX idx_notification_timestamp ON notifications (timestamp)"
};
private static final String[] SQL_V3_V4_UPGRADE = {
"ALTER TABLE notifications ADD COLUMN remote_id INTEGER",
"CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)"
};
private static final String[] SQL_V4_V5_UPGRADE = {
"ALTER TABLE notifications ADD COLUMN rule TEXT",
"ALTER TABLE notifications ADD COLUMN is_seen TEXT"
};
private static final String[] SQL_V5_V6_UPGRADE = {
"ALTER TABLE notifications ADD COLUMN author_url TEXT"
};
private static final String[] SQL_V6_V7_UPGRADE = {
"CREATE TABLE shuffle_watched (id INTEGER PRIMARY KEY NOT NULL, claim_id TEXT NOT NULL)",
"CREATE UNIQUE INDEX idx_shuffle_watched_claim ON shuffle_watched (claim_id)"
};
private static final String[] SQL_V7_V8_UPGRADE = {
"AlTER TABLE subscriptions ADD COLUMN is_notifications_disabled INTEGER DEFAULT 0 NOT NULL"
};
private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url, is_notifications_disabled) VALUES (?, ?, ?)";
private static final String SQL_UPDATE_SUBSCRIPTION_NOTIFICATION = "UPDATE subscriptions SET is_notification_disabled = ? WHERE url = ?";
private static final String SQL_CLEAR_SUBSCRIPTIONS = "DELETE FROM subscriptions";
private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?"; private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?";
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url, is_notifications_disabled FROM subscriptions"; private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url FROM subscriptions";
private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?, ?)"; private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?, ?)";
private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history"; private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?"; private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?";
private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10"; private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10";
private static final String SQL_INSERT_NOTIFICATION = "REPLACE INTO notifications (remote_id, author_url, title, description, rule, target_url, is_read, is_seen, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String SQL_GET_NOTIFICATIONS = "SELECT id, remote_id, author_url, title, description, rule, target_url, is_read, is_seen, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500";
private static final String SQL_GET_UNREAD_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_read <> 1";
private static final String SQL_GET_UNSEEN_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_seen <> 1";
private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0";
private static final String SQL_MARK_NOTIFICATIONS_SEEN = "UPDATE notifications SET is_seen = 1 WHERE is_seen = 0";
private static final String SQL_MARK_NOTIFICATION_READ_AND_SEEN = "UPDATE notifications SET is_read = 1, is_seen = 1 WHERE id = ?";
private static final String SQL_INSERT_SHUFFLE_WATCHED = "REPLACE INTO shuffle_watched (claim_id) VALUES (?)";
private static final String SQL_GET_SHUFFLE_WATCHED_CLAIMS = "SELECT claim_id FROM shuffle_watched";
private static final String SQL_INSERT_VIEW_HISTORY = private static final String SQL_INSERT_VIEW_HISTORY =
"REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; "REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String SQL_GET_VIEW_HISTORY = private static final String SQL_GET_VIEW_HISTORY =
@ -169,36 +110,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
db.execSQL(sql); db.execSQL(sql);
} }
} }
if (oldVersion < 3) {
for (String sql : SQL_V2_V3_UPGRADE) {
db.execSQL(sql);
}
}
if (oldVersion < 4) {
for (String sql : SQL_V3_V4_UPGRADE) {
db.execSQL(sql);
}
}
if (oldVersion < 5) {
for (String sql : SQL_V4_V5_UPGRADE) {
db.execSQL(sql);
}
}
if (oldVersion < 6) {
for (String sql : SQL_V5_V6_UPGRADE) {
db.execSQL(sql);
}
}
if (oldVersion < 7) {
for (String sql : SQL_V6_V7_UPGRADE) {
db.execSQL(sql);
}
}
if (oldVersion < 8) {
for (String sql : SQL_V7_V8_UPGRADE) {
db.execSQL(sql);
}
}
} }
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
@ -215,7 +126,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) { public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) {
db.execSQL(SQL_CLEAR_URL_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) }); db.execSQL(SQL_CLEAR_URL_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) });
} }
// History items are essentially url suggestions // History items are essentially url suggestions
public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) { public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) {
List<UrlSuggestion> suggestions = new ArrayList<>(); List<UrlSuggestion> suggestions = new ArrayList<>();
@ -315,21 +225,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
} }
public static void createOrUpdateSubscription(Subscription subscription, SQLiteDatabase db) { public static void createOrUpdateSubscription(Subscription subscription, SQLiteDatabase db) {
db.execSQL(SQL_INSERT_SUBSCRIPTION, new Object[] { db.execSQL(SQL_INSERT_SUBSCRIPTION, new Object[] { subscription.getChannelName(), subscription.getUrl() });
subscription.getChannelName(),
subscription.getUrl(),
subscription.isNotificationsDisabled() ? 1 : 0
});
}
public static void setSubscriptionNotificationDisabled(boolean flag, String url, SQLiteDatabase db) {
db.execSQL(SQL_UPDATE_SUBSCRIPTION_NOTIFICATION, new Object[] { flag ? 1 : 0, url });
} }
public static void deleteSubscription(Subscription subscription, SQLiteDatabase db) { public static void deleteSubscription(Subscription subscription, SQLiteDatabase db) {
db.execSQL(SQL_DELETE_SUBSCRIPTION, new Object[] { subscription.getUrl() }); db.execSQL(SQL_DELETE_SUBSCRIPTION, new Object[] { subscription.getUrl() });
} }
public static void clearSubscriptions(SQLiteDatabase db) {
db.execSQL(SQL_CLEAR_SUBSCRIPTIONS);
}
public static List<Subscription> getSubscriptions(SQLiteDatabase db) { public static List<Subscription> getSubscriptions(SQLiteDatabase db) {
List<Subscription> subscriptions = new ArrayList<>(); List<Subscription> subscriptions = new ArrayList<>();
Cursor cursor = null; Cursor cursor = null;
@ -339,7 +239,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
subscription.setChannelName(cursor.getString(0)); subscription.setChannelName(cursor.getString(0));
subscription.setUrl(cursor.getString(1)); subscription.setUrl(cursor.getString(1));
subscription.setNotificationsDisabled(cursor.getInt(2) == 1);
subscriptions.add(subscription); subscriptions.add(subscription);
} }
} finally { } finally {
@ -348,112 +247,4 @@ public class DatabaseHelper extends SQLiteOpenHelper {
return subscriptions; return subscriptions;
} }
public static void createOrUpdateNotification(LbryNotification notification, SQLiteDatabase db) {
db.execSQL(SQL_INSERT_NOTIFICATION, new Object[] {
notification.getRemoteId(),
notification.getAuthorUrl(),
notification.getTitle(),
notification.getDescription(),
notification.getRule(),
notification.getTargetUrl(),
notification.isRead() ? 1 : 0,
notification.isSeen() ? 1 : 0,
new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(notification.getTimestamp() != null ? notification.getTimestamp() : new Date())
});
}
public static List<LbryNotification> getNotifications(SQLiteDatabase db) {
List<LbryNotification> notifications = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery(SQL_GET_NOTIFICATIONS, null);
while (cursor.moveToNext()) {
LbryNotification notification = new LbryNotification();
int columnIndex = 0;
notification.setId(cursor.getLong(columnIndex++));
notification.setRemoteId(cursor.getLong(columnIndex++));
notification.setAuthorUrl(cursor.getString(columnIndex++));
notification.setTitle(cursor.getString(columnIndex++));
notification.setDescription(cursor.getString(columnIndex++));
notification.setRule(cursor.getString(columnIndex++));
notification.setTargetUrl(cursor.getString(columnIndex++));
notification.setRead(cursor.getInt(columnIndex++) == 1);
notification.setSeen(cursor.getInt(columnIndex++) == 1);
try {
notification.setTimestamp(new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).parse(cursor.getString(columnIndex++)));
} catch (ParseException ex) {
// invalid timestamp (which shouldn't happen). Skip this item
continue;
}
notifications.add(notification);
}
} finally {
Helper.closeCursor(cursor);
}
return notifications;
}
public static void deleteNotifications(List<LbryNotification> notifications, SQLiteDatabase db) {
StringBuilder sb = new StringBuilder("DELETE FROM notifications WHERE remote_id IN (");
List<Object> remoteIds = new ArrayList<>();
String delim = "";
for (int i = 0; i < notifications.size(); i++) {
remoteIds.add(String.valueOf(notifications.get(i).getRemoteId()));
sb.append(delim).append("?");
delim = ",";
}
sb.append(")");
String sql = sb.toString();
db.execSQL(sql, remoteIds.toArray());
}
public static int getUnreadNotificationsCount(SQLiteDatabase db) {
int count = 0;
Cursor cursor = null;
try {
cursor = db.rawQuery(SQL_GET_UNREAD_NOTIFICATIONS_COUNT, null);
if (cursor.moveToNext()) {
count = cursor.getInt(0);
}
} finally {
Helper.closeCursor(cursor);
}
return count;
}
public static int getUnseenNotificationsCount(SQLiteDatabase db) {
int count = 0;
Cursor cursor = null;
try {
cursor = db.rawQuery(SQL_GET_UNSEEN_NOTIFICATIONS_COUNT, null);
if (cursor.moveToNext()) {
count = cursor.getInt(0);
}
} finally {
Helper.closeCursor(cursor);
}
return count;
}
public static void markNotificationsSeen(SQLiteDatabase db) {
db.execSQL(SQL_MARK_NOTIFICATIONS_SEEN);
}
public static void markNotificationsRead(SQLiteDatabase db) {
db.execSQL(SQL_MARK_NOTIFICATIONS_READ);
}
public static void markNotificationReadAndSeen(long notificationId, SQLiteDatabase db) {
db.execSQL(SQL_MARK_NOTIFICATION_READ_AND_SEEN, new Object[] { notificationId });
}
public static void createOrUpdateShuffleWatched(String claimId, SQLiteDatabase db) {
db.execSQL(SQL_INSERT_SHUFFLE_WATCHED, new Object[] { claimId });
}
public static List<String> getShuffleWatchedClaims(SQLiteDatabase db) {
List<String> claimIds = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery(SQL_GET_SHUFFLE_WATCHED_CLAIMS, null);
while (cursor.moveToNext()) {
claimIds.add(cursor.getString(0));
}
} finally {
Helper.closeCursor(cursor);
}
return claimIds;
}
} }

View file

@ -67,8 +67,8 @@ public class ContentFromDialogFragment extends BottomSheetDialogFragment {
R.id.content_from_past_year_item, R.id.content_from_past_year_item,
R.id.content_from_all_time_item R.id.content_from_all_time_item
}; };
private final BottomSheetDialogFragment dialog; private BottomSheetDialogFragment dialog;
private final ContentFromListener listener; private ContentFromListener listener;
public ContentFromItemClickListener(BottomSheetDialogFragment dialog, ContentFromListener listener) { public ContentFromItemClickListener(BottomSheetDialogFragment dialog, ContentFromListener listener) {
this.dialog = dialog; this.dialog = dialog;

View file

@ -54,8 +54,8 @@ public class ContentScopeDialogFragment extends BottomSheetDialogFragment {
private final int[] checkViewIds = { private final int[] checkViewIds = {
R.id.content_scope_everyone_item_selected, R.id.content_scope_tags_item_selected R.id.content_scope_everyone_item_selected, R.id.content_scope_tags_item_selected
}; };
private final BottomSheetDialogFragment dialog; private BottomSheetDialogFragment dialog;
private final ContentScopeListener listener; private ContentScopeListener listener;
public ContentScopeItemClickListener(BottomSheetDialogFragment dialog, ContentScopeListener listener) { public ContentScopeItemClickListener(BottomSheetDialogFragment dialog, ContentScopeListener listener) {
this.dialog = dialog; this.dialog = dialog;

View file

@ -57,8 +57,8 @@ public class ContentSortDialogFragment extends BottomSheetDialogFragment {
private final int[] checkViewIds = { private final int[] checkViewIds = {
R.id.sort_by_trending_item_selected, R.id.sort_by_new_item_selected, R.id.sort_by_top_item_selected R.id.sort_by_trending_item_selected, R.id.sort_by_new_item_selected, R.id.sort_by_top_item_selected
}; };
private final BottomSheetDialogFragment dialog; private BottomSheetDialogFragment dialog;
private final SortByListener listener; private SortByListener listener;
public SortByItemClickListener(BottomSheetDialogFragment dialog, SortByListener listener) { public SortByItemClickListener(BottomSheetDialogFragment dialog, SortByListener listener) {
this.dialog = dialog; this.dialog = dialog;

View file

@ -1,349 +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.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);
}
}

View file

@ -142,7 +142,7 @@ public class CustomizeTagsDialogFragment extends BottomSheetDialogFragment {
return view; return view;
} }
private final TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() { private TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
@Override @Override
public void onTagClicked(Tag tag, int customizeMode) { public void onTagClicked(Tag tag, int customizeMode) {
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) { if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {

View file

@ -5,6 +5,7 @@ import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;

View file

@ -37,6 +37,7 @@ import io.lbry.browser.tasks.claim.StreamRepostTask;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
import lombok.Setter;
public class RepostClaimDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener { public class RepostClaimDialogFragment extends BottomSheetDialogFragment implements WalletBalanceListener {
public static final String TAG = "RepostClaimDialog"; public static final String TAG = "RepostClaimDialog";
@ -56,17 +57,13 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
private TextView linkToggleAdvanced; private TextView linkToggleAdvanced;
private View advancedContainer; private View advancedContainer;
private final RepostClaimListener listener; @Setter
private final Claim claim; private RepostClaimListener listener;
@Setter
private Claim claim;
private RepostClaimDialogFragment(Claim claim, RepostClaimListener listener) { public static RepostClaimDialogFragment newInstance() {
super(); return new RepostClaimDialogFragment();
this.listener = listener;
this.claim = claim;
}
public static RepostClaimDialogFragment newInstance(Claim claim, RepostClaimListener listener) {
return new RepostClaimDialogFragment(claim, listener);
} }
@Override @Override
@ -195,16 +192,14 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
private void loadChannels(List<Claim> channels) { private void loadChannels(List<Claim> channels) {
if (channelSpinnerAdapter == null) { if (channelSpinnerAdapter == null) {
Context context = getContext(); Context context = getContext();
if (context != null) { channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels);
channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels); channelSpinnerAdapter.notifyDataSetChanged();
channelSpinnerAdapter.notifyDataSetChanged();
}
} else { } else {
channelSpinnerAdapter.clear(); channelSpinnerAdapter.clear();
channelSpinnerAdapter.addAll(channels); channelSpinnerAdapter.addAll(channels);
channelSpinnerAdapter.notifyDataSetChanged(); channelSpinnerAdapter.notifyDataSetChanged();
} }
if (channelSpinner != null && channelSpinnerAdapter != null) { if (channelSpinner != null) {
channelSpinner.setAdapter(channelSpinnerAdapter); channelSpinner.setAdapter(channelSpinnerAdapter);
} }
} }
@ -234,18 +229,8 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
showError(getString(R.string.insufficient_balance)); showError(getString(R.string.insufficient_balance));
return; return;
} }
if (bid.doubleValue() < Helper.MIN_DEPOSIT) {
String message = getResources().getQuantityString(R.plurals.min_deposit_required, 2, String.valueOf(Helper.MIN_DEPOSIT));
showError(message);
return;
}
Claim channel = (Claim) channelSpinner.getSelectedItem(); Claim channel = (Claim) channelSpinner.getSelectedItem();
if (channel == null) {
showError(getString(R.string.please_select_repost_channel));
return;
}
StreamRepostTask task = new StreamRepostTask(name, bid, claim.getClaimId(), channel.getClaimId(), repostProgress, new ClaimResultHandler() { StreamRepostTask task = new StreamRepostTask(name, bid, claim.getClaimId(), channel.getClaimId(), repostProgress, new ClaimResultHandler() {
@Override @Override
public void beforeStart() { public void beforeStart() {
@ -271,13 +256,10 @@ public class RepostClaimDialogFragment extends BottomSheetDialogFragment impleme
} }
private void showError(String message) { private void showError(String message) {
View view = getView(); Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
if (view != null && !Helper.isNullOrEmpty(message)) { setBackgroundTint(Color.RED).
Snackbar.make(view, message, Snackbar.LENGTH_LONG). setTextColor(Color.WHITE).
setBackgroundTint(Color.RED). show();
setTextColor(Color.WHITE).
show();
}
} }
private void startLoading() { private void startLoading() {

View file

@ -0,0 +1,196 @@
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);
}
}

View file

@ -1,4 +0,0 @@
package io.lbry.browser.exceptions;
public class AuthTokenInvalidatedException extends Exception {
}

View file

@ -1,6 +0,0 @@
package io.lbry.browser.listener;
public interface PIPModeListener {
void onEnterPIPMode();
void onExitPIPMode();
}

View file

@ -7,7 +7,4 @@ public interface SignInListener {
void onPhoneAdded(String countryCode, String phoneNumber); void onPhoneAdded(String countryCode, String phoneNumber);
void onPhoneVerified(); void onPhoneVerified();
void onManualVerifyContinue(); void onManualVerifyContinue();
void onSkipQueueAction();
void onTwitterVerified();
void onManualProgress(boolean progress);
} }

View file

@ -1,7 +1,5 @@
package io.lbry.browser.model; package io.lbry.browser.model;
import androidx.annotation.Nullable;
import com.google.gson.FieldNamingPolicy; import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
@ -17,6 +15,7 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
@ -55,7 +54,6 @@ public class Claim {
@EqualsAndHashCode.Include @EqualsAndHashCode.Include
private boolean placeholder; private boolean placeholder;
private boolean placeholderAnonymous; private boolean placeholderAnonymous;
private boolean loadingPlaceholder;
private boolean featured; private boolean featured;
private boolean unresolved; // used for featured private boolean unresolved; // used for featured
private String address; private String address;
@ -139,14 +137,6 @@ public class Claim {
return null; return null;
} }
public boolean hasSource() {
if (value instanceof StreamMetadata) {
StreamMetadata metadata = (StreamMetadata) value;
return metadata.getSource() != null;
}
return false;
}
public boolean isPlayable() { public boolean isPlayable() {
if (value instanceof StreamMetadata) { if (value instanceof StreamMetadata) {
StreamMetadata metadata = (StreamMetadata) value; StreamMetadata metadata = (StreamMetadata) value;
@ -186,21 +176,6 @@ public class Claim {
return null; return null;
} }
/**
* Gets the URL from the CDN where getting the image file
* @param width Pass zero for width and height for the full size image file
* @param height Pass zero for width and height for the full size image file
* @param q Desired quality for the image to be retrieved
* @return URL from the CDN from where image can be retrieved
*/
public String getThumbnailUrl(int width, int height, int q) {
if (value != null && value.getThumbnail() != null) {
ImageCDNUrl imageCDNUrl = new ImageCDNUrl(Math.max(width, 0), Math.max(height, 0), q, null, value.getThumbnail().getUrl());
return imageCDNUrl.toString();
}
return null;
}
public String getCoverUrl() { public String getCoverUrl() {
if (TYPE_CHANNEL.equals(valueType) && value != null && value instanceof ChannelMetadata && ((ChannelMetadata) value).getCover() != null) { if (TYPE_CHANNEL.equals(valueType) && value != null && value instanceof ChannelMetadata && ((ChannelMetadata) value).getCover() != null) {
return ((ChannelMetadata) value).getCover().getUrl(); return ((ChannelMetadata) value).getCover().getUrl();
@ -314,9 +289,6 @@ public class Claim {
Claim signingChannel = new Claim(); Claim signingChannel = new Claim();
signingChannel.setClaimId(viewHistory.getPublisherClaimId()); signingChannel.setClaimId(viewHistory.getPublisherClaimId());
signingChannel.setName(viewHistory.getPublisherName()); signingChannel.setName(viewHistory.getPublisherName());
LbryUri channelUrl = LbryUri.tryParse(String.format("%s#%s", signingChannel.getName(), signingChannel.getClaimId()));
signingChannel.setPermanentUrl(channelUrl != null ? channelUrl.toString() : null);
if (!Helper.isNullOrEmpty(viewHistory.getPublisherTitle())) { if (!Helper.isNullOrEmpty(viewHistory.getPublisherTitle())) {
GenericMetadata channelValue = new GenericMetadata(); GenericMetadata channelValue = new GenericMetadata();
channelValue.setTitle(viewHistory.getPublisherTitle()); channelValue.setTitle(viewHistory.getPublisherTitle());
@ -508,30 +480,6 @@ public class Claim {
private String url; private String url;
} }
/**
* Object to be instantiated. In order to get the URLto the CDN, call toString() on it
*/
static class ImageCDNUrl {
private String appendedPath = "";
public ImageCDNUrl(int width, int height, int quality, @Nullable String format, String thumbnailUrl) {
if (width != 0 && height != 0)
appendedPath = "s:".concat(String.valueOf(width)).concat(":").concat(String.valueOf(height)).concat("/");
appendedPath = appendedPath.concat("quality:").concat(String.valueOf(quality)).concat("/");
appendedPath = appendedPath.concat("plain/").concat(thumbnailUrl);
if (format != null)
appendedPath = appendedPath.concat("@").concat(format);
}
@Override
public String toString() {
String url = "https://image-processor.vanwanet.com/optimize/";
return url.concat(appendedPath);
}
}
@Data @Data
public static class StreamInfo { public static class StreamInfo {
private long duration; // video / audio private long duration; // video / audio

View file

@ -40,7 +40,7 @@ public class ClaimCacheKey {
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof ClaimCacheKey)) { if (obj == null || !(obj instanceof ClaimCacheKey)) {
return false; return false;
} }
ClaimCacheKey key = (ClaimCacheKey) obj; ClaimCacheKey key = (ClaimCacheKey) obj;

View file

@ -1,15 +1,19 @@
package io.lbry.browser.model; package io.lbry.browser.model;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
public class ClaimSearchCacheValue { public class ClaimSearchCacheValue {
@Getter @Getter
private final List<Claim> claims; @Setter
private List<Claim> claims;
@Getter @Getter
private final long timestamp; @Setter
private long timestamp;
public ClaimSearchCacheValue(List<Claim> claims, long timestamp) { public ClaimSearchCacheValue(List<Claim> claims, long timestamp) {
this.claims = new ArrayList<>(claims); this.claims = new ArrayList<>(claims);

View file

@ -1,72 +0,0 @@
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());
}
}

View file

@ -4,9 +4,9 @@ import lombok.Data;
@Data @Data
public class Language { public class Language {
private final String code; private String code;
private final String name; private String name;
private final int stringResourceId; private int stringResourceId;
public Language(String code, String name, int stringResourceId) { public Language(String code, String name, int stringResourceId) {
this.code = code; this.code = code;

View file

@ -4,9 +4,9 @@ import lombok.Data;
@Data @Data
public class License { public class License {
private final String name; private String name;
private String url; private String url;
private final int stringResourceId; private int stringResourceId;
public License(String name, int stringResourceId) { public License(String name, int stringResourceId) {
this.name = name; this.name = name;

View file

@ -2,6 +2,8 @@ package io.lbry.browser.model;
import android.content.Context; import android.content.Context;
import androidx.core.content.res.ResourcesCompat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -18,7 +20,6 @@ public class NavMenuItem {
public static final int ID_ITEM_FOLLOWING = 101; public static final int ID_ITEM_FOLLOWING = 101;
public static final int ID_ITEM_EDITORS_CHOICE = 102; public static final int ID_ITEM_EDITORS_CHOICE = 102;
public static final int ID_ITEM_ALL_CONTENT = 103; public static final int ID_ITEM_ALL_CONTENT = 103;
public static final int ID_ITEM_SHUFFLE = 104;
// Your Content // Your Content
public static final int ID_ITEM_CHANNELS = 201; public static final int ID_ITEM_CHANNELS = 201;
@ -35,8 +36,8 @@ public class NavMenuItem {
public static final int ID_ITEM_SETTINGS = 401; public static final int ID_ITEM_SETTINGS = 401;
public static final int ID_ITEM_ABOUT = 402; public static final int ID_ITEM_ABOUT = 402;
private final Context context; private Context context;
private final int id; private int id;
private boolean group; private boolean group;
private int icon; private int icon;
private String title; private String title;

View file

@ -1,11 +0,0 @@
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;
}
}

View file

@ -5,9 +5,7 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import io.lbry.browser.R; import io.lbry.browser.R;
import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.exceptions.LbryUriException;
@ -55,22 +53,13 @@ public class Transaction {
int descStringId = -1; int descStringId = -1;
TransactionInfo info = null; TransactionInfo info = null;
List<TransactionInfo> infos = new ArrayList<>();
try { try {
if (jsonObject.has("abandon_info")) { if (jsonObject.has("abandon_info")) {
JSONArray array = jsonObject.getJSONArray("abandon_info"); JSONArray array = jsonObject.getJSONArray("abandon_info");
if (array.length() > 0) { if (array.length() > 0) {
if (array.length() == 1) { info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
info = TransactionInfo.fromJSONObject(array.getJSONObject(0)); descStringId = R.string.abandon;
descStringId = info.getBalanceDelta().doubleValue() == info.getAmount().doubleValue() ? R.string.unlock : R.string.abandon; transaction.setAbandonInfo(info);
transaction.setAbandonInfo(info);
} else {
// multiple abandon infos (txo_spend unlock tip)
descStringId = R.string.unlock;
for (int i = 0; i < array.length(); i++) {
infos.add(TransactionInfo.fromJSONObject(array.getJSONObject(i)));
}
}
} }
} }
if (info == null && jsonObject.has("claim_info")) { if (info == null && jsonObject.has("claim_info")) {
@ -105,18 +94,8 @@ public class Transaction {
// pass // pass
} }
if (transaction.getValue().doubleValue() == 0 && info != null && info.getBalanceDelta().doubleValue() != 0) {
transaction.setValue(info.getBalanceDelta());
if (transaction.getValue().doubleValue() == 0) {
if (info != null && info.getBalanceDelta().doubleValue() != 0) {
transaction.setValue(info.getBalanceDelta());
} else if (infos.size() > 0) {
BigDecimal total = new BigDecimal(0);
for (TransactionInfo txInfo : infos) {
total = total.add(txInfo.getAmount());
}
transaction.setValue(total);
}
} }
if (descStringId == -1) { if (descStringId == -1) {

View file

@ -1,9 +0,0 @@
package io.lbry.browser.model;
import lombok.Data;
@Data
public class TwitterOauth {
private String oauthToken;
private String oauthTokenSecret;
}

View file

@ -3,7 +3,9 @@ package io.lbry.browser.model;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import lombok.Data; import lombok.Data;
@Data @Data

View file

@ -1,33 +1,16 @@
package io.lbry.browser.model; package io.lbry.browser.model;
import org.json.JSONObject;
import java.math.BigDecimal; import java.math.BigDecimal;
import io.lbry.browser.utils.Helper;
import lombok.Data; import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data @Data
public class WalletBalance { public class WalletBalance {
@Setter
@Getter
private BigDecimal available; private BigDecimal available;
@Setter
@Getter
private BigDecimal reserved; private BigDecimal reserved;
@Setter
@Getter
private BigDecimal claims; private BigDecimal claims;
@Setter
@Getter
private BigDecimal supports; private BigDecimal supports;
@Setter
@Getter
private BigDecimal tips; private BigDecimal tips;
@Setter
@Getter
private BigDecimal total; private BigDecimal total;
public WalletBalance() { public WalletBalance() {
@ -38,18 +21,4 @@ public class WalletBalance {
tips = new BigDecimal(0); tips = new BigDecimal(0);
total = new BigDecimal(0); total = new BigDecimal(0);
} }
public static WalletBalance fromJSONObject(JSONObject json) {
WalletBalance balance = new WalletBalance();
JSONObject reservedSubtotals = Helper.getJSONObject("reserved_subtotals", json);
balance.setAvailable(new BigDecimal(Helper.getJSONString("available", "0", json)));
balance.setReserved(new BigDecimal(Helper.getJSONString("reserved", "0", json)));
balance.setTotal(new BigDecimal(Helper.getJSONString("total", "0", json)));
if (reservedSubtotals != null) {
balance.setClaims(new BigDecimal(Helper.getJSONString("claims", "0", reservedSubtotals)));
balance.setSupports(new BigDecimal(Helper.getJSONString("supports", "0", reservedSubtotals)));
balance.setTips(new BigDecimal(Helper.getJSONString("tips", "0", reservedSubtotals)));
}
return balance;
}
} }

View file

@ -1,17 +0,0 @@
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;
}
}

View file

@ -1,15 +1,11 @@
package io.lbry.browser.model; package io.lbry.browser.model;
import lombok.Data; import lombok.Data;
import lombok.Getter;
@Data @Data
public class WalletSync { public class WalletSync {
@Getter private String hash;
private final String hash; private String data;
@Getter
private final String data;
@Getter
private boolean changed; private boolean changed;
public WalletSync(String hash, String data) { public WalletSync(String hash, String data) {
@ -21,5 +17,4 @@ public class WalletSync {
this(hash, data); this(hash, data);
this.changed = changed; this.changed = changed;
} }
} }

View file

@ -1,40 +0,0 @@
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;
}
}

View file

@ -9,6 +9,7 @@ import org.json.JSONObject;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import io.lbry.browser.model.Claim;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import lombok.Data; import lombok.Data;

View file

@ -1,9 +0,0 @@
package io.lbry.browser.model.lbryinc;
import lombok.Data;
@Data
public class RewardVerified {
private long userId;
private boolean isRewardApproved;
}

View file

@ -11,21 +11,17 @@ public class Subscription {
@Getter @Getter
@Setter @Setter
private String url; private String url;
@Getter
@Setter
private boolean isNotificationsDisabled;
public Subscription() { public Subscription() {
} }
public Subscription(String channelName, String url, boolean isNotificationsDisabled) { public Subscription(String channelName, String url) {
this.channelName = channelName; this.channelName = channelName;
this.url = url; this.url = url;
this.isNotificationsDisabled = isNotificationsDisabled;
} }
public static Subscription fromClaim(Claim claim) { public static Subscription fromClaim(Claim claim) {
return new Subscription(claim.getName(), claim.getPermanentUrl(), false); return new Subscription(claim.getName(), claim.getPermanentUrl());
} }
public String toString() { public String toString() {
return url; return url;

View file

@ -1,70 +0,0 @@
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;
}
}

View file

@ -1,85 +0,0 @@
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);
}
}

View file

@ -1,10 +0,0 @@
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);
}

View file

@ -1,99 +0,0 @@
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);
}
}
}
}

View file

@ -10,10 +10,10 @@ import io.lbry.browser.model.Tag;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class FollowUnfollowTagTask extends AsyncTask<Void, Void, Boolean> { public class FollowUnfollowTagTask extends AsyncTask<Void, Void, Boolean> {
private final Tag tag; private Tag tag;
private final boolean unfollowing; private boolean unfollowing;
private final Context context; private Context context;
private final FollowUnfollowTagHandler handler; private FollowUnfollowTagHandler handler;
private Exception error; private Exception error;
public FollowUnfollowTagTask(Tag tag, boolean unfollowing, Context context, FollowUnfollowTagHandler handler) { public FollowUnfollowTagTask(Tag tag, boolean unfollowing, Context context, FollowUnfollowTagHandler handler) {

View file

@ -12,9 +12,9 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lighthouse; import io.lbry.browser.utils.Lighthouse;
public class LighthouseAutoCompleteTask extends AsyncTask<Void, Void, List<UrlSuggestion>> { public class LighthouseAutoCompleteTask extends AsyncTask<Void, Void, List<UrlSuggestion>> {
private final String text; private String text;
private final AutoCompleteResultHandler handler; private AutoCompleteResultHandler handler;
private final View progressView; private View progressView;
private Exception error; private Exception error;
public LighthouseAutoCompleteTask(String text, View progressView, AutoCompleteResultHandler handler) { public LighthouseAutoCompleteTask(String text, View progressView, AutoCompleteResultHandler handler) {

View file

@ -14,13 +14,13 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lighthouse; import io.lbry.browser.utils.Lighthouse;
public class LighthouseSearchTask extends AsyncTask<Void, Void, List<Claim>> { public class LighthouseSearchTask extends AsyncTask<Void, Void, List<Claim>> {
private final String rawQuery; private String rawQuery;
private final int size; private int size;
private final int from; private int from;
private final boolean nsfw; private boolean nsfw;
private final String relatedTo; private String relatedTo;
private final ClaimSearchResultHandler handler; private ClaimSearchResultHandler handler;
private final ProgressBar progressBar; private ProgressBar progressBar;
private Exception error; private Exception error;
public LighthouseSearchTask(String rawQuery, int size, int from, boolean nsfw, String relatedTo, ProgressBar progressBar, ClaimSearchResultHandler handler) { public LighthouseSearchTask(String rawQuery, int size, int from, boolean nsfw, String relatedTo, ProgressBar progressBar, ClaimSearchResultHandler handler) {

View file

@ -4,16 +4,22 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.view.View;
import android.widget.ProgressBar;
import java.util.List; import java.util.List;
import io.lbry.browser.MainActivity; import io.lbry.browser.MainActivity;
import io.lbry.browser.data.DatabaseHelper; import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.exceptions.LbryRequestException;
import io.lbry.browser.exceptions.LbryResponseException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.Tag; import io.lbry.browser.model.Tag;
import io.lbry.browser.utils.Helper;
public class LoadTagsTask extends AsyncTask<Void, Void, List<Tag>> { public class LoadTagsTask extends AsyncTask<Void, Void, List<Tag>> {
private final Context context; private Context context;
private final LoadTagsHandler handler; private LoadTagsHandler handler;
private Exception error; private Exception error;
public LoadTagsTask(Context context, LoadTagsHandler handler) { public LoadTagsTask(Context context, LoadTagsHandler handler) {

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -16,25 +17,26 @@ import java.util.Map;
import io.lbry.browser.MainActivity; import io.lbry.browser.MainActivity;
import io.lbry.browser.data.DatabaseHelper; import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.exceptions.LbryioRequestException; import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException; import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio; import io.lbry.browser.utils.Lbryio;
import okhttp3.Response;
// background task to create a diff of local and remote subscriptions and try to merge // background task to create a diff of local and remote subscriptions and try to merge
public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscription>> { public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscription>> {
private static final String TAG = "MergeSubscriptionsTask"; private static final String TAG = "MergeSubscriptionsTask";
private final Context context; private Context context;
private final List<Subscription> base; private List<Subscription> base;
private List<Subscription> diff; private List<Subscription> diff;
private final MergeSubscriptionsHandler handler; private MergeSubscriptionsHandler handler;
private Exception error; private Exception error;
private final boolean replaceLocal;
public MergeSubscriptionsTask(List<Subscription> base, boolean replaceLocal, Context context, MergeSubscriptionsHandler handler) { public MergeSubscriptionsTask(List<Subscription> base, Context context, MergeSubscriptionsHandler handler) {
this.base = base; this.base = base;
this.replaceLocal = replaceLocal;
this.context = context; this.context = context;
this.handler = handler; this.handler = handler;
} }
@ -51,17 +53,10 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
db = ((MainActivity) context).getDbHelper().getWritableDatabase(); db = ((MainActivity) context).getDbHelper().getWritableDatabase();
} }
if (db != null) { if (db != null) {
if (replaceLocal) { localSubs = DatabaseHelper.getSubscriptions(db);
DatabaseHelper.clearSubscriptions(db); for (Subscription sub : localSubs) {
for (Subscription sub : base) { if (!combined.contains(sub)) {
DatabaseHelper.createOrUpdateSubscription(sub, db); combined.add(sub);
}
} else {
localSubs = DatabaseHelper.getSubscriptions(db);
for (Subscription sub : localSubs) {
if (!combined.contains(sub)) {
combined.add(sub);
}
} }
} }
} }
@ -69,55 +64,48 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
// fetch remote subscriptions // fetch remote subscriptions
JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("subscription", "list", context)); JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("subscription", "list", context));
if (array != null) { if (array != null) {
// check for any remote subs that may have been removed, and unsubscribe from them
for (int i = 0; i < array.length(); i++) { for (int i = 0; i < array.length(); i++) {
JSONObject item = array.getJSONObject(i); JSONObject item = array.getJSONObject(i);
// TODO: Refactor by creating static Subscription.fromJSON method
String claimId = item.getString("claim_id"); String claimId = item.getString("claim_id");
String channelName = item.getString("channel_name"); String channelName = item.getString("channel_name");
boolean isNotificationsDisabled = item.getBoolean("is_notifications_disabled");
LbryUri url = new LbryUri(); LbryUri url = new LbryUri();
url.setChannelName(channelName); url.setChannelName(channelName);
url.setClaimId(claimId); url.setClaimId(claimId);
Subscription subscription = new Subscription(channelName, url.toString(), isNotificationsDisabled); Subscription subscription = new Subscription(channelName, url.toString());
remoteSubs.add(subscription); remoteSubs.add(subscription);
} }
} }
List<Subscription> remoteUnsubs = new ArrayList<>(); for (int i = 0; i < combined.size(); i++) {
List<Subscription> finalRemoteSubs = new ArrayList<>(); Subscription local = combined.get(i);
if (remoteSubs.size() > 0) { if (!remoteSubs.contains(local)) {
for (int i = 0; i < remoteSubs.size(); i++) { // add to remote subscriptions
Subscription sub = remoteSubs.get(i); try {
if (!combined.contains(sub)) { LbryUri uri = LbryUri.parse(local.getUrl());
Map<String, String> options = new HashMap<>(); Map<String, String> options = new HashMap<>();
LbryUri uri = LbryUri.tryParse(sub.getUrl()); options.put("claim_id", uri.getChannelClaimId());
if (uri != null) { options.put("channel_name", Helper.normalizeChannelName(local.getChannelName()));
options.put("claim_id", uri.getChannelClaimId()); Lbryio.parseResponse(Lbryio.call("subscription", "new", options, context));
Lbryio.parseResponse(Lbryio.call("subscription", "delete", options, context)); } catch (LbryUriException | LbryioRequestException | LbryioResponseException ex) {
remoteUnsubs.add(sub); // pass
} else { Log.e(TAG, String.format("subscription/new failed: %s", ex.getMessage()), ex);
finalRemoteSubs.add(sub);
}
} }
} }
} }
if (!replaceLocal) { for (int i = 0; i < localSubs.size(); i++) {
for (int i = 0; i < localSubs.size(); i++) { Subscription local = localSubs.get(i);
Subscription local = localSubs.get(i); if (!base.contains(local) && !diff.contains(local)) {
if (!base.contains(local) && !diff.contains(local)) { diff.add(local);
diff.add(local);
}
} }
for (int i = 0; i < finalRemoteSubs.size(); i++) { }
Subscription remote = finalRemoteSubs.get(i); for (int i = 0; i < remoteSubs.size(); i++) {
if (!combined.contains(remote)) { Subscription remote = remoteSubs.get(i);
combined.add(remote); if (!combined.contains(remote)) {
if (!diff.contains(remote)) { combined.add(remote);
diff.add(remote); if (!diff.contains(remote)) {
} diff.add(remote);
} }
} }
} }

View file

@ -4,15 +4,18 @@ import android.os.AsyncTask;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.Buffer;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
public class ReadTextFileTask extends AsyncTask<Void, Void, String> { public class ReadTextFileTask extends AsyncTask<Void, Void, String> {
private final String filePath; private String filePath;
private Exception error; private Exception error;
private final ReadTextFileHandler handler; private ReadTextFileHandler handler;
public ReadTextFileTask(String filePath, ReadTextFileHandler handler) { public ReadTextFileTask(String filePath, ReadTextFileHandler handler) {
this.filePath = filePath; this.filePath = filePath;
this.handler = handler; this.handler = handler;

View file

@ -1,8 +0,0 @@
package io.lbry.browser.tasks;
import io.lbry.browser.model.lbryinc.RewardVerified;
public interface RewardVerifiedHandler {
void onSuccess(RewardVerified rewardVerified);
void onError(Exception error);
}

View file

@ -9,9 +9,9 @@ import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class SetSdkSettingTask extends AsyncTask<Void, Void, Boolean> { public class SetSdkSettingTask extends AsyncTask<Void, Void, Boolean> {
private final String key; private String key;
private final String value; private String value;
private final GenericTaskHandler handler; private GenericTaskHandler handler;
private Exception error; private Exception error;
public SetSdkSettingTask(String key, String value, GenericTaskHandler handler) { public SetSdkSettingTask(String key, String value, GenericTaskHandler handler) {
this.key = key; this.key = key;

View file

@ -1,8 +0,0 @@
package io.lbry.browser.tasks;
import io.lbry.browser.model.TwitterOauth;
public interface TwitterOauthHandler {
void onSuccess(TwitterOauth twitterOauth);
void onError(Exception error);
}

View file

@ -13,13 +13,13 @@ import io.lbry.browser.utils.Lbry;
public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> { public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
private final boolean clearPrevious; private boolean clearPrevious;
private final boolean excludeMature; private boolean excludeMature;
private final int limit; private int limit;
private final String filter; private String filter;
private final TagListAdapter addedTagsAdapter; private TagListAdapter addedTagsAdapter;
private final TagListAdapter suggestedTagsAdapter; private TagListAdapter suggestedTagsAdapter;
private final KnownTagsHandler handler; private KnownTagsHandler handler;
public UpdateSuggestedTagsTask( public UpdateSuggestedTagsTask(
String filter, String filter,
@ -45,15 +45,13 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
if (suggestedTagsAdapter != null && !clearPrevious) { if (suggestedTagsAdapter != null && !clearPrevious) {
tags = new ArrayList<>(suggestedTagsAdapter.getTags()); tags = new ArrayList<>(suggestedTagsAdapter.getTags());
} }
if (Lbry.knownTags.size() > 0) { while (tags.size() < limit) {
while (tags.size() < limit) { Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size())); if (excludeMature && randomTag.isMature()) {
if (excludeMature && randomTag.isMature()) { continue;
continue; }
} if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) {
if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) { tags.add(randomTag);
tags.add(randomTag);
}
} }
} }
} else { } else {
@ -66,15 +64,10 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
if (excludeMature && knownTag.isMature()) { if (excludeMature && knownTag.isMature()) {
continue; continue;
} }
try { if ((knownTag.getLowercaseName().startsWith(filter) || knownTag.getLowercaseName().matches(filter)) &&
if ((knownTag.getLowercaseName().startsWith(filter) || (!tags.contains(knownTag) &&
knownTag.getLowercaseName().matches(filter)) && !Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag)))) {
(!tags.contains(knownTag) && !Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag))) tags.add(knownTag);
) {
tags.add(knownTag);
}
} catch (Exception ex) {
// continue
} }
} }
} }

View file

@ -21,9 +21,9 @@ import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
public class UploadImageTask extends AsyncTask<Void, Void, String> { public class UploadImageTask extends AsyncTask<Void, Void, String> {
private final String filePath; private String filePath;
private final View progressView; private View progressView;
private final UploadThumbnailHandler handler; private UploadThumbnailHandler handler;
private Exception error; private Exception error;
public UploadImageTask(String filePath, View progressView, UploadThumbnailHandler handler) { public UploadImageTask(String filePath, View progressView, UploadThumbnailHandler handler) {

View file

@ -11,16 +11,17 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class AbandonChannelTask extends AsyncTask<Void, Void, Boolean> { public class AbandonChannelTask extends AsyncTask<Void, Void, Boolean> {
private final List<String> claimIds; private List<String> claimIds;
private List<String> successfulClaimIds; private List<String> successfulClaimIds;
private List<String> failedClaimIds; private List<String> failedClaimIds;
private List<Exception> failedExceptions; private List<Exception> failedExceptions;
private final View progressView; private View progressView;
private final AbandonHandler handler; private AbandonHandler handler;
public AbandonChannelTask(List<String> claimIds, View progressView, AbandonHandler handler) { public AbandonChannelTask(List<String> claimIds, View progressView, AbandonHandler handler) {
this.claimIds = claimIds; this.claimIds = claimIds;

View file

@ -11,16 +11,17 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class AbandonStreamTask extends AsyncTask<Void, Void, Boolean> { public class AbandonStreamTask extends AsyncTask<Void, Void, Boolean> {
private final List<String> claimIds; private List<String> claimIds;
private List<String> successfulClaimIds; private List<String> successfulClaimIds;
private List<String> failedClaimIds; private List<String> failedClaimIds;
private List<Exception> failedExceptions; private List<Exception> failedExceptions;
private final View progressView; private View progressView;
private final AbandonHandler handler; private AbandonHandler handler;
public AbandonStreamTask(List<String> claimIds, View progressView, AbandonHandler handler) { public AbandonStreamTask(List<String> claimIds, View progressView, AbandonHandler handler) {
this.claimIds = claimIds; this.claimIds = claimIds;

View file

@ -21,12 +21,12 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Claim> { public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Claim> {
private final Claim claim; private Claim claim;
private final BigDecimal deposit; private BigDecimal deposit;
private final boolean update; private boolean update;
private Exception error; private Exception error;
private final ClaimResultHandler handler; private ClaimResultHandler handler;
private final View progressView; private View progressView;
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, ClaimResultHandler handler) { public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, ClaimResultHandler handler) {
this.claim = claim; this.claim = claim;

View file

@ -19,9 +19,9 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> { public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
private final List<String> types; private List<String> types;
private final View progressView; private View progressView;
private final ClaimListResultHandler handler; private ClaimListResultHandler handler;
private Exception error; private Exception error;
public ClaimListTask(String type, View progressView, ClaimListResultHandler handler) { public ClaimListTask(String type, View progressView, ClaimListResultHandler handler) {
@ -62,8 +62,7 @@ public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
Helper.setViewVisibility(progressView, View.GONE); Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) { if (handler != null) {
if (claims != null) { if (claims != null) {
// TODO: Add fix for handling invalid reposts in ClaimListAdapter handler.onSuccess(claims);
handler.onSuccess(Helper.filterInvalidReposts(claims));
} else { } else {
handler.onError(error); handler.onError(error);
} }

View file

@ -12,10 +12,10 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> { public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
private final Map<String, Object> options; private Map<String, Object> options;
private final String connectionString; private String connectionString;
private final ClaimSearchResultHandler handler; private ClaimSearchResultHandler handler;
private final View progressView; private View progressView;
private ApiCallException error; private ApiCallException error;
public ClaimSearchTask(Map<String, Object> options, String connectionString, View progressView, ClaimSearchResultHandler handler) { public ClaimSearchTask(Map<String, Object> options, String connectionString, View progressView, ClaimSearchResultHandler handler) {
@ -29,7 +29,7 @@ public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
} }
protected List<Claim> doInBackground(Void... params) { protected List<Claim> doInBackground(Void... params) {
try { try {
return Lbry.claimSearch(options, connectionString); return Helper.filterInvalidReposts(Lbry.claimSearch(options, connectionString));
} catch (ApiCallException ex) { } catch (ApiCallException ex) {
error = ex; error = ex;
return null; return null;
@ -39,7 +39,7 @@ public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
Helper.setViewVisibility(progressView, View.GONE); Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) { if (handler != null) {
if (claims != null) { if (claims != null) {
handler.onSuccess(Helper.filterInvalidReposts(claims), claims.size() < Helper.parseInt(options.get("page_size"), 0)); handler.onSuccess(claims, claims.size() < Helper.parseInt(options.get("page_size"), 0));
} else { } else {
handler.onError(error); handler.onError(error);
} }

View file

@ -21,10 +21,10 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class PublishClaimTask extends AsyncTask<Void, Void, Claim> { public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
private final Claim claim; private Claim claim;
private final String filePath; private String filePath;
private final View progressView; private View progressView;
private final ClaimResultHandler handler; private ClaimResultHandler handler;
private Exception error; private Exception error;
public PublishClaimTask(Claim claim, String filePath, View progressView, ClaimResultHandler handler) { public PublishClaimTask(Claim claim, String filePath, View progressView, ClaimResultHandler handler) {
this.claim = claim; this.claim = claim;
@ -73,14 +73,6 @@ public class PublishClaimTask extends AsyncTask<Void, Void, Claim> {
options.put("license_url", metadata.getLicenseUrl()); options.put("license_url", metadata.getLicenseUrl());
} }
if (metadata.getReleaseTime() > 0) {
options.put("release_time", metadata.getReleaseTime());
} else if (claim.getTimestamp() > 0) {
options.put("release_time", claim.getTimestamp());
} else {
options.put("release_time", Double.valueOf(Math.floor(System.currentTimeMillis() / 1000.0)).intValue());
}
Claim claimResult = null; Claim claimResult = null;
try { try {
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PUBLISH, options); JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PUBLISH, options);

View file

@ -18,19 +18,12 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> { public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
private String claimId;
private int page; private int page;
private int pageSize; private int pageSize;
private final ClaimSearchResultHandler handler; private ClaimSearchResultHandler handler;
private final View progressView; private View progressView;
private Exception error; private Exception error;
public PurchaseListTask(String claimId, View progressView, ClaimSearchResultHandler handler) {
this.claimId = claimId;
this.progressView = progressView;
this.handler = handler;
}
public PurchaseListTask(int page, int pageSize, View progressView, ClaimSearchResultHandler handler) { public PurchaseListTask(int page, int pageSize, View progressView, ClaimSearchResultHandler handler) {
this.page = page; this.page = page;
this.pageSize = pageSize; this.pageSize = pageSize;
@ -45,15 +38,8 @@ public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
List<Claim> claims = null; List<Claim> claims = null;
try { try {
Map<String, Object> options = new HashMap<>(); Map<String, Object> options = new HashMap<>();
if (!Helper.isNullOrEmpty(claimId)) { options.put("page", page);
options.put("claim_id", claimId); options.put("page_size", pageSize);
}
if (page > 0) {
options.put("page", page);
}
if (pageSize > 0) {
options.put("page_size", pageSize);
}
options.put("resolve", true); options.put("resolve", true);
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PURCHASE_LIST, options); JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_PURCHASE_LIST, options);
@ -61,10 +47,9 @@ public class PurchaseListTask extends AsyncTask<Void, Void, List<Claim>> {
claims = new ArrayList<>(); claims = new ArrayList<>();
for (int i = 0; i < items.length(); i++) { for (int i = 0; i < items.length(); i++) {
Claim claim = Claim.fromJSONObject(items.getJSONObject(i).getJSONObject("claim")); Claim claim = Claim.fromJSONObject(items.getJSONObject(i).getJSONObject("claim"));
if (!Helper.isNullOrEmpty(claim.getClaimId())) { claims.add(claim);
claims.add(claim);
Lbry.addClaimToCache(claim); Lbry.addClaimToCache(claim);
}
} }
} catch (ApiCallException | JSONException | ClassCastException ex) { } catch (ApiCallException | JSONException | ClassCastException ex) {
error = ex; error = ex;

View file

@ -13,10 +13,10 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> { public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
private final List<String> urls; private List<String> urls;
private final String connectionString; private String connectionString;
private final ClaimListResultHandler handler; private ClaimListResultHandler handler;
private final View progressView; private View progressView;
private ApiCallException error; private ApiCallException error;
public ResolveTask(String url, String connectionString, View progressView, ClaimListResultHandler handler) { public ResolveTask(String url, String connectionString, View progressView, ClaimListResultHandler handler) {

View file

@ -20,12 +20,12 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class StreamRepostTask extends AsyncTask<Void, Void, Claim> { public class StreamRepostTask extends AsyncTask<Void, Void, Claim> {
private final String name; private String name;
private final BigDecimal bid; private BigDecimal bid;
private final String claimId; private String claimId;
private final String channelId; private String channelId;
private final View progressView; private View progressView;
private final ClaimResultHandler handler; private ClaimResultHandler handler;
private Exception error; private Exception error;
public StreamRepostTask(String name, BigDecimal bid, String claimId, String channelId, View progressView, ClaimResultHandler handler) { public StreamRepostTask(String name, BigDecimal bid, String claimId, String channelId, View progressView, ClaimResultHandler handler) {

View file

@ -7,11 +7,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
// Just run delete on the specified claim IDs (no need for a handler) // Just run delete on the specified claim IDs (no need for a handler)
public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> { public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> {
private final List<String> claimIds; private List<String> claimIds;
public BulkDeleteFilesTask(List<String> claimIds) { public BulkDeleteFilesTask(List<String> claimIds) {
this.claimIds = claimIds; this.claimIds = claimIds;
} }

View file

@ -10,9 +10,9 @@ import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class DeleteFileTask extends AsyncTask<Void, Void, Boolean> { public class DeleteFileTask extends AsyncTask<Void, Void, Boolean> {
private final String claimId; private String claimId;
private Exception error; private Exception error;
private final GenericTaskHandler handler; private GenericTaskHandler handler;
public DeleteFileTask(String claimId, GenericTaskHandler handler) { public DeleteFileTask(String claimId, GenericTaskHandler handler) {
this.claimId = claimId; this.claimId = claimId;

View file

@ -11,12 +11,12 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> { public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
private final String claimId; private String claimId;
private boolean downloads; private boolean downloads;
private int page; private int page;
private int pageSize; private int pageSize;
private final FileListResultHandler handler; private FileListResultHandler handler;
private final View progressView; private View progressView;
private ApiCallException error; private ApiCallException error;
public FileListTask(int page, int pageSize, boolean downloads, View progressView, FileListResultHandler handler) { public FileListTask(int page, int pageSize, boolean downloads, View progressView, FileListResultHandler handler) {

View file

@ -14,10 +14,10 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
public class GetFileTask extends AsyncTask<Void, Void, LbryFile> { public class GetFileTask extends AsyncTask<Void, Void, LbryFile> {
private final String uri; private String uri;
private final boolean saveFile; private boolean saveFile;
private final View progressView; private View progressView;
private final GetFileHandler handler; private GetFileHandler handler;
private Exception error; private Exception error;
public GetFileTask(String uri, boolean saveFile, View progressView, GetFileHandler handler) { public GetFileTask(String uri, boolean saveFile, View progressView, GetFileHandler handler) {

View file

@ -1,66 +0,0 @@
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);
}
}
}
}

View file

@ -13,15 +13,16 @@ import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.exceptions.LbryioRequestException; import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException; import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbryio; import io.lbry.browser.utils.Lbryio;
public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> { public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
private final Context context; private Context context;
private final String channelClaimId; private String channelClaimId;
private final Subscription subscription; private Subscription subscription;
private final ChannelSubscribeHandler handler; private ChannelSubscribeHandler handler;
private Exception error; private Exception error;
private final boolean isUnsubscribing; private boolean isUnsubscribing;
public ChannelSubscribeTask(Context context, String channelClaimId, Subscription subscription, boolean isUnsubscribing, ChannelSubscribeHandler handler) { public ChannelSubscribeTask(Context context, String channelClaimId, Subscription subscription, boolean isUnsubscribing, ChannelSubscribeHandler handler) {
this.context = context; this.context = context;
@ -50,11 +51,11 @@ public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
options.put("claim_id", channelClaimId); options.put("claim_id", channelClaimId);
if (!isUnsubscribing) { if (!isUnsubscribing) {
options.put("channel_name", subscription.getChannelName()); options.put("channel_name", subscription.getChannelName());
options.put("notifications_disabled", String.valueOf(subscription.isNotificationsDisabled()).toLowerCase());
} }
String action = isUnsubscribing ? "delete" : "new"; String action = isUnsubscribing ? "delete" : "new";
Object response = Lbryio.parseResponse(Lbryio.call("subscription", action, options, context)); Lbryio.call("subscription", action, options, context);
if (!isUnsubscribing) { if (!isUnsubscribing) {
Lbryio.addSubscription(subscription); Lbryio.addSubscription(subscription);
} else { } else {

View file

@ -4,8 +4,6 @@ import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.view.View; import android.view.View;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.text.DecimalFormat; import java.text.DecimalFormat;
@ -16,25 +14,23 @@ import io.lbry.browser.R;
import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.exceptions.LbryioRequestException; import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException; import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.Lbryio; import io.lbry.browser.utils.Lbryio;
public class ClaimRewardTask extends AsyncTask<Void, Void, String> { public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
private final Context context; private Context context;
private final String type; private String type;
private final String rewardCode; private String claimCode;
private final View progressView; private View progressView;
private double amountClaimed; private double amountClaimed;
private final ClaimRewardHandler handler; private ClaimRewardHandler handler;
private Exception error; private Exception error;
public ClaimRewardTask(String type, String rewardCode, View progressView, Context context, ClaimRewardHandler handler) { public ClaimRewardTask(String type, String claimCode, View progressView, Context context, ClaimRewardHandler handler) {
this.type = type; this.type = type;
this.rewardCode = rewardCode; this.claimCode = claimCode;
this.progressView = progressView; this.progressView = progressView;
this.context = context; this.context = context;
this.handler = handler; this.handler = handler;
@ -47,27 +43,15 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
public String doInBackground(Void... params) { public String doInBackground(Void... params) {
String message = null; String message = null;
try { try {
String txid = null;
if (Reward.TYPE_FIRST_CHANNEL.equalsIgnoreCase(type)) {
// fetch a channel
txid = fetchSingleClaimTxid(Claim.TYPE_CHANNEL);
} else if (Reward.TYPE_FIRST_PUBLISH.equalsIgnoreCase(type)) {
// fetch a publish
txid = fetchSingleClaimTxid(Claim.TYPE_STREAM);
}
// Get a new wallet address for the reward // Get a new wallet address for the reward
String address = (String) Lbry.genericApiCall(Lbry.METHOD_ADDRESS_UNUSED); String address = (String) Lbry.genericApiCall(Lbry.METHOD_ADDRESS_UNUSED);
Map<String, String> options = new HashMap<>(); Map<String, String> options = new HashMap<>();
options.put("reward_type", type); options.put("reward_type", type);
options.put("wallet_address", address); options.put("wallet_address", address);
if (!Helper.isNullOrEmpty(rewardCode)) { if (!Helper.isNullOrEmpty(claimCode)) {
options.put("code", rewardCode); options.put("claim_code", claimCode);
}
if (!Helper.isNullOrEmpty(txid)) {
options.put("transaction_id", txid);
}
}
JSONObject reward = (JSONObject) Lbryio.parseResponse( JSONObject reward = (JSONObject) Lbryio.parseResponse(
Lbryio.call("reward", "claim", options, Helper.METHOD_POST, null)); Lbryio.call("reward", "claim", options, Helper.METHOD_POST, null));
amountClaimed = Helper.getJSONDouble("reward_amount", 0, reward); amountClaimed = Helper.getJSONDouble("reward_amount", 0, reward);
@ -77,7 +61,7 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
amountClaimed == 1 ? 1 : 2, amountClaimed == 1 ? 1 : 2,
new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed)) : ""; new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed)) : "";
message = Helper.getJSONString("reward_notification", defaultMessage, reward); message = Helper.getJSONString("reward_notification", defaultMessage, reward);
} catch (ApiCallException | JSONException | LbryioRequestException | LbryioResponseException ex) { } catch (ApiCallException | LbryioRequestException | LbryioResponseException ex) {
error = ex; error = ex;
} }
@ -95,23 +79,6 @@ public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
} }
} }
private String fetchSingleClaimTxid(String claimType) throws ApiCallException, JSONException {
Map<String, Object> options = new HashMap<>();
options.put("claim_type", claimType);
options.put("page", 1);
options.put("page_size", 1);
options.put("resolve", true);
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_CLAIM_LIST, options);
JSONArray items = result.getJSONArray("items");
if (items.length() > 0) {
Claim claim = Claim.fromJSONObject(items.getJSONObject(0));
return claim.getTxid();
}
return null;
}
public interface ClaimRewardHandler { public interface ClaimRewardHandler {
void onSuccess(double amountClaimed, String message); void onSuccess(double amountClaimed, String message);
void onError(Exception error); void onError(Exception error);

View file

@ -1,23 +1,20 @@
package io.lbry.browser.tasks.lbryinc; package io.lbry.browser.tasks.lbryinc;
import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import io.lbry.browser.model.lbryinc.User; import io.lbry.browser.model.lbryinc.User;
import io.lbry.browser.utils.Lbryio; import io.lbry.browser.utils.Lbryio;
public class FetchCurrentUserTask extends AsyncTask<Void, Void, User> { public class FetchCurrentUserTask extends AsyncTask<Void, Void, User> {
private final Context context;
private Exception error; private Exception error;
private final FetchUserTaskHandler handler; private FetchUserTaskHandler handler;
public FetchCurrentUserTask(Context context, FetchUserTaskHandler handler) { public FetchCurrentUserTask(FetchUserTaskHandler handler) {
this.context = context;
this.handler = handler; this.handler = handler;
} }
protected User doInBackground(Void... params) { protected User doInBackground(Void... params) {
try { try {
return Lbryio.fetchCurrentUser(context); return Lbryio.fetchCurrentUser(null);
} catch (Exception ex) { } catch (Exception ex) {
error = ex; error = ex;
return null; return null;

Some files were not shown because too many files have changed in this diff Show more