sdk 0.74.0. Publish and Publishes pages.

This commit is contained in:
Akinwale Ariwodola 2020-05-19 15:56:24 +01:00
parent 314e6be77e
commit 3e032a0f9d
47 changed files with 1623 additions and 192 deletions

View file

@ -62,6 +62,10 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.preference:preference:1.1.1'
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 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
implementation 'com.google.firebase:firebase-analytics:17.4.0'
@ -91,8 +95,8 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
__32bitImplementation files('libs/lbrysdk-0.73.1-release__arm.aar')
__64bitImplementation files('libs/lbrysdk-0.73.1-release__arm64.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'

View file

@ -3,11 +3,12 @@
package="io.lbry.browser"
android:installLocation="auto">
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application

View file

@ -16,7 +16,6 @@ import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
@ -30,7 +29,6 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
@ -96,6 +94,7 @@ import io.lbry.browser.adapter.UrlSuggestionListAdapter;
import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.dialog.ContentScopeDialogFragment;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.listener.CameraPermissionListener;
import io.lbry.browser.listener.DownloadActionListener;
import io.lbry.browser.listener.FetchChannelsListener;
import io.lbry.browser.listener.SdkStatusListener;
@ -133,6 +132,8 @@ import io.lbry.browser.ui.following.FileViewFragment;
import io.lbry.browser.ui.following.FollowingFragment;
import io.lbry.browser.ui.library.LibraryFragment;
import io.lbry.browser.ui.other.AboutFragment;
import io.lbry.browser.ui.publish.PublishFragment;
import io.lbry.browser.ui.publish.PublishesFragment;
import io.lbry.browser.ui.search.SearchFragment;
import io.lbry.browser.ui.other.SettingsFragment;
import io.lbry.browser.ui.allcontent.AllContentFragment;
@ -164,7 +165,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static Claim nowPlayingClaim;
public static boolean startingFilePickerActivity = false;
public static boolean startingShareActivity = false;
public static boolean startingStoragePermissionRequest = false;
public static boolean startingPermissionRequest = false;
public static boolean startingSignInFlowActivity = false;
private boolean enteringPIPMode = false;
private boolean fullSyncInProgress = false;
@ -185,8 +186,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
fragmentClassNavIdMap.put(EditorsChoiceFragment.class, NavMenuItem.ID_ITEM_EDITORS_CHOICE);
fragmentClassNavIdMap.put(AllContentFragment.class, NavMenuItem.ID_ITEM_ALL_CONTENT);
fragmentClassNavIdMap.put(PublishFragment.class, NavMenuItem.ID_ITEM_NEW_PUBLISH);
fragmentClassNavIdMap.put(ChannelManagerFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
fragmentClassNavIdMap.put(LibraryFragment.class, NavMenuItem.ID_ITEM_LIBRARY);
fragmentClassNavIdMap.put(PublishesFragment.class, NavMenuItem.ID_ITEM_PUBLISHES);
fragmentClassNavIdMap.put(WalletFragment.class, NavMenuItem.ID_ITEM_WALLET);
fragmentClassNavIdMap.put(RewardsFragment.class, NavMenuItem.ID_ITEM_REWARDS);
@ -202,6 +205,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
public static final int REQUEST_STORAGE_PERMISSION = 1001;
public static final int REQUEST_CAMERA_PERMISSION = 1002;
public static final int REQUEST_SIMPLE_SIGN_IN = 2001;
public static final int REQUEST_WALLET_SYNC_SIGN_IN = 2002;
public static final int REQUEST_REWARDS_VERIFY_SIGN_IN = 2003;
@ -270,6 +274,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Getter
private DatabaseHelper dbHelper;
private int selectedMenuItemId = -1;
private List<CameraPermissionListener> cameraPermissionListeners;
private List<DownloadActionListener> downloadActionListeners;
private List<SdkStatusListener> sdkStatusListeners;
private List<StoragePermissionListener> storagePermissionListeners;
@ -296,25 +301,6 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private static final int STARTUP_STAGE_SUBSCRIPTIONS_LOADED = 6;
private static final int STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED = 7;
private final List<Integer> supportedMenuItemIds = Arrays.asList(
// find content
NavMenuItem.ID_ITEM_FOLLOWING,
NavMenuItem.ID_ITEM_EDITORS_CHOICE,
NavMenuItem.ID_ITEM_ALL_CONTENT,
// your content
NavMenuItem.ID_ITEM_CHANNELS,
NavMenuItem.ID_ITEM_LIBRARY,
// wallet
NavMenuItem.ID_ITEM_WALLET,
NavMenuItem.ID_ITEM_REWARDS,
NavMenuItem.ID_ITEM_INVITES,
NavMenuItem.ID_ITEM_SETTINGS,
NavMenuItem.ID_ITEM_ABOUT
);
public boolean isDarkMode() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
return sp.getBoolean(PREFERENCE_KEY_DARK_MODE, false);
@ -391,6 +377,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
// other
pendingSyncSetQueue = new ArrayList<>();
openNavFragments = new HashMap<>();
cameraPermissionListeners = new ArrayList<>();
downloadActionListeners = new ArrayList<>();
sdkStatusListeners = new ArrayList<>();
storagePermissionListeners = new ArrayList<>();
@ -468,13 +455,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
return;
}
if (!supportedMenuItemIds.contains(menuItem.getId())) {
Snackbar.make(navItemsView, R.string.not_yet_implemented, Snackbar.LENGTH_LONG).show();
} else {
navMenuAdapter.setCurrentItem(menuItem);
shouldOpenUserSelectedMenuItem = true;
selectedMenuItemId = menuItem.getId();
}
closeDrawer();
}
});
@ -496,8 +479,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
specialRouteFragmentClassMap.put("invite", InvitesFragment.class);
specialRouteFragmentClassMap.put("invites", InvitesFragment.class);
specialRouteFragmentClassMap.put("library", LibraryFragment.class);
//specialRouteFragmentClassMap.put("publish", PublishFragment.class);
//specialRouteFragmentClassMap.put("publishes", PublishesFragment.class);
specialRouteFragmentClassMap.put("publish", PublishFragment.class);
specialRouteFragmentClassMap.put("publishes", PublishesFragment.class);
specialRouteFragmentClassMap.put("following", FollowingFragment.class);
specialRouteFragmentClassMap.put("rewards", RewardsFragment.class);
specialRouteFragmentClassMap.put("settings", SettingsFragment.class);
@ -512,6 +495,16 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
checkNotificationOpenIntent(intent);
}
public void addCameraPermissionListener(CameraPermissionListener listener) {
if (!cameraPermissionListeners.contains(listener)) {
cameraPermissionListeners.add(listener);
}
}
public void removeCameraPermissionListener(CameraPermissionListener listener) {
cameraPermissionListeners.remove(listener);
}
public void addDownloadActionListener(DownloadActionListener listener) {
if (!downloadActionListeners.contains(listener)) {
downloadActionListeners.add(listener);
@ -581,12 +574,18 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
openFragment(AllContentFragment.class, true, NavMenuItem.ID_ITEM_ALL_CONTENT);
break;
case NavMenuItem.ID_ITEM_NEW_PUBLISH:
openFragment(PublishFragment.class, true, NavMenuItem.ID_ITEM_NEW_PUBLISH);
break;
case NavMenuItem.ID_ITEM_CHANNELS:
openFragment(ChannelManagerFragment.class, true, NavMenuItem.ID_ITEM_CHANNELS);
break;
case NavMenuItem.ID_ITEM_LIBRARY:
openFragment(LibraryFragment.class, true, NavMenuItem.ID_ITEM_LIBRARY);
break;
case NavMenuItem.ID_ITEM_PUBLISHES:
openFragment(PublishesFragment.class, true, NavMenuItem.ID_ITEM_PUBLISHES);
break;
case NavMenuItem.ID_ITEM_WALLET:
openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET);
@ -818,6 +817,20 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
super.onPause();
}
public static void suspendGlobalPlayer(Context context) {
if (MainActivity.appPlayer != null) {
MainActivity.appPlayer.setPlayWhenReady(false);
}
if (context instanceof MainActivity) {
((MainActivity) context).hideGlobalNowPlaying();
}
}
public static void resumeGlobalPlayer(Context context) {
if (context instanceof MainActivity) {
((MainActivity) context).checkNowPlaying();
}
}
private void toggleUrlSuggestions(boolean visible) {
View container = findViewById(R.id.url_suggestions_container);
View closeIcon = findViewById(R.id.wunderbar_close);
@ -830,7 +843,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public int getScaledValue(int value) {
float scale = getResources().getDisplayMetrics().density;
return (int) (value * scale + 0.5f);
return Helper.getScaledValue(value, scale);
}
private void setupUriBar() {
@ -1249,6 +1262,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
startup();
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
openFragment(FollowingFragment.class, false, NavMenuItem.ID_ITEM_FOLLOWING);
fetchRewards();
}
}
@ -1340,7 +1354,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
if (navMenuAdapter != null) {
navMenuAdapter.setExtraLabelForItem(
NavMenuItem.ID_ITEM_WALLET,
Lbryio.LBCUSDRate > 0 ? String.format("$%s", Helper.USD_CURRENCY_FORMAT.format(usdBalance)) : null
Lbryio.LBCUSDRate > 0 ? String.format("$%s", Helper.SIMPLE_CURRENCY_FORMAT.format(usdBalance)) : null
);
}
}
@ -1750,9 +1764,21 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
listener.onStoragePermissionRefused();
}
}
startingStoragePermissionRequest = false;
startingPermissionRequest = false;
break;
case REQUEST_CAMERA_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
for (CameraPermissionListener listener : cameraPermissionListeners) {
listener.onCameraPermissionGranted();
}
} else {
for (CameraPermissionListener listener : cameraPermissionListeners) {
listener.onCameraPermissionRefused();
}
}
startingPermissionRequest = false;
break;
}
}
@ -2015,7 +2041,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
if (navMenuAdapter != null) {
navMenuAdapter.setExtraLabelForItem(
NavMenuItem.ID_ITEM_REWARDS,
Lbryio.LBCUSDRate > 0 ? String.format("$%s", Helper.USD_CURRENCY_FORMAT.format(usdRewardAmount)) : null
Lbryio.LBCUSDRate > 0 ? String.format("$%s", Helper.SIMPLE_CURRENCY_FORMAT.format(usdRewardAmount)) : null
);
}
}
@ -2115,7 +2141,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}, 1000);
return;
}
if (startingStoragePermissionRequest) {
if (startingPermissionRequest) {
return;
}
enterPIPMode();
@ -2241,10 +2267,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
));
yourContentGroup.setItems(Arrays.asList(
//new NavMenuItem(NavMenuItem.ID_ITEM_NEW_PUBLISH, R.string.fa_upload, R.string.new_publish, "NewPublish", context),
new NavMenuItem(NavMenuItem.ID_ITEM_NEW_PUBLISH, R.string.fa_upload, R.string.new_publish, "NewPublish", context),
new NavMenuItem(NavMenuItem.ID_ITEM_CHANNELS, R.string.fa_at, R.string.channels, "Channels", context),
new NavMenuItem(NavMenuItem.ID_ITEM_LIBRARY, R.string.fa_download, R.string.library, "Library", context)
//new NavMenuItem(NavMenuItem.ID_ITEM_PUBLISHES, R.string.fa_cloud_upload, R.string.publishes, "Publishes", context)
new NavMenuItem(NavMenuItem.ID_ITEM_LIBRARY, R.string.fa_download, R.string.library, "Library", context),
new NavMenuItem(NavMenuItem.ID_ITEM_PUBLISHES, R.string.fa_cloud_upload, R.string.publishes, "Publishes", context)
));
walletGroup.setItems(Arrays.asList(
@ -2518,7 +2544,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
if (!forceRequest && ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission)) {
Toast.makeText(context, rationale, Toast.LENGTH_LONG).show();
} else {
startingStoragePermissionRequest = true;
startingPermissionRequest = true;
ActivityCompat.requestPermissions((Activity) context, new String[] { permission }, requestCode);
}
}

