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
app/google-services.json
app/twitter.properties
*.log
.vagrant
*.hprof
app/build
bin
app/debuglib

View file

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,3 +1,2 @@
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
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)
[![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" />
@ -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.
## Running from Source
Clone the repository and open the project in Android Studio. Android Studio will automatically run the initial build process.
Create file 'twitter.properties' in app/ folder with the following content:
```
twitterConsumerKey=XXXXXX
twitterConsumerSecret=XXXXXX
```
Copy the file 'google-services.sample.json' to 'google-services.json' in the app/ folder.
Click the Sync button and when process finishes, the Run button to launch the app on your simulator or connected debugging device after the build process is complete.
Please refer to https://github.com/lbryio/lbry-react-native/blob/master/README.md
## 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).
## 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
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'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
buildToolsVersion "29.0.1"
flavorDimensions "default"
compileOptions {
@ -16,14 +14,10 @@ android {
applicationId "io.lbry.browser"
minSdkVersion 21
targetSdkVersion 29
versionCode 1701
versionName "0.17.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
versionCode 1503
versionName "0.15.3"
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'lib/x86_64/darwin/libscrypt.dylib'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
productFlavors {
@ -42,17 +36,7 @@ android {
}
buildTypes {
debug {
Properties twitterProps = new Properties()
twitterProps.load(project.file('twitter.properties').newDataInputStream())
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
}
release {
Properties twitterProps = new Properties()
twitterProps.load(project.file('twitter.properties').newDataInputStream())
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
@ -65,49 +49,36 @@ task printVersionName {
}
}
configurations {
all {
exclude module: 'httpclient'
exclude module: 'commons-logging'
}
}
dependencies {
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 '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.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment:2.3.1'
implementation 'androidx.navigation:navigation-ui:2.3.1'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.2.2'
implementation 'androidx.navigation:navigation-ui:2.2.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.webkit:webkit:1.4.0-rc01'
implementation 'androidx.camera:camera-core:1.0.0-beta03'
implementation 'androidx.webkit:webkit:1.3.0-alpha02'
implementation 'androidx.camera:camera-camera2:1.0.0-beta03'
implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03'
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
implementation 'com.google.firebase:firebase-analytics:18.0.0'
implementation 'com.google.android.gms:play-services-base:17.5.0'
implementation 'com.google.firebase:firebase-messaging:21.0.0'
implementation 'com.google.oauth-client:google-oauth-client:1.30.4'
implementation 'com.android.billingclient:billing:3.0.2'
implementation 'com.google.firebase:firebase-analytics:17.4.0'
implementation 'com.google.android.gms:play-services-base:17.2.1'
implementation 'com.google.firebase:firebase-messaging:20.1.6'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.2'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.2'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.2'
implementation 'com.google.android.exoplayer:extension-cast:2.12.2'
implementation 'com.google.android.exoplayer:extension-mediasession:2.12.2'
implementation 'com.google.android.exoplayer:exoplayer-core:2.11.4'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.11.4'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.11.4'
implementation 'com.google.android.exoplayer:extension-cast:2.11.4'
implementation 'com.google.android.exoplayer:extension-mediasession:2.11.4'
implementation 'com.google.android:flexbox:2.0.1'
@ -118,27 +89,17 @@ dependencies {
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS'
implementation 'commons-codec:commons-codec:1.15'
implementation 'org.bitcoinj:bitcoinj-tools:0.14.7'
implementation 'org.java-websocket:Java-WebSocket:1.5.1'
implementation ('com.journeyapps:zxing-android-embedded:4.1.0') { transitive = false }
implementation 'com.google.zxing:core:3.3.0'
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test:rules:1.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
__32bitImplementation 'io.lbry:lbrysdk32:0.102.0'
__64bitImplementation 'io.lbry:lbrysdk64:0.102.0'
//__64bitImplementation(name: 'lbrysdk', ext: 'aar')
__32bitImplementation files('libs/lbrysdk-0.74.0-release__arm.aar')
__64bitImplementation files('libs/lbrysdk-0.74.0-release__arm64.aar')
}
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"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="io.lbry.browser"
android:installLocation="auto">
@ -11,10 +10,6 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
<application
android:allowBackup="true"
@ -55,38 +50,12 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="video/*" />
<data android:mimeType="image/*" />
<data android:mimeType="text/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="lbry" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="open.lbry.com"/>
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.tv" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.lat" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.fr" android:pathPattern="/.*#.*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/..*/*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*:.*" />
<data android:scheme="https" android:host="lbry.in" android:pathPattern="/.*#.*" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
@ -101,11 +70,6 @@
android:theme="@style/AppTheme.NoActionBarTranslucent"
android:windowSoftInputMode="adjustResize" />
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
<service
android:name="io.lbry.browser.LbrynetMessagingService"
android:exported="false">

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,8 +2,10 @@ package io.lbry.browser.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
@ -15,14 +17,15 @@ import io.lbry.browser.R;
import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.ui.controls.SolidIconView;
import io.lbry.browser.utils.Helper;
import lombok.Getter;
import lombok.Setter;
public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAdapter.ViewHolder> {
private static final int TYPE_GROUP = 1;
private static final int TYPE_ITEM = 2;
private final Context context;
private final List<NavMenuItem> menuItems;
private Context context;
private List<NavMenuItem> menuItems;
private NavMenuItem currentItem;
@Setter
private NavigationMenuItemClickListener listener;
@ -62,8 +65,8 @@ public class NavigationMenuAdapter extends RecyclerView.Adapter<NavigationMenuAd
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final SolidIconView iconView;
protected final TextView titleView;
protected SolidIconView iconView;
protected TextView titleView;
public ViewHolder(View v) {
super(v);
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_UNCLAIMED = 2;
private final Context context;
private Context context;
@Setter
private List<Reward> all;
private List<Reward> items;
@ -85,16 +85,16 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View iconClaimed;
protected final View loading;
protected final View upTo;
protected final TextView textTitle;
protected final TextView textDescription;
protected final TextView textLbcValue;
protected final TextView textUsdValue;
protected final TextView textLinkTransaction;
protected final EditText inputCustomCode;
protected final MaterialButton buttonClaimCustom;
protected View iconClaimed;
protected View loading;
protected View upTo;
protected TextView textTitle;
protected TextView textDescription;
protected TextView textLbcValue;
protected TextView textUsdValue;
protected TextView textLinkTransaction;
protected EditText inputCustomCode;
protected MaterialButton buttonClaimCustom;
public ViewHolder(View v) {
super(v);
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
@ -168,10 +168,6 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
return;
}
if (vh.inputCustomCode != null && !vh.inputCustomCode.hasFocus()) {
vh.inputCustomCode.requestFocus();
}
if (clickListener != null) {
clickListener.onRewardClicked(reward, vh.loading);
}

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;
public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedChannelGridAdapter.ViewHolder> {
private final Context context;
private final List<Claim> items;
private final List<Claim> selectedItems;
private Context context;
private List<Claim> items;
private List<Claim> selectedItems;
@Setter
private ChannelItemSelectionListener listener;
@ -35,11 +35,11 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final View noThumbnailView;
protected final ImageView thumbnailView;
protected final TextView alphaView;
protected final TextView titleView;
protected final TextView tagView;
protected View noThumbnailView;
protected ImageView thumbnailView;
protected TextView alphaView;
protected TextView titleView;
protected TextView tagView;
public ViewHolder(View v) {
super(v);
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
@ -89,8 +89,7 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
@Override
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) {
Claim claim = items.get(position);
ViewGroup.LayoutParams lp = vh.thumbnailView.getLayoutParams();
String thumbnailUrl = claim.getThumbnailUrl(lp.width, lp.height, 85);
String thumbnailUrl = claim.getThumbnailUrl();
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
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_REMOVE = 2;
private final Context context;
private Context context;
private List<Tag> items;
@Setter
private TagClickListener clickListener;
@Setter
@Getter
@Setter
private int customizeMode;
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 {
protected final ImageView iconView;
protected final TextView nameView;
protected ImageView iconView;
protected TextView nameView;
public ViewHolder(View v) {
super(v);
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 SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
private final Context context;
private final List<Transaction> items;
private Context context;
private List<Transaction> items;
@Setter
private TransactionClickListener listener;
@ -72,9 +72,7 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
vh.claimView.setText(item.getClaim());
vh.feeView.setText(context.getString(R.string.tx_list_fee, TX_LIST_AMOUNT_FORMAT.format(item.getFee().doubleValue())));
vh.txidLinkView.setText(item.getTxid().substring(0, 7));
vh.dateView.setVisibility(item.getConfirmations() > 0 ? View.VISIBLE : View.GONE);
vh.dateView.setText(item.getConfirmations() > 0 ? TX_LIST_DATE_FORMAT.format(item.getTxDate()) : null);
vh.pendingView.setVisibility(item.getConfirmations() == 0 ? View.VISIBLE : View.GONE);
vh.dateView.setText(TX_LIST_DATE_FORMAT.format(item.getTxDate()));
vh.infoFeeContainer.setVisibility(!Helper.isNullOrEmpty(item.getClaim()) || Math.abs(item.getFee().doubleValue()) > 0 ?
View.VISIBLE : View.GONE);
@ -107,14 +105,13 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected final TextView descView;
protected final TextView amountView;
protected final TextView claimView;
protected final TextView feeView;
protected final TextView txidLinkView;
protected final TextView dateView;
protected final TextView pendingView;
protected final View infoFeeContainer;
protected TextView descView;
protected TextView amountView;
protected TextView claimView;
protected TextView feeView;
protected TextView txidLinkView;
protected TextView dateView;
protected View infoFeeContainer;
public ViewHolder(View v) {
super(v);
@ -124,7 +121,6 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
feeView = v.findViewById(R.id.transaction_fee);
txidLinkView = v.findViewById(R.id.transaction_id_link);
dateView = v.findViewById(R.id.transaction_date);
pendingView = v.findViewById(R.id.transaction_pending_text);
infoFeeContainer = v.findViewById(R.id.transaction_info_fee_container);
}
}

View file

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

View file

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

View file

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

View file

@ -57,8 +57,8 @@ public class ContentSortDialogFragment extends BottomSheetDialogFragment {
private final int[] checkViewIds = {
R.id.sort_by_trending_item_selected, R.id.sort_by_new_item_selected, R.id.sort_by_top_item_selected
};
private final BottomSheetDialogFragment dialog;
private final SortByListener listener;
private BottomSheetDialogFragment dialog;
private SortByListener listener;
public SortByItemClickListener(BottomSheetDialogFragment dialog, SortByListener listener) {
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;
}
private final TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
private TagListAdapter.TagClickListener customizeTagClickListener = new TagListAdapter.TagClickListener() {
@Override
public void onTagClicked(Tag tag, int customizeMode) {
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {

View file

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

View file

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

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 onPhoneVerified();
void onManualVerifyContinue();
void onSkipQueueAction();
void onTwitterVerified();
void onManualProgress(boolean progress);
}

View file

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

View file

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

View file

@ -1,15 +1,19 @@
package io.lbry.browser.model;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
public class ClaimSearchCacheValue {
@Getter
private final List<Claim> claims;
@Setter
private List<Claim> claims;
@Getter
private final long timestamp;
@Setter
private long timestamp;
public ClaimSearchCacheValue(List<Claim> claims, long timestamp) {
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
public class Language {
private final String code;
private final String name;
private final int stringResourceId;
private String code;
private String name;
private int stringResourceId;
public Language(String code, String name, int stringResourceId) {
this.code = code;

View file

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

View file

@ -2,6 +2,8 @@ package io.lbry.browser.model;
import android.content.Context;
import androidx.core.content.res.ResourcesCompat;
import java.util.ArrayList;
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_EDITORS_CHOICE = 102;
public static final int ID_ITEM_ALL_CONTENT = 103;
public static final int ID_ITEM_SHUFFLE = 104;
// Your Content
public static final int ID_ITEM_CHANNELS = 201;
@ -35,8 +36,8 @@ public class NavMenuItem {
public static final int ID_ITEM_SETTINGS = 401;
public static final int ID_ITEM_ABOUT = 402;
private final Context context;
private final int id;
private Context context;
private int id;
private boolean group;
private int icon;
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 java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.exceptions.LbryUriException;
@ -55,22 +53,13 @@ public class Transaction {
int descStringId = -1;
TransactionInfo info = null;
List<TransactionInfo> infos = new ArrayList<>();
try {
if (jsonObject.has("abandon_info")) {
JSONArray array = jsonObject.getJSONArray("abandon_info");
if (array.length() > 0) {
if (array.length() == 1) {
info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
descStringId = info.getBalanceDelta().doubleValue() == info.getAmount().doubleValue() ? R.string.unlock : R.string.abandon;
descStringId = R.string.abandon;
transaction.setAbandonInfo(info);
} else {
// multiple abandon infos (txo_spend unlock tip)
descStringId = R.string.unlock;
for (int i = 0; i < array.length(); i++) {
infos.add(TransactionInfo.fromJSONObject(array.getJSONObject(i)));
}
}
}
}
if (info == null && jsonObject.has("claim_info")) {
@ -105,18 +94,8 @@ public class Transaction {
// pass
}
if (transaction.getValue().doubleValue() == 0) {
if (info != null && info.getBalanceDelta().doubleValue() != 0) {
if (transaction.getValue().doubleValue() == 0 && 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) {

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.util.Date;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import lombok.Data;
@Data

View file

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

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;
import lombok.Data;
import lombok.Getter;
@Data
public class WalletSync {
@Getter
private final String hash;
@Getter
private final String data;
@Getter
private String hash;
private String data;
private boolean changed;
public WalletSync(String hash, String data) {
@ -21,5 +17,4 @@ public class WalletSync {
this(hash, data);
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 io.lbry.browser.model.Claim;
import io.lbry.browser.utils.Helper;
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
@Setter
private String url;
@Getter
@Setter
private boolean isNotificationsDisabled;
public Subscription() {
}
public Subscription(String channelName, String url, boolean isNotificationsDisabled) {
public Subscription(String channelName, String url) {
this.channelName = channelName;
this.url = url;
this.isNotificationsDisabled = isNotificationsDisabled;
}
public static Subscription fromClaim(Claim claim) {
return new Subscription(claim.getName(), claim.getPermanentUrl(), false);
return new Subscription(claim.getName(), claim.getPermanentUrl());
}
public String toString() {
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;
public class FollowUnfollowTagTask extends AsyncTask<Void, Void, Boolean> {
private final Tag tag;
private final boolean unfollowing;
private final Context context;
private final FollowUnfollowTagHandler handler;
private Tag tag;
private boolean unfollowing;
private Context context;
private FollowUnfollowTagHandler handler;
private Exception error;
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;
public class LighthouseAutoCompleteTask extends AsyncTask<Void, Void, List<UrlSuggestion>> {
private final String text;
private final AutoCompleteResultHandler handler;
private final View progressView;
private String text;
private AutoCompleteResultHandler handler;
private View progressView;
private Exception error;
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;
public class LighthouseSearchTask extends AsyncTask<Void, Void, List<Claim>> {
private final String rawQuery;
private final int size;
private final int from;
private final boolean nsfw;
private final String relatedTo;
private final ClaimSearchResultHandler handler;
private final ProgressBar progressBar;
private String rawQuery;
private int size;
private int from;
private boolean nsfw;
private String relatedTo;
private ClaimSearchResultHandler handler;
private ProgressBar progressBar;
private Exception error;
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.SQLiteException;
import android.os.AsyncTask;
import android.view.View;
import android.widget.ProgressBar;
import java.util.List;
import io.lbry.browser.MainActivity;
import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.exceptions.LbryRequestException;
import io.lbry.browser.exceptions.LbryResponseException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.Tag;
import io.lbry.browser.utils.Helper;
public class LoadTagsTask extends AsyncTask<Void, Void, List<Tag>> {
private final Context context;
private final LoadTagsHandler handler;
private Context context;
private LoadTagsHandler handler;
private Exception error;
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.SQLiteException;
import android.os.AsyncTask;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
@ -16,25 +17,26 @@ import java.util.Map;
import io.lbry.browser.MainActivity;
import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import okhttp3.Response;
// background task to create a diff of local and remote subscriptions and try to merge
public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscription>> {
private static final String TAG = "MergeSubscriptionsTask";
private final Context context;
private final List<Subscription> base;
private Context context;
private List<Subscription> base;
private List<Subscription> diff;
private final MergeSubscriptionsHandler handler;
private MergeSubscriptionsHandler handler;
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.replaceLocal = replaceLocal;
this.context = context;
this.handler = handler;
}
@ -51,12 +53,6 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
db = ((MainActivity) context).getDbHelper().getWritableDatabase();
}
if (db != null) {
if (replaceLocal) {
DatabaseHelper.clearSubscriptions(db);
for (Subscription sub : base) {
DatabaseHelper.createOrUpdateSubscription(sub, db);
}
} else {
localSubs = DatabaseHelper.getSubscriptions(db);
for (Subscription sub : localSubs) {
if (!combined.contains(sub)) {
@ -64,55 +60,48 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
}
}
}
}
// fetch remote subscriptions
JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("subscription", "list", context));
if (array != null) {
// check for any remote subs that may have been removed, and unsubscribe from them
for (int i = 0; i < array.length(); i++) {
JSONObject item = array.getJSONObject(i);
// TODO: Refactor by creating static Subscription.fromJSON method
String claimId = item.getString("claim_id");
String channelName = item.getString("channel_name");
boolean isNotificationsDisabled = item.getBoolean("is_notifications_disabled");
LbryUri url = new LbryUri();
url.setChannelName(channelName);
url.setClaimId(claimId);
Subscription subscription = new Subscription(channelName, url.toString(), isNotificationsDisabled);
Subscription subscription = new Subscription(channelName, url.toString());
remoteSubs.add(subscription);
}
}
List<Subscription> remoteUnsubs = new ArrayList<>();
List<Subscription> finalRemoteSubs = new ArrayList<>();
if (remoteSubs.size() > 0) {
for (int i = 0; i < remoteSubs.size(); i++) {
Subscription sub = remoteSubs.get(i);
if (!combined.contains(sub)) {
for (int i = 0; i < combined.size(); i++) {
Subscription local = combined.get(i);
if (!remoteSubs.contains(local)) {
// add to remote subscriptions
try {
LbryUri uri = LbryUri.parse(local.getUrl());
Map<String, String> options = new HashMap<>();
LbryUri uri = LbryUri.tryParse(sub.getUrl());
if (uri != null) {
options.put("claim_id", uri.getChannelClaimId());
Lbryio.parseResponse(Lbryio.call("subscription", "delete", options, context));
remoteUnsubs.add(sub);
} else {
finalRemoteSubs.add(sub);
}
options.put("channel_name", Helper.normalizeChannelName(local.getChannelName()));
Lbryio.parseResponse(Lbryio.call("subscription", "new", options, context));
} catch (LbryUriException | LbryioRequestException | LbryioResponseException ex) {
// pass
Log.e(TAG, String.format("subscription/new failed: %s", ex.getMessage()), ex);
}
}
}
if (!replaceLocal) {
for (int i = 0; i < localSubs.size(); i++) {
Subscription local = localSubs.get(i);
if (!base.contains(local) && !diff.contains(local)) {
diff.add(local);
}
}
for (int i = 0; i < finalRemoteSubs.size(); i++) {
Subscription remote = finalRemoteSubs.get(i);
for (int i = 0; i < remoteSubs.size(); i++) {
Subscription remote = remoteSubs.get(i);
if (!combined.contains(remote)) {
combined.add(remote);
if (!diff.contains(remote)) {
@ -120,7 +109,6 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
}
}
}
}
} catch (ClassCastException | LbryioRequestException | LbryioResponseException | JSONException | IllegalStateException | SQLiteException ex) {
error = ex;
return null;

View file

@ -4,15 +4,18 @@ import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.Buffer;
import io.lbry.browser.utils.Helper;
public class ReadTextFileTask extends AsyncTask<Void, Void, String> {
private final String filePath;
private String filePath;
private Exception error;
private final ReadTextFileHandler handler;
private ReadTextFileHandler handler;
public ReadTextFileTask(String filePath, ReadTextFileHandler handler) {
this.filePath = filePath;
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;
public class SetSdkSettingTask extends AsyncTask<Void, Void, Boolean> {
private final String key;
private final String value;
private final GenericTaskHandler handler;
private String key;
private String value;
private GenericTaskHandler handler;
private Exception error;
public SetSdkSettingTask(String key, String value, GenericTaskHandler handler) {
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>> {
private final boolean clearPrevious;
private final boolean excludeMature;
private final int limit;
private final String filter;
private final TagListAdapter addedTagsAdapter;
private final TagListAdapter suggestedTagsAdapter;
private final KnownTagsHandler handler;
private boolean clearPrevious;
private boolean excludeMature;
private int limit;
private String filter;
private TagListAdapter addedTagsAdapter;
private TagListAdapter suggestedTagsAdapter;
private KnownTagsHandler handler;
public UpdateSuggestedTagsTask(
String filter,
@ -45,7 +45,6 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
if (suggestedTagsAdapter != null && !clearPrevious) {
tags = new ArrayList<>(suggestedTagsAdapter.getTags());
}
if (Lbry.knownTags.size() > 0) {
while (tags.size() < limit) {
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
if (excludeMature && randomTag.isMature()) {
@ -55,7 +54,6 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
tags.add(randomTag);
}
}
}
} else {
Tag filterTag = new Tag(filter);
if (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(filterTag)) {
@ -66,16 +64,11 @@ public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
if (excludeMature && knownTag.isMature()) {
continue;
}
try {
if ((knownTag.getLowercaseName().startsWith(filter) ||
knownTag.getLowercaseName().matches(filter)) &&
(!tags.contains(knownTag) && !Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag)))
) {
if ((knownTag.getLowercaseName().startsWith(filter) || knownTag.getLowercaseName().matches(filter)) &&
(!tags.contains(knownTag) &&
!Lbry.followedTags.contains(knownTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(knownTag)))) {
tags.add(knownTag);
}
} catch (Exception ex) {
// continue
}
}
}
return tags;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,10 +13,10 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
private final List<String> urls;
private final String connectionString;
private final ClaimListResultHandler handler;
private final View progressView;
private List<String> urls;
private String connectionString;
private ClaimListResultHandler handler;
private View progressView;
private ApiCallException error;
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;
public class StreamRepostTask extends AsyncTask<Void, Void, Claim> {
private final String name;
private final BigDecimal bid;
private final String claimId;
private final String channelId;
private final View progressView;
private final ClaimResultHandler handler;
private String name;
private BigDecimal bid;
private String claimId;
private String channelId;
private View progressView;
private ClaimResultHandler handler;
private Exception error;
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 io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Lbry;
// Just run delete on the specified claim IDs (no need for a handler)
public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> {
private final List<String> claimIds;
private List<String> claimIds;
public BulkDeleteFilesTask(List<String> claimIds) {
this.claimIds = claimIds;
}

View file

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

View file

@ -11,12 +11,12 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
private final String claimId;
private String claimId;
private boolean downloads;
private int page;
private int pageSize;
private final FileListResultHandler handler;
private final View progressView;
private FileListResultHandler handler;
private View progressView;
private ApiCallException error;
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;
public class GetFileTask extends AsyncTask<Void, Void, LbryFile> {
private final String uri;
private final boolean saveFile;
private final View progressView;
private final GetFileHandler handler;
private String uri;
private boolean saveFile;
private View progressView;
private GetFileHandler handler;
private Exception error;
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.LbryioResponseException;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbryio;
public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
private final Context context;
private final String channelClaimId;
private final Subscription subscription;
private final ChannelSubscribeHandler handler;
private Context context;
private String channelClaimId;
private Subscription subscription;
private ChannelSubscribeHandler handler;
private Exception error;
private final boolean isUnsubscribing;
private boolean isUnsubscribing;
public ChannelSubscribeTask(Context context, String channelClaimId, Subscription subscription, boolean isUnsubscribing, ChannelSubscribeHandler handler) {
this.context = context;
@ -50,11 +51,11 @@ public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
options.put("claim_id", channelClaimId);
if (!isUnsubscribing) {
options.put("channel_name", subscription.getChannelName());
options.put("notifications_disabled", String.valueOf(subscription.isNotificationsDisabled()).toLowerCase());
}
String action = isUnsubscribing ? "delete" : "new";
Object response = Lbryio.parseResponse(Lbryio.call("subscription", action, options, context));
Lbryio.call("subscription", action, options, context);
if (!isUnsubscribing) {
Lbryio.addSubscription(subscription);
} else {

View file

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

View file

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

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