View file

@ -96,6 +96,14 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
return new ArrayList<>(this.items);
}
public void updateSigningChannelForClaim(Claim resolvedClaim) {
for (Claim claim : items) {
if (claim.getClaimId().equalsIgnoreCase(resolvedClaim.getClaimId())) {
claim.setSigningChannel(resolvedClaim.getSigningChannel());
}
}
}
public void clearItems() {
clearSelectedItems();
this.items.clear();
@ -413,7 +421,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
boolean isDownloading = false;
int progress = 0;
String fileSizeString = claimFile == null ? null : Helper.formatBytes(claimFile.getTotalBytes(), false);
if (claimFile != null && !claimFile.isCompleted() && claimFile.getWrittenBytes() < claimFile.getTotalBytes()) {
if (claimFile != null &&
!Helper.isNullOrEmpty(claimFile.getDownloadPath()) &&
!claimFile.isCompleted() &&
claimFile.getWrittenBytes() < claimFile.getTotalBytes()) {
isDownloading = true;
progress = claimFile.getTotalBytes() > 0 ?
Double.valueOf(((double) claimFile.getWrittenBytes() / (double) claimFile.getTotalBytes()) * 100.0).intValue() : 0;

View file

@ -0,0 +1,122 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.listener.ChannelItemSelectionListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.GalleryItem;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class GalleryGridAdapter extends RecyclerView.Adapter<GalleryGridAdapter.ViewHolder> {
private Context context;
private List<GalleryItem> items;
@Setter
private GalleryItemClickListener listener;
public GalleryGridAdapter(List<GalleryItem> items, Context context) {
this.items = new ArrayList<>(items);
this.context = context;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected ImageView thumbnailView;
protected TextView durationView;
public ViewHolder(View v) {
super(v);
thumbnailView = v.findViewById(R.id.gallery_item_thumbnail);
durationView = v.findViewById(R.id.gallery_item_duration);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public void addItem(GalleryItem item) {
if (!items.contains(item)) {
items.add(item);
notifyDataSetChanged();
}
}
public void addItems(List<GalleryItem> items) {
for (GalleryItem item : items) {
if (!this.items.contains(item)) {
this.items.add(item);
notifyDataSetChanged();
}
}
}
public void clearItems() {
items.clear();
notifyDataSetChanged();
}
@Override
public GalleryGridAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_gallery, root, false);
return new GalleryGridAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(GalleryGridAdapter.ViewHolder vh, int position) {
GalleryItem item = items.get(position);
String thumbnailUrl = item.getThumbnailUrl();
Glide.with(context.getApplicationContext()).load(thumbnailUrl).centerCrop().into(vh.thumbnailView);
vh.durationView.setVisibility(item.getDuration() > 0 ? View.VISIBLE : View.INVISIBLE);
vh.durationView.setText(item.getDuration() > 0 ? Helper.formatDuration(Double.valueOf(item.getDuration() / 1000.0).longValue()) : null);
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onGalleryItemClicked(item);
}
}
});
}
public interface GalleryItemClickListener {
void onGalleryItemClicked(GalleryItem item);
}
public static class GalleryGridItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
public GalleryGridItemDecoration(int spanCount, int spacing) {
this.spanCount = spanCount;
this.spacing = spacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item position
int column = position % spanCount; // item column
outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing; // item top
}
}
}
}

View file

@ -159,7 +159,7 @@ public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.Vi
});
vh.textUsdValue.setText(reward.isCustom() || Lbryio.LBCUSDRate == 0 ? null :
String.format("≈$%s", Helper.USD_CURRENCY_FORMAT.format(rewardAmount * Lbryio.LBCUSDRate)));
String.format("≈$%s", Helper.SIMPLE_CURRENCY_FORMAT.format(rewardAmount * Lbryio.LBCUSDRate)));
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override

View file

@ -22,7 +22,7 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri;
public class DatabaseHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 2;
public static final String DATABASE_NAME = "LbryApp.db";
private static DatabaseHelper instance;
@ -40,6 +40,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
", claim_id TEXT" +
", claim_name TEXT" +
", cost REAL " +
", currency TEXT " +
", title TEXT " +
", publisher_claim_id TEXT" +
", publisher_name TEXT" +
@ -58,6 +59,10 @@ public class DatabaseHelper extends SQLiteOpenHelper {
"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_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 FROM subscriptions";
@ -68,9 +73,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
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_VIEW_HISTORY =
"REPLACE INTO view_history (url, claim_id, claim_name, cost, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
"REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String SQL_GET_VIEW_HISTORY =
"SELECT url, claim_id, claim_name, cost, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp " +
"SELECT url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp " +
"FROM view_history WHERE '' = ? OR timestamp < ? ORDER BY timestamp DESC LIMIT %d";
private static final String SQL_CLEAR_VIEW_HISTORY = "DELETE FROM view_history";
private static final String SQL_CLEAR_VIEW_HISTORY_BY_DEVICE = "DELETE FROM view_history WHERE device = ?";
@ -82,6 +87,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private static final String SQL_UNFOLLOW_TAGS = "UPDATE tags SET is_followed = 0";
private static final String SQL_GET_FOLLOWED_TAGS = "SELECT name FROM tags WHERE is_followed = 1";
public DatabaseHelper(Context context) {
super(context, String.format("%s/%s", context.getFilesDir().getAbsolutePath(), DATABASE_NAME), null, DATABASE_VERSION);
instance = this;
@ -98,7 +105,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
}
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
for (String sql : SQL_V1_V2_UPGRADE) {
db.execSQL(sql);
}
}
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
@ -142,6 +153,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
viewHistory.getClaimId(),
viewHistory.getClaimName(),
viewHistory.getCost() != null ? viewHistory.getCost().doubleValue() : 0,
viewHistory.getCurrency(),
viewHistory.getTitle(),
viewHistory.getPublisherClaimId(),
viewHistory.getPublisherName(),
@ -166,6 +178,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
item.setClaimId(cursor.getString(cursorIndex++));
item.setClaimName(cursor.getString(cursorIndex++));
item.setCost(new BigDecimal(cursor.getDouble(cursorIndex++)));
item.setCurrency(cursor.getString(cursorIndex++));
item.setTitle(cursor.getString(cursorIndex++));
item.setPublisherClaimId(cursor.getString(cursorIndex++));
item.setPublisherName(cursor.getString(cursorIndex++));

View file

@ -0,0 +1,8 @@
package io.lbry.browser.listener;
public interface CameraPermissionListener {
void onCameraPermissionGranted();
void onCameraPermissionRefused();
void onRecordAudioPermissionGranted();
void onRecordAudioPermissionRefused();
}

View file

@ -0,0 +1,13 @@
package io.lbry.browser.model;
import lombok.Data;
@Data
public class GalleryItem {
private String id;
private String name;
private String filePath;
private String type;
private String thumbnailUrl;
private long duration;
}

View file

@ -8,6 +8,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -18,13 +19,16 @@ import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
private String type;
private List<String> types;
private View progressView;
private ClaimListResultHandler handler;
private Exception error;
public ClaimListTask(String type, View progressView, ClaimListResultHandler handler) {
this.type = type;
this(Arrays.asList(type), progressView, handler);
}
public ClaimListTask(List<String> types, View progressView, ClaimListResultHandler handler) {
this.types = types;
this.progressView = progressView;
this.handler = handler;
}
@ -36,8 +40,8 @@ public class ClaimListTask extends AsyncTask<Void, Void, List<Claim>> {
try {
Map<String, Object> options = new HashMap<>();
if (!Helper.isNullOrEmpty(type)) {
options.put("claim_type", type);
if (types != null && types.size() > 0) {
options.put("claim_type", types);
}
options.put("page", 1);
options.put("page_size", 999);

View file

@ -0,0 +1,137 @@
package io.lbry.browser.tasks.localdata;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.model.GalleryItem;
import io.lbry.browser.utils.Helper;
public class LoadGalleryItemsTask extends AsyncTask<Void, GalleryItem, List<GalleryItem>> {
private static final String TAG = "LoadGalleryItemsTask";
private LoadGalleryHandler handler;
private View progressView;
private Context context;
public LoadGalleryItemsTask(View progressView, Context context, LoadGalleryHandler handler) {
this.progressView = progressView;
this.context = context;
this.handler = handler;
}
protected void onPreExecute(Void... params) {
Helper.setViewVisibility(progressView, View.VISIBLE);
}
protected List<GalleryItem> doInBackground(Void... params) {
List<GalleryItem> items = new ArrayList<>();
List<GalleryItem> itemsWithThumbnails = new ArrayList<>();
Cursor cursor = null;
if (context != null) {
ContentResolver resolver = context.getContentResolver();
try {
String[] projection = {
MediaStore.MediaColumns._ID,
MediaStore.MediaColumns.DATA,
MediaStore.MediaColumns.DISPLAY_NAME,
MediaStore.MediaColumns.MIME_TYPE,
MediaStore.Video.Media.DURATION
};
cursor = resolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection, null, null,
String.format("%s DESC", MediaStore.MediaColumns.DATE_MODIFIED));
while (cursor.moveToNext()) {
int idColumn = cursor.getColumnIndex(MediaStore.MediaColumns._ID);
int nameColumn = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
int typeColumn = cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE);
int pathColumn = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
int durationColumn = cursor.getColumnIndex(MediaStore.Video.Media.DURATION);
String id = cursor.getString(idColumn);
GalleryItem item = new GalleryItem();
item.setId(id);
item.setName(cursor.getString(nameColumn));
item.setType(cursor.getString(typeColumn));
item.setFilePath(cursor.getString(pathColumn));
item.setDuration(cursor.getLong(durationColumn));
items.add(item);
}
} catch (SQLiteException ex) {
// failed to load videos. log and pass
Log.e(TAG, ex.getMessage(), ex);
} finally {
Helper.closeCursor(cursor);
}
// load (or generate) thumbnail for each item
for (GalleryItem item : items) {
String id = item.getId();
File cacheDir = context.getExternalCacheDir();
File thumbnailsDir = new File(String.format("%s/thumbnails", cacheDir.getAbsolutePath()));
if (!thumbnailsDir.isDirectory()) {
thumbnailsDir.mkdirs();
}
String thumbnailPath = String.format("%s/%s.png", thumbnailsDir.getAbsolutePath(), id);
File file = new File(thumbnailPath);
if (!file.exists()) {
// save the thumbnail to the path
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap thumbnail = MediaStore.Video.Thumbnails.getThumbnail(
resolver, Long.parseLong(id), MediaStore.Video.Thumbnails.MINI_KIND, options);
if (thumbnail != null) {
try (FileOutputStream os = new FileOutputStream(thumbnailPath)) {
thumbnail.compress(Bitmap.CompressFormat.PNG, 80, os);
} catch (IOException ex) {
// skip
}
}
}
if (file.exists() && file.length() > 0) {
item.setThumbnailUrl(Uri.fromFile(file).toString());
itemsWithThumbnails.add(item);
publishProgress(item);
}
}
}
return itemsWithThumbnails;
}
protected void onProgressUpdate(GalleryItem... items) {
if (handler != null) {
for (GalleryItem item : items) {
handler.onItemLoaded(item);
}
}
}
protected void onPostExecute(List<GalleryItem> items) {
if (handler != null) {
handler.onAllItemsLoaded(items);
}
}
public interface LoadGalleryHandler {
void onItemLoaded(GalleryItem item);
void onAllItemsLoaded(List<GalleryItem> items);
}
}

View file

@ -16,6 +16,34 @@ public class BaseFragment extends Fragment {
@Setter
private Map<String, Object> params;
public boolean shouldHideGlobalPlayer() {
return false;
}
public boolean shouldSuspendGlobalPlayer() {
return false;
}
public void onStart() {
super.onStart();
if (shouldSuspendGlobalPlayer()) {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity.suspendGlobalPlayer(context);
}
}
}
public void onStop() {
if (shouldSuspendGlobalPlayer()) {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity.resumeGlobalPlayer(context);
}
}
super.onStop();
}
public void onResume() {
super.onResume();
Context context = getContext();
@ -23,12 +51,11 @@ public class BaseFragment extends Fragment {
MainActivity activity = (MainActivity) context;
activity.setSelectedMenuItemForFragment(this);
if (this instanceof FileViewFragment) {
if (shouldHideGlobalPlayer()) {
activity.hideGlobalNowPlaying();
} else {
activity.checkNowPlaying();
}
}
}
}

View file

@ -214,7 +214,7 @@ public class ChannelContentFragment extends Fragment implements DownloadActionLi
Context context = getContext();
boolean canShowMatureContent = false;
if (context != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
}

View file

@ -936,20 +936,22 @@ public class FileViewFragment extends BaseFragment implements
loadViewCount();
checkIsFollowing();
getView().findViewById(R.id.file_view_scroll_view).scrollTo(0, 0);
View root = getView();
if (root != null) {
root.findViewById(R.id.file_view_scroll_view).scrollTo(0, 0);
Helper.setViewVisibility(layoutDisplayArea, View.VISIBLE);
ImageView descIndicator = getView().findViewById(R.id.file_view_desc_toggle_arrow);
ImageView descIndicator = root.findViewById(R.id.file_view_desc_toggle_arrow);
descIndicator.setImageResource(R.drawable.ic_arrow_dropdown);
getView().findViewById(R.id.file_view_description_area).setVisibility(View.GONE);
((TextView) getView().findViewById(R.id.file_view_title)).setText(claim.getTitle());
((TextView) getView().findViewById(R.id.file_view_description)).setText(claim.getDescription());
((TextView) getView().findViewById(R.id.file_view_publisher_name)).setText(
root.findViewById(R.id.file_view_description_area).setVisibility(View.GONE);
((TextView) root.findViewById(R.id.file_view_title)).setText(claim.getTitle());
((TextView) root.findViewById(R.id.file_view_description)).setText(claim.getDescription());
((TextView) root.findViewById(R.id.file_view_publisher_name)).setText(
Helper.isNullOrEmpty(claim.getPublisherName()) ? getString(R.string.anonymous) : claim.getPublisherName());
Context context = getContext();
RecyclerView descTagsList = getView().findViewById(R.id.file_view_tag_list);
RecyclerView descTagsList = root.findViewById(R.id.file_view_tag_list);
FlexboxLayoutManager flm = new FlexboxLayoutManager(context);
descTagsList.setLayoutManager(flm);
@ -967,27 +969,27 @@ public class FileViewFragment extends BaseFragment implements
}
});
descTagsList.setAdapter(tagListAdapter);
getView().findViewById(R.id.file_view_tag_area).setVisibility(tags.size() > 0 ? View.VISIBLE : View.GONE);
root.findViewById(R.id.file_view_tag_area).setVisibility(tags.size() > 0 ? View.VISIBLE : View.GONE);
getView().findViewById(R.id.file_view_exoplayer_container).setVisibility(View.GONE);
getView().findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
getView().findViewById(R.id.file_view_media_meta_container).setVisibility(View.VISIBLE);
root.findViewById(R.id.file_view_exoplayer_container).setVisibility(View.GONE);
root.findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
root.findViewById(R.id.file_view_media_meta_container).setVisibility(View.VISIBLE);
Claim.GenericMetadata metadata = claim.getValue();
if (!Helper.isNullOrEmpty(claim.getThumbnailUrl())) {
ImageView thumbnailView = getView().findViewById(R.id.file_view_thumbnail);
ImageView thumbnailView = root.findViewById(R.id.file_view_thumbnail);
Glide.with(getContext().getApplicationContext()).load(claim.getThumbnailUrl()).centerCrop().into(thumbnailView);
} else {
// display first x letters of claim name, with random background
}
getView().findViewById(R.id.file_view_main_action_button).setOnClickListener(new View.OnClickListener() {
root.findViewById(R.id.file_view_main_action_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onMainActionButtonClicked();
}
});
getView().findViewById(R.id.file_view_media_meta_container).setOnClickListener(new View.OnClickListener() {
root.findViewById(R.id.file_view_media_meta_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onMainActionButtonClicked();
@ -997,20 +999,20 @@ public class FileViewFragment extends BaseFragment implements
if (metadata instanceof Claim.StreamMetadata) {
Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
long publishTime = streamMetadata.getReleaseTime() > 0 ? streamMetadata.getReleaseTime() * 1000 : claim.getTimestamp() * 1000;
((TextView) getView().findViewById(R.id.file_view_publish_time)).setText(DateUtils.getRelativeTimeSpanString(
((TextView) root.findViewById(R.id.file_view_publish_time)).setText(DateUtils.getRelativeTimeSpanString(
publishTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
Fee fee = streamMetadata.getFee();
if (fee != null && Helper.parseDouble(fee.getAmount(), 0) > 0) {
getView().findViewById(R.id.file_view_fee_container).setVisibility(View.VISIBLE);
((TextView) getView().findViewById(R.id.file_view_fee)).setText(
root.findViewById(R.id.file_view_fee_container).setVisibility(View.VISIBLE);
((TextView) root.findViewById(R.id.file_view_fee)).setText(
Helper.shortCurrencyFormat(claim.getActualCost(Lbryio.LBCUSDRate).doubleValue()));
}
}
getView().findViewById(R.id.file_view_icon_follow_unfollow).setVisibility(claim.getSigningChannel() != null ? View.VISIBLE : View.GONE);
root.findViewById(R.id.file_view_icon_follow_unfollow).setVisibility(claim.getSigningChannel() != null ? View.VISIBLE : View.GONE);
MaterialButton mainActionButton = getView().findViewById(R.id.file_view_main_action_button);
MaterialButton mainActionButton = root.findViewById(R.id.file_view_main_action_button);
if (claim.isPlayable()) {
mainActionButton.setText(R.string.play);
} else if (claim.isViewable()) {
@ -1037,11 +1039,12 @@ public class FileViewFragment extends BaseFragment implements
restoreMainActionButton();
}
RecyclerView relatedContentList = getView().findViewById(R.id.file_view_related_content_list);
RecyclerView relatedContentList = root.findViewById(R.id.file_view_related_content_list);
if (relatedContentList == null || relatedContentList.getAdapter() == null || relatedContentList.getAdapter().getItemCount() == 0) {
loadRelatedContent();
}
}
}
private void showUnsupportedView() {
getView().findViewById(R.id.file_view_exoplayer_container).setVisibility(View.GONE);
@ -1067,7 +1070,7 @@ public class FileViewFragment extends BaseFragment implements
boolean newPlayerCreated = false;
Context context = getContext();
if (MainActivity.appPlayer == null) {
if (MainActivity.appPlayer == null && context != null) {
MainActivity.appPlayer = new SimpleExoPlayer.Builder(context).build();
MainActivity.playerCache = new SimpleCache(context.getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 256), new ExoDatabaseProvider(context));
newPlayerCreated = true;
@ -1081,7 +1084,6 @@ public class FileViewFragment extends BaseFragment implements
((MainActivity) context).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
if (MainActivity.nowPlayingClaim != null &&
MainActivity.nowPlayingClaim.getClaimId().equalsIgnoreCase(claim.getClaimId()) &&
!newPlayerCreated) {
@ -1089,6 +1091,7 @@ public class FileViewFragment extends BaseFragment implements
return;
}
if (MainActivity.appPlayer != null) {
showBuffering();
if (fileViewPlayerListener != null) {
MainActivity.appPlayer.addListener(fileViewPlayerListener);
@ -1107,6 +1110,7 @@ public class FileViewFragment extends BaseFragment implements
MainActivity.appPlayer.prepare(mediaSource, true, true);
}
}
private void setCurrentPlayer(Player currentPlayer) {
if (this.currentPlayer == currentPlayer) {
@ -1174,9 +1178,12 @@ public class FileViewFragment extends BaseFragment implements
public void onSuccess(int count) {
try {
String displayText = getResources().getQuantityString(R.plurals.view_count, count, NumberFormat.getInstance().format(count));
TextView textViewCount = getView().findViewById(R.id.file_view_view_count);
View root = getView();
if (root != null) {
TextView textViewCount = root.findViewById(R.id.file_view_view_count);
Helper.setViewText(textViewCount, displayText);
Helper.setViewVisibility(textViewCount, View.VISIBLE);
}
} catch (IllegalStateException ex) {
// pass
}
@ -1218,7 +1225,12 @@ public class FileViewFragment extends BaseFragment implements
if (claim != null) {
Fee fee = ((Claim.StreamMetadata) claim.getValue()).getFee();
double cost = claim.getActualCost(Lbryio.LBCUSDRate).doubleValue();
String message = getResources().getQuantityString(R.plurals.confirm_purchase_message, cost == 1 ? 1 : 2, claim.getTitle(), cost);
String formattedCost = Helper.LBC_CURRENCY_FORMAT.format(cost);
String message = getResources().getQuantityString(
R.plurals.confirm_purchase_message,
cost == 1 ? 1 : 2,
claim.getTitle(),
formattedCost.equals("0") ? Helper.FULL_LBC_CURRENCY_FORMAT.format(cost) : formattedCost);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()).
setTitle(R.string.confirm_purchase).
setMessage(message)
@ -1445,10 +1457,10 @@ public class FileViewFragment extends BaseFragment implements
}
public void showError(String message) {
Snackbar.make(getView().findViewById(R.id.file_view_claim_display_area), message, Snackbar.LENGTH_LONG).
setTextColor(Color.WHITE).
setBackgroundTint(Color.RED).
show();
View root = getView();
if (root != null) {
Snackbar.make(root, message, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
}
}
private void loadRelatedContent() {
@ -1884,4 +1896,9 @@ public class FileViewFragment extends BaseFragment implements
// invalid file info for download
}
}
@Override
public boolean shouldHideGlobalPlayer() {
return true;
}
}

View file

@ -396,8 +396,12 @@ public class FollowingFragment extends BaseFragment implements
}
private Map<String, Object> buildSuggestedOptions() {
Context context = getContext();
boolean canShowMatureContent = false;
if (context != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
boolean canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
}
return Lbry.buildClaimSearchOptions(
Claim.TYPE_CHANNEL,

View file

@ -46,6 +46,8 @@ import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.model.ViewHistory;
import io.lbry.browser.tasks.claim.AbandonChannelTask;
import io.lbry.browser.tasks.claim.AbandonHandler;
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
import io.lbry.browser.tasks.claim.ResolveTask;
import io.lbry.browser.tasks.file.BulkDeleteFilesTask;
import io.lbry.browser.tasks.file.DeleteFileTask;
import io.lbry.browser.tasks.file.FileListTask;
@ -55,6 +57,7 @@ import io.lbry.browser.ui.channel.ChannelFormFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
public class LibraryFragment extends BaseFragment implements
ActionMode.Callback, DownloadActionListener, SelectionModeListener, SdkStatusListener {
@ -320,7 +323,10 @@ public class LibraryFragment extends BaseFragment implements
} else {
contentListAdapter.addItems(claims);
}
if (contentList.getAdapter() == null) {
contentList.setAdapter(contentListAdapter);
}
resolveMissingChannelNames(buildUrlsToResolve(claims));
checkListEmpty();
contentListLoading = false;
}
@ -355,7 +361,9 @@ public class LibraryFragment extends BaseFragment implements
} else {
contentListAdapter.addItems(claims);
}
if (contentList.getAdapter() == null) {
contentList.setAdapter(contentListAdapter);
}
checkListEmpty();
contentListLoading = false;
}
@ -564,6 +572,50 @@ public class LibraryFragment extends BaseFragment implements
}
}
private List<String> buildUrlsToResolve(List<Claim> claims) {
List<String> urls = new ArrayList<>();
for (Claim claim : claims) {
Claim channel = claim.getSigningChannel();
if (channel != null && Helper.isNullOrEmpty(channel.getName()) && !Helper.isNullOrEmpty(channel.getClaimId())) {
LbryUri uri = LbryUri.tryParse(String.format("%s#%s", claim.getName(), claim.getClaimId()));
if (uri != null) {
urls.add(uri.toString());
}
}
}
return urls;
}
private void resolveMissingChannelNames(List<String> urls) {
if (urls.size() > 0) {
ResolveTask task = new ResolveTask(urls, Lbry.SDK_CONNECTION_STRING, null, new ClaimListResultHandler() {
@Override
public void onSuccess(List<Claim> claims) {
boolean updated = false;
for (Claim claim : claims) {
if (claim.getClaimId() == null) {
continue;
}
if (contentListAdapter != null) {
contentListAdapter.updateSigningChannelForClaim(claim);
updated = true;
}
}
if (updated) {
contentListAdapter.notifyDataSetChanged();
}
}
@Override
public void onError(Exception error) {
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
public void onEnterSelectionMode() {
Context context = getContext();
if (context instanceof MainActivity) {

View file

@ -0,0 +1,316 @@
package io.lbry.browser.ui.publish;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraX;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.adapter.GalleryGridAdapter;
import io.lbry.browser.listener.CameraPermissionListener;
import io.lbry.browser.listener.StoragePermissionListener;
import io.lbry.browser.model.GalleryItem;
import io.lbry.browser.tasks.localdata.LoadGalleryItemsTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryAnalytics;
public class PublishFragment extends BaseFragment implements CameraPermissionListener, StoragePermissionListener {
private boolean loadGalleryItemsPending;
private PreviewView cameraPreview;
private RecyclerView galleryGrid;
private GalleryGridAdapter adapter;
private TextView noVideosLoaded;
private View loading;
private View buttonRecord;
private View buttonTakePhoto;
private View buttonUpload;
private boolean recordPending;
private boolean takePhotoPending;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_publish, container, false);
noVideosLoaded = root.findViewById(R.id.publish_grid_no_videos);
loading = root.findViewById(R.id.publish_grid_loading);
cameraPreview = root.findViewById(R.id.publish_camera_preview);
Context context = getContext();
galleryGrid = root.findViewById(R.id.publish_video_grid);
GridLayoutManager glm = new GridLayoutManager(context, 3);
galleryGrid.setLayoutManager(glm);
galleryGrid.addItemDecoration(new GalleryGridAdapter.GalleryGridItemDecoration(
3, Helper.getScaledValue(3, context.getResources().getDisplayMetrics().density)));
buttonRecord = root.findViewById(R.id.publish_record_button);
buttonTakePhoto = root.findViewById(R.id.publish_photo_button);
buttonUpload = root.findViewById(R.id.publish_upload_button);
buttonRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkCameraPermissionAndRecord();
}
});
buttonTakePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
checkCameraPermissionAndTakePhoto();
}
});
return root;
}
private boolean cameraAvailable() {
Context context = getContext();
return context != null && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
}
private void showCameraPreview() {
buttonRecord.setBackgroundColor(Color.TRANSPARENT);
buttonTakePhoto.setBackgroundColor(Color.TRANSPARENT);
displayPreviewWithCameraX();
}
private void displayPreviewWithCameraX() {
Context context = getContext();
if (context != null) {
cameraProviderFuture = ProcessCameraProvider.getInstance(context);
cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
if (cameraProvider != null) {
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, preview);
preview.setSurfaceProvider(cameraPreview.createSurfaceProvider(camera.getCameraInfo()));
} else {
android.util.Log.d("#HELP", "camera provider future is null?");
}
} catch (ExecutionException | InterruptedException ex) {
// pass
}
}
}, ContextCompat.getMainExecutor(context));
}
}
private void checkCameraPermissionAndRecord() {
Context context = getContext();
if (!MainActivity.hasPermission(Manifest.permission.CAMERA, context)) {
recordPending = true;
MainActivity.requestPermission(
Manifest.permission.CAMERA,
MainActivity.REQUEST_CAMERA_PERMISSION,
getString(R.string.camera_permission_rationale_record),
context,
true);
} else {
// start video record intent
}
}
private void checkCameraPermissionAndTakePhoto() {
Context context = getContext();
if (!MainActivity.hasPermission(Manifest.permission.CAMERA, context)) {
takePhotoPending = true;
MainActivity.requestPermission(
Manifest.permission.CAMERA,
MainActivity.REQUEST_CAMERA_PERMISSION,
getString(R.string.camera_permission_rationale_photo),
context,
true);
} else {
// start video record intent
}
}
public void onResume() {
super.onResume();
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
LbryAnalytics.setCurrentScreen(activity, "Publish", "Publish");
activity.addCameraPermissionListener(this);
activity.addStoragePermissionListener(this);
activity.hideFloatingWalletBalance();
if (cameraAvailable() && MainActivity.hasPermission(Manifest.permission.CAMERA, context)) {
showCameraPreview();
}
}
checkStoragePermissionAndLoadVideos();
}
@SuppressLint("RestrictedApi")
public void onStop() {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.removeCameraPermissionListener(this);
activity.removeStoragePermissionListener(this);
activity.showFloatingWalletBalance();
}
CameraX.unbindAll();
super.onStop();
}
private void checkStoragePermissionAndLoadVideos() {
Context context = getContext();
if (MainActivity.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, context)) {
loadGalleryItems();
} else {
loadGalleryItemsPending = true;
MainActivity.requestPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
MainActivity.REQUEST_STORAGE_PERMISSION,
getString(R.string.storage_permission_rationale_download),
context,
true);
}
}
private void loadGalleryItems() {
Context context = getContext();
Helper.setViewVisibility(noVideosLoaded, View.GONE);
LoadGalleryItemsTask task = new LoadGalleryItemsTask(loading, context, new LoadGalleryItemsTask.LoadGalleryHandler() {
@Override
public void onItemLoaded(GalleryItem item) {
if (context != null) {
if (adapter == null) {
adapter = new GalleryGridAdapter(Arrays.asList(item), context);
} else {
adapter.addItem(item);
}
if (galleryGrid.getAdapter() == null) {
galleryGrid.setAdapter(adapter);
}
Helper.setViewVisibility(loading, adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
}
@Override
public void onAllItemsLoaded(List<GalleryItem> items) {
if (context != null) {
if (adapter == null) {
adapter = new GalleryGridAdapter(items, context);
} else {
adapter.addItems(items);
}
if (galleryGrid.getAdapter() == null) {
galleryGrid.setAdapter(adapter);
}
}
checkNoVideosLoaded();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void checkNoVideosLoaded() {
Helper.setViewVisibility(noVideosLoaded, adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
@Override
public void onCameraPermissionGranted() {
if (recordPending) {
// record video
recordPending = false;
} else if (takePhotoPending) {
// take a photo
takePhotoPending = false;
}
}
@Override
public void onCameraPermissionRefused() {
if (takePhotoPending) {
takePhotoPending = false;
Snackbar.make(getView(), R.string.camera_permission_rationale_photo, Toast.LENGTH_LONG).
setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
return;
}
recordPending = false;
Snackbar.make(getView(), R.string.camera_permission_rationale_record, Toast.LENGTH_LONG).
setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
}
@Override
public void onRecordAudioPermissionGranted() {
}
@Override
public void onRecordAudioPermissionRefused() {
}
@Override
public void onStoragePermissionGranted() {
if (loadGalleryItemsPending) {
loadGalleryItemsPending = false;
loadGalleryItems();
}
}
@Override
public void onStoragePermissionRefused() {
Snackbar.make(getView(), R.string.storage_permission_rationale_videos, Snackbar.LENGTH_LONG).setBackgroundTint(
ContextCompat.getColor(getContext(), R.color.red)
).show();
}
@Override
public boolean shouldHideGlobalPlayer() {
return true;
}
@Override
public boolean shouldSuspendGlobalPlayer() {
return true;
}
}

View file

@ -0,0 +1,321 @@
package io.lbry.browser.ui.publish;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.Arrays;
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.adapter.ClaimListAdapter;
import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.listener.SelectionModeListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.tasks.claim.AbandonChannelTask;
import io.lbry.browser.tasks.claim.AbandonHandler;
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
import io.lbry.browser.tasks.claim.ClaimListTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryAnalytics;
public class PublishesFragment extends BaseFragment implements ActionMode.Callback, SelectionModeListener, SdkStatusListener {
private Button buttonNewPublish;
private FloatingActionButton fabNewPublish;
private ActionMode actionMode;
private View emptyView;
private View layoutSdkInitializing;
private ProgressBar loading;
private ProgressBar bigLoading;
private RecyclerView contentList;
private ClaimListAdapter adapter;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_publishes, container, false);
buttonNewPublish = root.findViewById(R.id.publishes_create_button);
fabNewPublish = root.findViewById(R.id.publishes_fab_new_publish);
buttonNewPublish.setOnClickListener(newPublishClickListener);
fabNewPublish.setOnClickListener(newPublishClickListener);
emptyView = root.findViewById(R.id.publishes_empty_container);
layoutSdkInitializing = root.findViewById(R.id.container_sdk_initializing);
contentList = root.findViewById(R.id.publishes_list);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
contentList.setLayoutManager(llm);
loading = root.findViewById(R.id.publishes_list_loading);
bigLoading = root.findViewById(R.id.publishes_list_big_loading);
layoutSdkInitializing.setVisibility(Lbry.SDK_READY ? View.GONE : View.VISIBLE);
return root;
}
private View.OnClickListener newPublishClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
Context context = getContext();
if (context instanceof MainActivity) {
//((MainActivity) context).openPublishForm(null);
}
}
};
@Override
public void onStart() {
super.onStart();
Context context = getContext();
if (context != null) {
MainActivity activity = (MainActivity) context;
activity.hideFloatingWalletBalance();
}
}
@Override
public void onStop() {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.showFloatingWalletBalance();
}
super.onStop();
}
public void onResume() {
super.onResume();
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.setWunderbarValue(null);
LbryAnalytics.setCurrentScreen(activity, "Publishes", "Publishes");
}
if (!Lbry.SDK_READY) {
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.addSdkStatusListener(this);
}
} else {
onSdkReady();
}
}
public void onSdkReady() {
Helper.setViewVisibility(layoutSdkInitializing, View.GONE);
Helper.setViewVisibility(fabNewPublish, View.VISIBLE);
if (adapter != null && contentList != null) {
contentList.setAdapter(adapter);
}
fetchPublishes();
}
public View getLoading() {
return (adapter == null || adapter.getItemCount() == 0) ? bigLoading : loading;
}
private void checkNoPublishes() {
Helper.setViewVisibility(emptyView, adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
private void fetchPublishes() {
Helper.setViewVisibility(emptyView, View.GONE);
ClaimListTask task = new ClaimListTask(Arrays.asList(Claim.TYPE_STREAM, Claim.TYPE_REPOST), getLoading(), new ClaimListResultHandler() {
@Override
public void onSuccess(List<Claim> claims) {
Lbry.ownClaims = Helper.filterDeletedClaims(new ArrayList<>(claims));
Context context = getContext();
if (adapter == null) {
adapter = new ClaimListAdapter(claims, context);
adapter.setCanEnterSelectionMode(true);
adapter.setSelectionModeListener(PublishesFragment.this);
adapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
@Override
public void onClaimClicked(Claim claim) {
if (context instanceof MainActivity) {
((MainActivity) context).openFileClaim(claim);
}
}
});
if (contentList != null) {
contentList.setAdapter(adapter);
}
} else {
adapter.setItems(claims);
}
checkNoPublishes();
}
@Override
public void onError(Exception error) {
checkNoPublishes();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void onEnterSelectionMode() {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.startSupportActionMode(this);
}
}
public void onItemSelectionToggled() {
if (actionMode != null) {
actionMode.setTitle(String.valueOf(adapter.getSelectedCount()));
actionMode.invalidate();
}
}
public void onExitSelectionMode() {
if (actionMode != null) {
actionMode.finish();
}
}
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
this.actionMode = actionMode;
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
if (!activity.isDarkMode()) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
actionMode.getMenuInflater().inflate(R.menu.menu_claim_list, menu);
return true;
}
@Override
public void onDestroyActionMode(ActionMode actionMode) {
if (adapter != null) {
adapter.clearSelectedItems();
adapter.setInSelectionMode(false);
adapter.notifyDataSetChanged();
}
Context context = getContext();
if (context != null) {
MainActivity activity = (MainActivity) context;
if (!activity.isDarkMode()) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
this.actionMode = null;
}
@Override
public boolean onPrepareActionMode(androidx.appcompat.view.ActionMode actionMode, Menu menu) {
int selectionCount = adapter != null ? adapter.getSelectedCount() : 0;
menu.findItem(R.id.action_edit).setVisible(selectionCount == 1);
return true;
}
@Override
public boolean onActionItemClicked(androidx.appcompat.view.ActionMode actionMode, MenuItem menuItem) {
if (R.id.action_edit == menuItem.getItemId()) {
if (adapter != null && adapter.getSelectedCount() > 0) {
Claim claim = adapter.getSelectedItems().get(0);
// start channel editor with the claim
Context context = getContext();
if (context instanceof MainActivity) {
Map<String, Object> params = new HashMap<>();
params.put("claim", claim);
/*((MainActivity) context).openFragment(PublishFormFragment.class, true, NavMenuItem.ID_ITEM_NEW_PUBLISH, params);*/
}
actionMode.finish();
return true;
}
}
if (R.id.action_delete == menuItem.getItemId()) {
if (adapter != null && adapter.getSelectedCount() > 0) {
final List<Claim> selectedClaims = new ArrayList<>(adapter.getSelectedItems());
String message = getResources().getQuantityString(R.plurals.confirm_delete_publishes, selectedClaims.size());
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()).
setTitle(R.string.delete_selection).
setMessage(message)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
handleDeleteSelectedClaims(selectedClaims);
}
}).setNegativeButton(R.string.no, null);
builder.show();
return true;
}
}
return false;
}
private void handleDeleteSelectedClaims(List<Claim> selectedClaims) {
List<String> claimIds = new ArrayList<>();
for (Claim claim : selectedClaims) {
claimIds.add(claim.getClaimId());
}
if (actionMode != null) {
actionMode.finish();
}
Helper.setViewVisibility(contentList, View.INVISIBLE);
Helper.setViewVisibility(fabNewPublish, View.INVISIBLE);
AbandonChannelTask task = new AbandonChannelTask(claimIds, bigLoading, new AbandonHandler() {
@Override
public void onComplete(List<String> successfulClaimIds, List<String> failedClaimIds, List<Exception> errors) {
View root = getView();
if (root != null) {
if (failedClaimIds.size() > 0) {
Snackbar.make(root, R.string.one_or_more_publishes_failed_abandon, Snackbar.LENGTH_LONG).
setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
} else if (successfulClaimIds.size() == claimIds.size()) {
try {
String message = getResources().getQuantityString(R.plurals.publishes_deleted, successfulClaimIds.size());
Snackbar.make(root, message, Snackbar.LENGTH_LONG).show();
} catch (IllegalStateException ex) {
// pass
}
}
}
Lbry.abandonedClaimIds.addAll(successfulClaimIds);
if (adapter != null) {
adapter.setItems(Helper.filterDeletedClaims(adapter.getItems()));
}
Helper.setViewVisibility(contentList, View.VISIBLE);
Helper.setViewVisibility(fabNewPublish, View.VISIBLE);
checkNoPublishes();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}

View file

@ -214,8 +214,13 @@ public class SearchFragment extends BaseFragment implements
}
searchLoading = true;
Context context = getContext();
boolean canShowMatureContent = false;
if (context != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
boolean canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
}
LighthouseSearchTask task = new LighthouseSearchTask(
currentQuery, PAGE_SIZE, currentFrom, canShowMatureContent, null, loadingView, new ClaimSearchTask.ClaimSearchResultHandler() {
@Override

View file

@ -233,7 +233,7 @@ public class RewardsFragment extends BaseFragment implements RewardListAdapter.R
Helper.shortCurrencyFormat(Lbryio.totalUnclaimedRewardAmount));
double unclaimedRewardAmountUsd = Lbryio.totalUnclaimedRewardAmount * Lbryio.LBCUSDRate;
Helper.setViewText(textAccountDriverTitle, accountDriverTitle);
Helper.setViewText(textFreeCreditsWorth, getString(R.string.free_credits_worth, Helper.USD_CURRENCY_FORMAT.format(unclaimedRewardAmountUsd)));
Helper.setViewText(textFreeCreditsWorth, getString(R.string.free_credits_worth, Helper.SIMPLE_CURRENCY_FORMAT.format(unclaimedRewardAmountUsd)));
} catch (IllegalStateException ex) {
// pass
}

View file

@ -398,8 +398,12 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
}
private void checkReceiveAddress() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
String receiveAddress = sp.getString(MainActivity.PREFERENCE_KEY_INTERNAL_WALLET_RECEIVE_ADDRESS, null);
Context context = getContext();
String receiveAddress = null;
if (context != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
receiveAddress = sp.getString(MainActivity.PREFERENCE_KEY_INTERNAL_WALLET_RECEIVE_ADDRESS, null);
}
if (Helper.isNullOrEmpty(receiveAddress)) {
if (Lbry.SDK_READY) {
generateNewAddress();
@ -505,15 +509,16 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
double tipsBalance = walletBalance.getTips().doubleValue();
double tipsUsdBalance = tipsBalance * Lbryio.LBCUSDRate;
Helper.setViewText(textWalletBalance, Helper.LBC_CURRENCY_FORMAT.format(balance));
String formattedBalance = Helper.SIMPLE_CURRENCY_FORMAT.format(balance);
Helper.setViewText(textWalletBalance, balance > 0 && formattedBalance.equals("0") ? Helper.FULL_LBC_CURRENCY_FORMAT.format(balance) : formattedBalance);
Helper.setViewText(textTipsBalance, Helper.shortCurrencyFormat(tipsBalance));
Helper.setViewText(textClaimsBalance, Helper.shortCurrencyFormat(walletBalance.getClaims().doubleValue()));
Helper.setViewText(textSupportsBalance, Helper.shortCurrencyFormat(walletBalance.getSupports().doubleValue()));
Helper.setViewText(textWalletInlineBalance, Helper.shortCurrencyFormat(balance));
if (Lbryio.LBCUSDRate > 0) {
// only update display usd values if the rate is loaded
Helper.setViewText(textWalletBalanceUSD, String.format("≈$%s", Helper.USD_CURRENCY_FORMAT.format(usdBalance)));
Helper.setViewText(textTipsBalanceUSD, String.format("≈$%s", Helper.USD_CURRENCY_FORMAT.format(tipsUsdBalance)));
Helper.setViewText(textWalletBalanceUSD, String.format("≈$%s", Helper.SIMPLE_CURRENCY_FORMAT.format(usdBalance)));
Helper.setViewText(textTipsBalanceUSD, String.format("≈$%s", Helper.SIMPLE_CURRENCY_FORMAT.format(tipsUsdBalance)));
}
}
}

View file

@ -67,7 +67,8 @@ public final class Helper {
public static final String LBC_CURRENCY_FORMAT_PATTERN = "#,###.##";
public static final String FILE_SIZE_FORMAT_PATTERN = "#,###.#";
public static final DecimalFormat LBC_CURRENCY_FORMAT = new DecimalFormat(LBC_CURRENCY_FORMAT_PATTERN);
public static final DecimalFormat USD_CURRENCY_FORMAT = new DecimalFormat("#,##0.00");
public static final DecimalFormat FULL_LBC_CURRENCY_FORMAT = new DecimalFormat("#,###.########");
public static final DecimalFormat SIMPLE_CURRENCY_FORMAT = new DecimalFormat("#,##0.00");
public static final String EXPLORER_TX_PREFIX = "https://explorer.lbry.com/tx";
public static boolean isNull(String value) {
@ -300,7 +301,7 @@ public final class Helper {
return "0";
}
return format.format(value);
return format.format(value).equals("0") ? FULL_LBC_CURRENCY_FORMAT.format(value) : format.format(value);
}
public static String getValue(CharSequence cs) {
@ -680,4 +681,8 @@ public final class Helper {
}
return channelName;
}
public static int getScaledValue(int value, float scale) {
return (int) (value * scale + 0.5f);
}
}

View file

@ -44,7 +44,7 @@ import okhttp3.Response;
public final class Lbryio {
// TODO: Get this from the bundled aar
public static String SDK_VERSION = "0.73.1";
public static String SDK_VERSION = "0.74.0";
public static User currentUser;
public static boolean userHasSyncedWallet = false;
@ -121,7 +121,7 @@ public final class Lbryio {
if (options != null) {
for (Map.Entry<String, String> option : options.entrySet()) {
qs.append(delim).append(option.getKey()).append("=").append(URLEncoder.encode(option.getValue(), "UTF8"));
qs.append(delim).append(option.getKey()).append("=").append(URLEncoder.encode(Helper.isNull(option.getValue()) ? "" : option.getValue(), "UTF8"));
delim = "&";
}
}

View file

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M9,16h6v-6h4l-7,-7 -7,7h4zM5,18h14v2L5,20z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

View file

@ -40,6 +40,7 @@
android:layout_height="wrap_content"
android:hint="@string/uri_placeholder"
android:imeOptions="actionGo"
android:inputType="textNoSuggestions"
android:selectAllOnFocus="true"
android:singleLine="true"
android:textFontWeight="300"

View file

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/publishBackground">
<RelativeLayout
android:id="@+id/publish_main_actions"
android:layout_width="match_parent"
android:layout_height="300dp">
<androidx.camera.view.PreviewView
android:id="@+id/publish_camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="2">
<RelativeLayout
android:id="@+id/publish_record_button"
android:background="@android:color/black"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="-1.5dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:tint="@color/white"
android:src="@drawable/ic_record" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:fontFamily="@font/inter"
android:text="@string/record"
android:textAllCaps="true"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent">
<View
android:id="@+id/publish_vertical_divider"
android:background="@color/publishBackground"
android:layout_width="3dp"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/publish_photo_button"
android:clickable="true"
android:background="@android:color/black"
android:foreground="?attr/selectableItemBackground"
android:layout_toRightOf="@id/publish_vertical_divider"
android:layout_width="match_parent"
android:layout_height="148.5dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:tint="@color/white"
android:src="@drawable/ic_photo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:fontFamily="@font/inter"
android:text="@string/take_photo"
android:textAllCaps="true"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
<View
android:id="@+id/publish_photo_upload_divider"
android:background="@color/publishBackground"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_below="@id/publish_photo_button" />
<RelativeLayout
android:id="@+id/publish_upload_button"
android:layout_width="match_parent"
android:layout_height="148.5dp"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/publish_vertical_divider"
android:clickable="true"
android:background="@android:color/black"
android:foreground="?attr/selectableItemBackground"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:tint="@color/white"
android:src="@drawable/ic_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:fontFamily="@font/inter"
android:text="@string/upload_file"
android:textAllCaps="true"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/publish_video_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/publish_main_actions"
android:layout_marginTop="3dp" />
<TextView
android:id="@+id/publish_grid_no_videos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/publish_main_actions"
android:layout_margin="16dp"
android:fontFamily="@font/inter"
android:text="@string/no_videos_found"
android:textColor="@color/white"
android:textSize="16sp"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/publish_grid_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/publish_main_actions"
android:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="horizontal">
<ProgressBar
android:layout_width="20dp"
android:layout_height="20dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:fontFamily="@font/inter"
android:text="@string/loading_videos"
android:textColor="@color/white"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true">
<ProgressBar
android:id="@+id/publishes_list_big_loading"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:visibility="gone" />
<ProgressBar
android:id="@+id/publishes_list_loading"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/publishes_list"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/publishes_empty_container"
android:background="@color/pageBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="36dp">
<ImageView
android:layout_gravity="center_horizontal"
android:layout_width="160dp"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:src="@drawable/gerbil_happy" />
<TextView
android:text="@string/no_channel_created"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_gravity="center_horizontal"
android:fontFamily="@font/inter"
android:textAlignment="center"
android:textSize="16sp"
android:textFontWeight="300"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/publishes_create_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:fontFamily="@font/inter"
android:text="@string/new_publish" />
</LinearLayout>
</RelativeLayout>
<include layout="@layout/container_sdk_initializing" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/publishes_fab_new_publish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_add"
android:visibility="gone" />
</RelativeLayout>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:orientation="vertical"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground">
<ImageView
android:id="@+id/gallery_item_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:background="@android:color/black"
android:id="@+id/gallery_item_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:fontFamily="@font/inter"
android:textColor="@android:color/white"
android:textSize="10sp"
android:textFontWeight="300"
android:padding="2dp"
android:visibility="gone" />
</RelativeLayout>

View file

@ -15,6 +15,7 @@
<color name="smallIconBackground">#55000000</color>
<color name="costBackground">#F4E866</color>
<color name="publishBackground">#333333</color>
<color name="playerControlsBackground">#33000000</color>
<color name="scrubberColor">@color/nextLbryGreen</color>
<color name="playedColor">@color/nextLbryGreen</color>

View file

@ -93,6 +93,27 @@
<item quantity="other">%1$s followers</item>
</plurals>
<!-- Publish -->
<string name="record">Record</string>
<string name="take_photo">Take a Photo</string>
<string name="upload_file">Upload a file</string>
<string name="no_videos_found">We could not find any videos on your device. Take a photo or record a video to get started.</string>
<string name="loading_videos">Please wait while we load your videos...</string>
<string name="storage_permission_rationale_videos">LBRY requires access to be able to display and publish your videos, images and other files from your device.</string>
<string name="camera_permission_rationale_record">LBRY requires access to your camera to record videos.</string>
<string name="camera_permission_rationale_photo">LBRY requires access to your camera to take photos.</string>
<!-- Publishes -->
<string name="one_or_more_publishes_failed_abandon">One or more content items could not be deleted at this time. Please try again later.</string>
<plurals name="confirm_delete_publishes">
<item quantity="one">Are you sure you want to delete the selected content item?</item>
<item quantity="other">Are you sure you want to delete the selected content items?</item>
</plurals>
<plurals name="publishes_deleted">
<item quantity="one">The content item was successfully deleted.</item>
<item quantity="other">The content items were successfully deleted.</item>
</plurals>
<!-- Splash -->
<string name="oops_something_went_wrong">Oops! Something went wrong.</string>
<string name="installation_id_loaded">Loaded Installation ID.</string>
@ -323,7 +344,7 @@
<string name="item_pending_blockchain">The claim is pending publish on the blockchain. You will be able to access or edit the claim in a few moments.</string>
<string name="pending">Pending</string>
<string name="create">Create</string>
<string name="one_or_more_channels_failed_abandon">One or moe channels could not be deleted at this time. Please try again later.</string>
<string name="one_or_more_channels_failed_abandon">One or more channels could not be deleted at this time. Please try again later.</string>
<plurals name="min_deposit_required">
<item quantity="one">A minimum deposit of %1$s credit is required.</item>
<item quantity="other">A minimum deposit of %1$s credits is required.</item>

View file

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:title="@string/user_interface"
app:iconSpaceReserved="false">