Channel management and channel creation / editing
This commit is contained in:
parent
f45c517048
commit
2df4d76927
44 changed files with 2342 additions and 141 deletions
|
@ -26,7 +26,7 @@
|
|||
android:supportsPictureInPicture="true"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:launchMode="singleInstance"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
|
|
@ -49,6 +49,7 @@ import io.lbry.browser.model.Claim;
|
|||
import io.lbry.browser.model.ClaimCacheKey;
|
||||
import io.lbry.browser.model.File;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.tasks.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.ClaimSearchTask;
|
||||
import io.lbry.browser.tasks.FileListTask;
|
||||
import io.lbry.browser.tasks.LighthouseSearchTask;
|
||||
|
@ -266,7 +267,7 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
private void resolveUrl(String url) {
|
||||
resolving = true;
|
||||
View loadingView = findViewById(R.id.file_view_loading_container);
|
||||
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, loadingView, new ResolveTask.ResolveResultHandler() {
|
||||
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, loadingView, new ClaimListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Claim> claims) {
|
||||
if (claims.size() > 0) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.lbry.browser;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
|
@ -10,6 +11,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
@ -38,6 +40,7 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
@ -47,7 +50,6 @@ import androidx.core.view.GravityCompat;
|
|||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
@ -63,6 +65,7 @@ import java.io.BufferedReader;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.ConnectException;
|
||||
import java.nio.channels.Channel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -88,6 +91,7 @@ import io.lbry.browser.model.UrlSuggestion;
|
|||
import io.lbry.browser.model.WalletBalance;
|
||||
import io.lbry.browser.model.WalletSync;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.tasks.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.LighthouseAutoCompleteTask;
|
||||
import io.lbry.browser.tasks.MergeSubscriptionsTask;
|
||||
import io.lbry.browser.tasks.ResolveTask;
|
||||
|
@ -99,7 +103,9 @@ import io.lbry.browser.tasks.wallet.SyncGetTask;
|
|||
import io.lbry.browser.tasks.wallet.SyncSetTask;
|
||||
import io.lbry.browser.tasks.wallet.WalletBalanceTask;
|
||||
import io.lbry.browser.ui.BaseFragment;
|
||||
import io.lbry.browser.ui.channel.ChannelFormFragment;
|
||||
import io.lbry.browser.ui.channel.ChannelFragment;
|
||||
import io.lbry.browser.ui.channel.ChannelManagerFragment;
|
||||
import io.lbry.browser.ui.editorschoice.EditorsChoiceFragment;
|
||||
import io.lbry.browser.ui.following.FollowingFragment;
|
||||
import io.lbry.browser.ui.search.SearchFragment;
|
||||
|
@ -132,14 +138,23 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
fragmentClassNavIdMap.put(SettingsFragment.class, NavMenuItem.ID_ITEM_SETTINGS);
|
||||
fragmentClassNavIdMap.put(AllContentFragment.class, NavMenuItem.ID_ITEM_ALL_CONTENT);
|
||||
|
||||
fragmentClassNavIdMap.put(ChannelManagerFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
|
||||
|
||||
|
||||
// Internal (sub-)pages
|
||||
fragmentClassNavIdMap.put(ChannelFragment.class, NavMenuItem.ID_ITEM_FOLLOWING);
|
||||
fragmentClassNavIdMap.put(SearchFragment.class, NavMenuItem.ID_ITEM_FOLLOWING);
|
||||
|
||||
//fragmentClassNavIdMap.put(ChannelFormFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
|
||||
}
|
||||
|
||||
|
||||
public static final int REQUEST_STORAGE_PERMISSION = 1001;
|
||||
public static final int REQUEST_SIMPLE_SIGN_IN = 2001;
|
||||
public static final int REQUEST_WALLET_SYNC_SIGN_IN = 2002;
|
||||
|
||||
public static final int REQUEST_FILE_PICKER = 5001;
|
||||
|
||||
// broadcast action names
|
||||
public static final String ACTION_SDK_READY = "io.lbry.browser.Broadcast.SdkReady";
|
||||
public static final String ACTION_AUTH_TOKEN_GENERATED = "io.lbry.browser.Broadcast.AuthTokenGenerated";
|
||||
|
@ -205,24 +220,33 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
private boolean pendingFollowingReload;
|
||||
|
||||
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,
|
||||
|
||||
// wallet
|
||||
NavMenuItem.ID_ITEM_WALLET,
|
||||
NavMenuItem.ID_ITEM_SETTINGS
|
||||
);
|
||||
|
||||
public boolean isDarkMode() {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
return sp.getBoolean(PREFERENCE_KEY_DARK_MODE, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean darkMode = sp.getBoolean(PREFERENCE_KEY_DARK_MODE, false);
|
||||
AppCompatDelegate.setDefaultNightMode(darkMode ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
|
||||
AppCompatDelegate.setDefaultNightMode(isDarkMode() ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
|
||||
|
||||
initKeyStore();
|
||||
loadAuthToken();
|
||||
|
||||
dbHelper = new DatabaseHelper(this);
|
||||
if (!darkMode) {
|
||||
if (!isDarkMode()) {
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
}
|
||||
|
||||
|
@ -367,6 +391,11 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
case NavMenuItem.ID_ITEM_ALL_CONTENT:
|
||||
openFragment(AllContentFragment.class, true, NavMenuItem.ID_ITEM_ALL_CONTENT);
|
||||
break;
|
||||
|
||||
case NavMenuItem.ID_ITEM_CHANNELS:
|
||||
openFragment(ChannelManagerFragment.class, true, NavMenuItem.ID_ITEM_CHANNELS);
|
||||
break;
|
||||
|
||||
case NavMenuItem.ID_ITEM_WALLET:
|
||||
openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET);
|
||||
break;
|
||||
|
@ -384,6 +413,14 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
openFragment(ChannelFragment.class, true, NavMenuItem.ID_ITEM_FOLLOWING, params);
|
||||
}
|
||||
|
||||
public void openChannelForm(Claim claim) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (claim != null) {
|
||||
params.put("claim", claim);
|
||||
}
|
||||
openFragment(ChannelFormFragment.class, true, NavMenuItem.ID_ITEM_CHANNELS, params);
|
||||
}
|
||||
|
||||
public void openChannelUrl(String url) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("url", url);
|
||||
|
@ -667,7 +704,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}
|
||||
|
||||
private void resolveUrlSuggestions(List<String> urls) {
|
||||
ResolveTask task = new ResolveTask(urls, Lbry.LBRY_TV_CONNECTION_STRING, null, new ResolveTask.ResolveResultHandler() {
|
||||
ResolveTask task = new ResolveTask(urls, Lbry.LBRY_TV_CONNECTION_STRING, null, new ClaimListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Claim> claims) {
|
||||
if (findViewById(R.id.url_suggestions_container).getVisibility() == View.VISIBLE) {
|
||||
|
@ -1181,12 +1218,38 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
registerReceiver(userActionsReceiver, intentFilter);
|
||||
}
|
||||
|
||||
public void showMessage(int stringResourceId) {
|
||||
Snackbar.make(findViewById(R.id.content_main), stringResourceId, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
public void showMessage(String message) {
|
||||
Snackbar.make(findViewById(R.id.content_main), message, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
} else {
|
||||
boolean handled = false;
|
||||
if (findViewById(R.id.url_suggestions_container).getVisibility() == View.VISIBLE) {
|
||||
clearWunderbarFocus(findViewById(R.id.wunderbar));
|
||||
handled = true;
|
||||
} else {
|
||||
ChannelFormFragment channelFormFragment = null;
|
||||
for (Fragment fragment : openNavFragments.values()) {
|
||||
if (fragment instanceof ChannelFormFragment) {
|
||||
channelFormFragment = ((ChannelFormFragment) fragment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (channelFormFragment != null && channelFormFragment.isSaveInProgress()) {
|
||||
handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
// check fragment and nav history
|
||||
FragmentManager manager = getSupportFragmentManager();
|
||||
int backCount = getSupportFragmentManager().getBackStackEntryCount();
|
||||
|
@ -1201,6 +1264,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void simpleSignIn() {
|
||||
Intent intent = new Intent(this, VerificationActivity.class);
|
||||
|
@ -1214,9 +1278,58 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
startActivityForResult(intent, REQUEST_WALLET_SYNC_SIGN_IN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_STORAGE_PERMISSION:
|
||||
ChannelFormFragment channelFormFragment = null;
|
||||
//PublishFormFragment publishFormFragment = null;
|
||||
for (Fragment fragment : openNavFragments.values()) {
|
||||
if (fragment instanceof ChannelFormFragment) {
|
||||
channelFormFragment = ((ChannelFormFragment) fragment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (channelFormFragment != null) {
|
||||
channelFormFragment.onStoragePermissionGranted();
|
||||
}
|
||||
} else {
|
||||
if (channelFormFragment != null) {
|
||||
channelFormFragment.onStoragePermissionRefused();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_FILE_PICKER) {
|
||||
ChannelFormFragment channelFormFragment = null;
|
||||
//PublishFormFragment publishFormFragment = null;
|
||||
for (Fragment fragment : openNavFragments.values()) {
|
||||
if (fragment instanceof ChannelFormFragment) {
|
||||
channelFormFragment = ((ChannelFormFragment) fragment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
Uri fileUri = data.getData();
|
||||
String filePath = Helper.getRealPathFromURI_API19(this, fileUri);
|
||||
if (channelFormFragment != null) {
|
||||
channelFormFragment.onFilePicked(filePath);
|
||||
}
|
||||
} else {
|
||||
if (channelFormFragment != null) {
|
||||
channelFormFragment.onFilePicked(null);
|
||||
}
|
||||
}
|
||||
} else if (requestCode == REQUEST_SIMPLE_SIGN_IN || requestCode == REQUEST_WALLET_SYNC_SIGN_IN) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
// user signed in
|
||||
showSignedInUser();
|
||||
|
@ -1234,6 +1347,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showSignedInUser() {
|
||||
if (Lbryio.isSignedIn()) {
|
||||
|
@ -1765,4 +1879,19 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public static void requestPermission(String permission, int requestCode, String rationale, Context context, boolean forceRequest) {
|
||||
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (!forceRequest && ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permission)) {
|
||||
Toast.makeText(context, rationale, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions((Activity) context, new String[] { permission }, requestCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasPermission(String permission, Context context) {
|
||||
return (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.listener.SelectionModeListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.ViewHolder> {
|
||||
|
@ -33,6 +35,11 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
private List<Claim> selectedItems;
|
||||
@Setter
|
||||
private ClaimListItemListener listener;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean inSelectionMode;
|
||||
@Setter
|
||||
private SelectionModeListener selectionModeListener;
|
||||
|
||||
public ClaimListAdapter(List<Claim> items, Context context) {
|
||||
this.context = context;
|
||||
|
@ -43,6 +50,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
public List<Claim> getSelectedItems() {
|
||||
return this.selectedItems;
|
||||
}
|
||||
public int getSelectedCount() {
|
||||
return selectedItems != null ? selectedItems.size() : 0;
|
||||
}
|
||||
public void clearSelectedItems() {
|
||||
this.selectedItems.clear();
|
||||
}
|
||||
|
@ -78,6 +88,16 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void setItems(List<Claim> claims) {
|
||||
items = new ArrayList<>(claims);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeItem(Claim claim) {
|
||||
items.remove(claim);
|
||||
selectedItems.remove(claim);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected View feeContainer;
|
||||
|
@ -92,6 +112,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
protected TextView publishTimeView;
|
||||
protected View repostInfoView;
|
||||
protected TextView repostChannelView;
|
||||
protected View selectedOverlayView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
feeContainer = v.findViewById(R.id.claim_fee_container);
|
||||
|
@ -106,6 +127,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
publishTimeView = v.findViewById(R.id.claim_publish_time);
|
||||
repostInfoView = v.findViewById(R.id.claim_repost_info);
|
||||
repostChannelView = v.findViewById(R.id.claim_repost_channel);
|
||||
selectedOverlayView = v.findViewById(R.id.claim_selected_overlay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,13 +182,33 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
bgColor = Helper.generateRandomColorForValue(item.getName());
|
||||
}
|
||||
|
||||
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 (inSelectionMode) {
|
||||
toggleSelectedClaim(item);
|
||||
} else {
|
||||
if (listener != null) {
|
||||
listener.onClaimClicked(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (!inSelectionMode) {
|
||||
inSelectionMode = true;
|
||||
if (selectionModeListener != null) {
|
||||
selectionModeListener.onEnterSelectionMode();
|
||||
}
|
||||
}
|
||||
toggleSelectedClaim(item);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
vh.publisherView.setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -241,6 +283,27 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
}
|
||||
}
|
||||
|
||||
private void toggleSelectedClaim(Claim claim) {
|
||||
if (selectedItems.contains(claim)) {
|
||||
selectedItems.remove(claim);
|
||||
} else {
|
||||
selectedItems.add(claim);
|
||||
}
|
||||
|
||||
if (selectionModeListener != null) {
|
||||
selectionModeListener.onItemSelectionToggled();
|
||||
}
|
||||
|
||||
if (selectedItems.size() == 0) {
|
||||
inSelectionMode = false;
|
||||
if (selectionModeListener != null) {
|
||||
selectionModeListener.onExitSelectionMode();
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public interface ClaimListItemListener {
|
||||
void onClaimClicked(Claim claim);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,12 @@ import com.google.android.material.textfield.TextInputEditText;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.adapter.TagListAdapter;
|
||||
import io.lbry.browser.listener.TagListener;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.tasks.UpdateSuggestedTagsTask;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
import lombok.Setter;
|
||||
|
@ -49,7 +50,7 @@ public class CustomizeTagsDialogFragment extends BottomSheetDialogFragment {
|
|||
}
|
||||
public void addTag(Tag tag) {
|
||||
if (followedTagsAdapter.getTags().contains(tag)) {
|
||||
Snackbar.make(getView(), getString(R.string.tag_already_followed, tag.getName()), Snackbar.LENGTH_LONG).show();
|
||||
Snackbar.make(getView(), getString(R.string.tag_already_added, tag.getName()), Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -158,37 +159,9 @@ public class CustomizeTagsDialogFragment extends BottomSheetDialogFragment {
|
|||
}
|
||||
|
||||
private void updateKnownTags(String filter, int limit, boolean clearPrevious) {
|
||||
(new AsyncTask<Void, Void, List<Tag>>() {
|
||||
protected List<Tag> doInBackground(Void... params) {
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
if (Helper.isNullOrEmpty(filter)) {
|
||||
Random random = new Random();
|
||||
if (suggestedTagsAdapter != null && !clearPrevious) {
|
||||
tags = new ArrayList<>(suggestedTagsAdapter.getTags());
|
||||
}
|
||||
while (tags.size() < limit) {
|
||||
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
|
||||
if (!Lbry.followedTags.contains(randomTag) && (followedTagsAdapter == null || !followedTagsAdapter.getTags().contains(randomTag))) {
|
||||
tags.add(randomTag);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Tag filterTag = new Tag(filter);
|
||||
if (followedTagsAdapter == null || !followedTagsAdapter.getTags().contains(filterTag)) {
|
||||
tags.add(new Tag(filter));
|
||||
}
|
||||
for (int i = 0; i < Lbry.knownTags.size() && tags.size() < SUGGESTED_LIMIT - 1; i++) {
|
||||
Tag knownTag = Lbry.knownTags.get(i);
|
||||
if ((knownTag.getLowercaseName().startsWith(filter) || knownTag.getLowercaseName().matches(filter)) &&
|
||||
(!tags.contains(knownTag) &&
|
||||
!Lbry.followedTags.contains(knownTag) && (followedTagsAdapter == null || !followedTagsAdapter.getTags().contains(knownTag)))) {
|
||||
tags.add(knownTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
protected void onPostExecute(List<Tag> tags) {
|
||||
UpdateSuggestedTagsTask task = new UpdateSuggestedTagsTask(filter, SUGGESTED_LIMIT, followedTagsAdapter, suggestedTagsAdapter, clearPrevious, new UpdateSuggestedTagsTask.KnownTagsHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Tag> tags) {
|
||||
if (suggestedTagsAdapter == null) {
|
||||
suggestedTagsAdapter = new TagListAdapter(tags, getContext());
|
||||
suggestedTagsAdapter.setCustomizeMode(TagListAdapter.CUSTOMIZE_MODE_ADD);
|
||||
|
@ -201,11 +174,7 @@ public class CustomizeTagsDialogFragment extends BottomSheetDialogFragment {
|
|||
}
|
||||
checkNoResults();
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public interface TagListener {
|
||||
void onTagAdded(Tag tag);
|
||||
void onTagRemoved(Tag tag);
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package io.lbry.browser.listener;
|
||||
|
||||
public interface SelectionModeListener {
|
||||
void onEnterSelectionMode();
|
||||
void onExitSelectionMode();
|
||||
void onItemSelectionToggled();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package io.lbry.browser.listener;
|
||||
|
||||
import io.lbry.browser.model.Tag;
|
||||
|
||||
public interface TagListener {
|
||||
void onTagAdded(Tag tag);
|
||||
void onTagRemoved(Tag tag);
|
||||
}
|
|
@ -112,6 +112,14 @@ public class Claim {
|
|||
return (value != null) ? value.getDescription() : null;
|
||||
}
|
||||
|
||||
public String getWebsiteUrl() {
|
||||
return (value instanceof ChannelMetadata) ? ((ChannelMetadata) value).getWebsiteUrl() : null;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return (value instanceof ChannelMetadata) ? ((ChannelMetadata) value).getEmail() : null;
|
||||
}
|
||||
|
||||
public String getPublisherName() {
|
||||
if (signingChannel != null) {
|
||||
return signingChannel.getName();
|
||||
|
|
|
@ -28,7 +28,7 @@ public class Subscription {
|
|||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof Subscription) && url.equalsIgnoreCase(((Subscription) o).getUrl());
|
||||
return (o instanceof Subscription) && url != null && url.equalsIgnoreCase(((Subscription) o).getUrl());
|
||||
}
|
||||
public int hashCode() {
|
||||
return url.toLowerCase().hashCode();
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package io.lbry.browser.tasks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.model.Claim;
|
||||
|
||||
public interface ClaimListResultHandler {
|
||||
void onSuccess(List<Claim> claims);
|
||||
void onError(Exception error);
|
||||
}
|
67
app/src/main/java/io/lbry/browser/tasks/ClaimListTask.java
Normal file
67
app/src/main/java/io/lbry/browser/tasks/ClaimListTask.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
package io.lbry.browser.tasks;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.exceptions.ApiCallException;
|
||||
import io.lbry.browser.model.Claim;
|
||||
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 View progressView;
|
||||
private ClaimListResultHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public ClaimListTask(String type, View progressView, ClaimListResultHandler handler) {
|
||||
this.type = type;
|
||||
this.progressView = progressView;
|
||||
this.handler = handler;
|
||||
}
|
||||
protected void onPreExecute() {
|
||||
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||
}
|
||||
protected List<Claim> doInBackground(Void... params) {
|
||||
List<Claim> claims = null;
|
||||
|
||||
try {
|
||||
Map<String, Object> options = new HashMap<>();
|
||||
if (!Helper.isNullOrEmpty(type)) {
|
||||
options.put("claim_type", type);
|
||||
}
|
||||
options.put("page", 1);
|
||||
options.put("page_size", 999);
|
||||
options.put("resolve", true);
|
||||
|
||||
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_CLAIM_LIST, options);
|
||||
JSONArray items = result.getJSONArray("items");
|
||||
claims = new ArrayList<>();
|
||||
for (int i = 0; i < items.length(); i++) {
|
||||
claims.add(Claim.fromJSONObject(items.getJSONObject(i)));
|
||||
}
|
||||
} catch (ApiCallException | JSONException ex) {
|
||||
error = ex;
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
protected void onPostExecute(List<Claim> claims) {
|
||||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != null) {
|
||||
if (claims != null) {
|
||||
handler.onSuccess(claims);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,15 +14,15 @@ import io.lbry.browser.utils.Lbry;
|
|||
public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||
private List<String> urls;
|
||||
private String connectionString;
|
||||
private ResolveResultHandler handler;
|
||||
private ClaimListResultHandler handler;
|
||||
private View progressView;
|
||||
private ApiCallException error;
|
||||
|
||||
public ResolveTask(String url, String connectionString, View progressView, ResolveResultHandler handler) {
|
||||
public ResolveTask(String url, String connectionString, View progressView, ClaimListResultHandler handler) {
|
||||
this(Arrays.asList(url), connectionString, progressView, handler);
|
||||
}
|
||||
|
||||
public ResolveTask(List<String> urls, String connectionString, View progressView, ResolveResultHandler handler) {
|
||||
public ResolveTask(List<String> urls, String connectionString, View progressView, ClaimListResultHandler handler) {
|
||||
this.urls = urls;
|
||||
this.connectionString = connectionString;
|
||||
this.progressView = progressView;
|
||||
|
@ -50,8 +50,4 @@ public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
|
|||
}
|
||||
}
|
||||
|
||||
public interface ResolveResultHandler {
|
||||
void onSuccess(List<Claim> claims);
|
||||
void onError(Exception error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package io.lbry.browser.tasks;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import io.lbry.browser.adapter.TagListAdapter;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class UpdateSuggestedTagsTask extends AsyncTask<Void, Void, List<Tag>> {
|
||||
|
||||
private boolean clearPrevious;
|
||||
private int limit;
|
||||
private String filter;
|
||||
private TagListAdapter addedTagsAdapter;
|
||||
private TagListAdapter suggestedTagsAdapter;
|
||||
private KnownTagsHandler handler;
|
||||
|
||||
public UpdateSuggestedTagsTask(String filter, int limit, TagListAdapter addedTagsAdapter, TagListAdapter suggestedTagsAdapter, boolean clearPrevious, KnownTagsHandler handler) {
|
||||
this.filter = filter;
|
||||
this.limit = limit;
|
||||
this.addedTagsAdapter = addedTagsAdapter;
|
||||
this.suggestedTagsAdapter = suggestedTagsAdapter;
|
||||
this.clearPrevious = clearPrevious;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
protected List<Tag> doInBackground(Void... params) {
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
if (Helper.isNullOrEmpty(filter)) {
|
||||
Random random = new Random();
|
||||
if (suggestedTagsAdapter != null && !clearPrevious) {
|
||||
tags = new ArrayList<>(suggestedTagsAdapter.getTags());
|
||||
}
|
||||
while (tags.size() < limit) {
|
||||
Tag randomTag = Lbry.knownTags.get(random.nextInt(Lbry.knownTags.size()));
|
||||
if (!Lbry.followedTags.contains(randomTag) && (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(randomTag))) {
|
||||
tags.add(randomTag);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Tag filterTag = new Tag(filter);
|
||||
if (addedTagsAdapter == null || !addedTagsAdapter.getTags().contains(filterTag)) {
|
||||
tags.add(new Tag(filter));
|
||||
}
|
||||
for (int i = 0; i < Lbry.knownTags.size() && tags.size() < limit - 1; i++) {
|
||||
Tag knownTag = Lbry.knownTags.get(i);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
protected void onPostExecute(List<Tag> tags) {
|
||||
if (handler != null) {
|
||||
handler.onSuccess(tags);
|
||||
}
|
||||
}
|
||||
|
||||
public interface KnownTagsHandler {
|
||||
void onSuccess(List<Tag> tags);
|
||||
}
|
||||
}
|
101
app/src/main/java/io/lbry/browser/tasks/UploadImageTask.java
Normal file
101
app/src/main/java/io/lbry/browser/tasks/UploadImageTask.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
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.Random;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import io.lbry.browser.exceptions.LbryResponseException;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class UploadImageTask extends AsyncTask<Void, Void, String> {
|
||||
private String filePath;
|
||||
private View progressView;
|
||||
private UploadThumbnailHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public UploadImageTask(String filePath, View progressView, UploadThumbnailHandler handler) {
|
||||
this.filePath = filePath;
|
||||
this.progressView = progressView;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||
}
|
||||
protected String doInBackground(Void... params) {
|
||||
String thumbnailUrl = null;
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
String fileName = file.getName();
|
||||
int dotIndex = fileName.lastIndexOf('.');
|
||||
String extension = "jpg";
|
||||
if (dotIndex > -1) {
|
||||
extension = fileName.substring(dotIndex + 1);
|
||||
}
|
||||
String fileType = String.format("image/%s", extension);
|
||||
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).
|
||||
addFormDataPart("name", makeid()).
|
||||
addFormDataPart("file", fileName, RequestBody.create(file, MediaType.parse(fileType))).
|
||||
build();
|
||||
Request request = new Request.Builder().url("https://spee.ch/api/claim/publish").post(body).build();
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Response response = client.newCall(request).execute();
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if (json.has("success")) {
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
String url = Helper.getJSONString("url", null, data);
|
||||
if (Helper.isNullOrEmpty(url)) {
|
||||
throw new LbryResponseException("Invalid thumbnail url returned after upload.");
|
||||
}
|
||||
|
||||
thumbnailUrl = String.format("%s.%s", url, extension);
|
||||
} else if (json.has("error")) {
|
||||
JSONObject error = json.getJSONObject("error");
|
||||
String message = Helper.getJSONString("message", null, error);
|
||||
throw new LbryResponseException(Helper.isNullOrEmpty(message) ? "The image failed to upload." : message);
|
||||
}
|
||||
} catch (IOException | JSONException | LbryResponseException ex) {
|
||||
error = ex;
|
||||
}
|
||||
|
||||
return thumbnailUrl;
|
||||
}
|
||||
protected void onPostExecute(String thumbnailUrl) {
|
||||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != null) {
|
||||
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
|
||||
handler.onSuccess(thumbnailUrl);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeid() {
|
||||
Random random = new Random();
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
StringBuilder id = new StringBuilder();
|
||||
for (int i = 0; i < 24; i++) {
|
||||
id.append(chars.charAt(random.nextInt(chars.length())));
|
||||
}
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
public interface UploadThumbnailHandler {
|
||||
void onSuccess(String url);
|
||||
void onError(Exception error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package io.lbry.browser.tasks.content;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.exceptions.ApiCallException;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private Claim claim;
|
||||
private BigDecimal deposit;
|
||||
private boolean update;
|
||||
private Exception error;
|
||||
private GenericTaskHandler handler;
|
||||
private View progressView;
|
||||
|
||||
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, GenericTaskHandler handler) {
|
||||
this.claim = claim;
|
||||
this.deposit = deposit;
|
||||
this.update = update;
|
||||
this.progressView = progressView;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||
if (handler != null) {
|
||||
handler.beforeStart();
|
||||
}
|
||||
}
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
Map<String, Object> options = new HashMap<>();
|
||||
if (!update) {
|
||||
options.put("name", claim.getName());
|
||||
} else {
|
||||
options.put("claim_id", claim.getClaimId());
|
||||
}
|
||||
options.put("bid", new DecimalFormat(Helper.SDK_AMOUNT_FORMAT).format(deposit.doubleValue()));
|
||||
options.put("title", claim.getTitle());
|
||||
options.put("cover_url", claim.getCoverUrl());
|
||||
options.put("thumbnail_url", claim.getThumbnailUrl());
|
||||
options.put("description", claim.getDescription());
|
||||
options.put("website_url", claim.getWebsiteUrl());
|
||||
options.put("email", claim.getEmail());
|
||||
options.put("tags", claim.getTags());
|
||||
options.put("blocking", true);
|
||||
|
||||
String method = !update ? Lbry.METHOD_CHANNEL_CREATE : Lbry.METHOD_CHANNEL_UPDATE;
|
||||
try {
|
||||
Lbry.genericApiCall(method, options);
|
||||
} catch (ApiCallException | ClassCastException ex) {
|
||||
error = ex;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected void onPostExecute(Boolean result) {
|
||||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != null) {
|
||||
if (result) {
|
||||
handler.onSuccess();
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package io.lbry.browser.tasks.content;
|
||||
|
||||
public class LogPublishTask {
|
||||
}
|
|
@ -30,12 +30,11 @@ import io.lbry.browser.dialog.ContentFromDialogFragment;
|
|||
import io.lbry.browser.dialog.ContentScopeDialogFragment;
|
||||
import io.lbry.browser.dialog.ContentSortDialogFragment;
|
||||
import io.lbry.browser.dialog.CustomizeTagsDialogFragment;
|
||||
import io.lbry.browser.listener.TagListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.tasks.ClaimSearchTask;
|
||||
import io.lbry.browser.tasks.FollowUnfollowTagTask;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.tasks.wallet.SaveSharedUserStateTask;
|
||||
import io.lbry.browser.ui.BaseFragment;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
@ -260,7 +259,7 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
|
|||
|
||||
private void showCustomizeTagsDialog() {
|
||||
CustomizeTagsDialogFragment dialog = CustomizeTagsDialogFragment.newInstance();
|
||||
dialog.setListener(new CustomizeTagsDialogFragment.TagListener() {
|
||||
dialog.setListener(new TagListener() {
|
||||
@Override
|
||||
public void onTagAdded(Tag tag) {
|
||||
// heavy-lifting
|
||||
|
@ -373,8 +372,12 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
|
|||
}
|
||||
|
||||
private Map<String, Object> buildContentOptions() {
|
||||
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(
|
||||
null,
|
||||
|
|
|
@ -199,8 +199,12 @@ public class ChannelContentFragment extends Fragment implements SharedPreference
|
|||
}
|
||||
|
||||
private Map<String, Object> buildContentOptions() {
|
||||
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(
|
||||
null,
|
||||
|
|
|
@ -0,0 +1,597 @@
|
|||
package io.lbry.browser.ui.channel;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.google.android.flexbox.FlexboxLayoutManager;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.MainActivity;
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.adapter.TagListAdapter;
|
||||
import io.lbry.browser.listener.WalletBalanceListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.model.WalletBalance;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.tasks.UpdateSuggestedTagsTask;
|
||||
import io.lbry.browser.tasks.UploadImageTask;
|
||||
import io.lbry.browser.tasks.content.ChannelCreateUpdateTask;
|
||||
import io.lbry.browser.ui.BaseFragment;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ChannelFormFragment extends BaseFragment implements WalletBalanceListener, TagListAdapter.TagClickListener {
|
||||
|
||||
private static final int SUGGESTED_LIMIT = 8;
|
||||
|
||||
@Getter
|
||||
private boolean saveInProgress;
|
||||
private boolean uploading;
|
||||
private Claim currentClaim;
|
||||
private boolean editFieldsLoaded;
|
||||
private boolean editMode;
|
||||
private View linkCancel;
|
||||
private TextView linkShowOptional;
|
||||
private MaterialButton buttonSave;
|
||||
|
||||
private TextView inlineBalanceValue;
|
||||
private View uploadProgress;
|
||||
private View containerOptionalFields;
|
||||
private ImageView imageCover;
|
||||
private ImageView imageThumbnail;
|
||||
private TextInputEditText inputTitle;
|
||||
private TextInputEditText inputChannelName;
|
||||
private TextInputEditText inputDeposit;
|
||||
private TextInputEditText inputDescription;
|
||||
private TextInputEditText inputWebsite;
|
||||
private TextInputEditText inputEmail;
|
||||
|
||||
private TextInputEditText inputTagFilter;
|
||||
private RecyclerView addedTagsList;
|
||||
private RecyclerView suggestedTagsList;
|
||||
private TagListAdapter addedTagsAdapter;
|
||||
private TagListAdapter suggestedTagsAdapter;
|
||||
private View noTagsView;
|
||||
private View noTagResultsView;
|
||||
|
||||
private View coverEditArea;
|
||||
private View iconContainer;
|
||||
private View channelSaveProgress;
|
||||
|
||||
private boolean launchCoverSelectPending;
|
||||
private boolean launchThumbnailSelectPending;
|
||||
private boolean coverFilePickerActive;
|
||||
private boolean thumbnailFilePickerActive;
|
||||
|
||||
private String currentFilter;
|
||||
|
||||
private String coverUrl;
|
||||
private String thumbnailUrl;
|
||||
private String lastSelectedCoverFile;
|
||||
private String lastSelectedThumbnailFile;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_channel_form, container, false);
|
||||
|
||||
linkCancel = root.findViewById(R.id.channel_form_cancel_link);
|
||||
linkShowOptional = root.findViewById(R.id.channel_form_toggle_optional);
|
||||
buttonSave = root.findViewById(R.id.channel_form_save_button);
|
||||
|
||||
containerOptionalFields = root.findViewById(R.id.channel_form_optional_fields_container);
|
||||
inputTitle = root.findViewById(R.id.channel_form_input_title);
|
||||
inputChannelName = root.findViewById(R.id.channel_form_input_channel_name);
|
||||
inputDeposit = root.findViewById(R.id.channel_form_input_deposit);
|
||||
inputDescription = root.findViewById(R.id.channel_form_input_description);
|
||||
inputWebsite = root.findViewById(R.id.channel_form_input_website);
|
||||
inputEmail = root.findViewById(R.id.channel_form_input_email);
|
||||
inputTagFilter = root.findViewById(R.id.form_tag_filter_input);
|
||||
|
||||
coverEditArea = root.findViewById(R.id.channel_form_cover_edit_area);
|
||||
iconContainer = root.findViewById(R.id.channel_form_icon_container);
|
||||
imageCover = root.findViewById(R.id.channel_form_cover_image);
|
||||
imageThumbnail = root.findViewById(R.id.channel_form_thumbnail);
|
||||
inlineBalanceValue = root.findViewById(R.id.channel_form_inline_balance_value);
|
||||
uploadProgress = root.findViewById(R.id.channel_form_upload_progress);
|
||||
channelSaveProgress = root.findViewById(R.id.channel_form_save_progress);
|
||||
|
||||
Context context = getContext();
|
||||
FlexboxLayoutManager flm1 = new FlexboxLayoutManager(context);
|
||||
FlexboxLayoutManager flm2 = new FlexboxLayoutManager(context);
|
||||
addedTagsList = root.findViewById(R.id.form_added_tags);
|
||||
addedTagsList.setLayoutManager(flm1);
|
||||
suggestedTagsList = root.findViewById(R.id.form_suggested_tags);
|
||||
suggestedTagsList.setLayoutManager(flm2);
|
||||
|
||||
addedTagsAdapter = new TagListAdapter(new ArrayList<>(), context);
|
||||
addedTagsAdapter.setCustomizeMode(TagListAdapter.CUSTOMIZE_MODE_REMOVE);
|
||||
addedTagsAdapter.setClickListener(this);
|
||||
addedTagsList.setAdapter(addedTagsAdapter);
|
||||
suggestedTagsAdapter = new TagListAdapter(new ArrayList<>(), getContext());
|
||||
suggestedTagsAdapter.setCustomizeMode(TagListAdapter.CUSTOMIZE_MODE_ADD);
|
||||
suggestedTagsAdapter.setClickListener(this);
|
||||
suggestedTagsList.setAdapter(suggestedTagsAdapter);
|
||||
|
||||
noTagsView = root.findViewById(R.id.form_no_added_tags);
|
||||
noTagResultsView = root.findViewById(R.id.form_no_tag_results);
|
||||
|
||||
buttonSave = root.findViewById(R.id.channel_form_save_button);
|
||||
|
||||
linkShowOptional.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (containerOptionalFields.getVisibility() != View.VISIBLE) {
|
||||
containerOptionalFields.setVisibility(View.VISIBLE);
|
||||
linkShowOptional.setText(R.string.hide_optional_fields);
|
||||
} else {
|
||||
containerOptionalFields.setVisibility(View.GONE);
|
||||
linkShowOptional.setText(R.string.show_optional_fields);
|
||||
}
|
||||
}
|
||||
});
|
||||
linkCancel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).onBackPressed();
|
||||
}
|
||||
}
|
||||
});
|
||||
coverEditArea.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (uploading) {
|
||||
Snackbar.make(getView(), R.string.wait_for_upload, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
checkPermissionsAndLaunchFilePicker(true);
|
||||
}
|
||||
});
|
||||
iconContainer.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (uploading) {
|
||||
Snackbar.make(getView(), R.string.wait_for_upload, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
checkPermissionsAndLaunchFilePicker(false);
|
||||
}
|
||||
});
|
||||
|
||||
buttonSave.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Claim claimToSave = buildChannelClaimToSave();
|
||||
validateAndSaveClaim(claimToSave);
|
||||
}
|
||||
});
|
||||
inputTagFilter.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) {
|
||||
String value = Helper.getValue(charSequence);
|
||||
setFilter(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void checkParams() {
|
||||
Map<String, Object> params = getParams();
|
||||
if (params.containsKey("claim")) {
|
||||
Claim claim = (Claim) params.get("claim");
|
||||
if (claim != null && !claim.equals(this.currentClaim)) {
|
||||
this.currentClaim = claim;
|
||||
editFieldsLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFieldsFromCurrentClaim() {
|
||||
if (currentClaim != null && !editFieldsLoaded) {
|
||||
inputTitle.setText(currentClaim.getTitle());
|
||||
inputChannelName.setText(currentClaim.getName());
|
||||
inputDeposit.setText(currentClaim.getAmount());
|
||||
inputEmail.setText(currentClaim.getEmail());
|
||||
inputWebsite.setText(currentClaim.getWebsiteUrl());
|
||||
inputDescription.setText(currentClaim.getDescription());
|
||||
if (currentClaim.getTagObjects() != null) {
|
||||
addedTagsAdapter.addTags(currentClaim.getTagObjects());
|
||||
}
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
if (!Helper.isNullOrEmpty(currentClaim.getCoverUrl())) {
|
||||
Glide.with(context.getApplicationContext()).load(currentClaim.getCoverUrl()).centerCrop().into(imageCover);
|
||||
coverUrl = currentClaim.getCoverUrl();
|
||||
}
|
||||
if (!Helper.isNullOrEmpty(currentClaim.getThumbnailUrl())) {
|
||||
Glide.with(context.getApplicationContext()).load(currentClaim.getThumbnailUrl()).apply(RequestOptions.circleCropTransform()).into(imageThumbnail);
|
||||
thumbnailUrl = currentClaim.getThumbnailUrl();
|
||||
}
|
||||
}
|
||||
|
||||
inputChannelName.setEnabled(false);
|
||||
editMode = true;
|
||||
editFieldsLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAndSaveClaim(Claim claim) {
|
||||
if (!editMode) {
|
||||
String channelName = claim.getName().startsWith("@") ? claim.getName().substring(1) : claim.getName();
|
||||
if (Helper.isNullOrEmpty(channelName)) {
|
||||
showError(getString(R.string.please_enter_channel_name));
|
||||
return;
|
||||
}
|
||||
if (!LbryUri.isNameValid(channelName)) {
|
||||
showError(getString(R.string.channel_name_invalid_characters));
|
||||
return;
|
||||
}
|
||||
if (Helper.channelExists(channelName)) {
|
||||
showError(getString(R.string.channel_name_already_created));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String depositString = Helper.getValue(inputDeposit.getText());
|
||||
double depositAmount = 0;
|
||||
try {
|
||||
depositAmount = Double.valueOf(depositString);
|
||||
} catch (NumberFormatException ex) {
|
||||
// pass
|
||||
showError(getString(R.string.please_enter_valid_deposit));
|
||||
return;
|
||||
}
|
||||
if (depositAmount == 0) {
|
||||
String error = getResources().getQuantityString(R.plurals.min_deposit_required, depositAmount == 1 ? 1 : 2, String.valueOf(Helper.MIN_DEPOSIT));
|
||||
showError(error);
|
||||
return;
|
||||
}
|
||||
if (Lbry.walletBalance == null || Lbry.walletBalance.getAvailable().doubleValue() < depositAmount) {
|
||||
showError(getString(R.string.deposit_more_than_balance));
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelCreateUpdateTask task = new ChannelCreateUpdateTask(claim, new BigDecimal(depositString), editMode, channelSaveProgress, new GenericTaskHandler() {
|
||||
@Override
|
||||
public void beforeStart() {
|
||||
preSave();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
postSave();
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
activity.showMessage(R.string.channel_save_successful);
|
||||
activity.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
showError(error != null ? error.getMessage() : getString(R.string.channel_save_failed));
|
||||
postSave();
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void showError(String message) {
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).setBackgroundTint(
|
||||
ContextCompat.getColor(context, R.color.red)).show();
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPermissionsAndLaunchFilePicker(boolean isCover) {
|
||||
Context context = getContext();
|
||||
if (MainActivity.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, context)) {
|
||||
launchCoverSelectPending = false;
|
||||
launchThumbnailSelectPending = false;
|
||||
|
||||
coverFilePickerActive = isCover;
|
||||
thumbnailFilePickerActive = !isCover;
|
||||
launchFilePicker();
|
||||
} else {
|
||||
launchCoverSelectPending = isCover;
|
||||
launchThumbnailSelectPending = !isCover;
|
||||
MainActivity.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
MainActivity.REQUEST_STORAGE_PERMISSION,
|
||||
getString(R.string.storage_permission_rationale_images),
|
||||
context,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
private void launchFilePicker() {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.setType("image/*");
|
||||
((MainActivity) context).startActivityForResult(
|
||||
Intent.createChooser(intent, getString(coverFilePickerActive ? R.string.select_cover : R.string.select_thumbnail)),
|
||||
MainActivity.REQUEST_FILE_PICKER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void onFilePicked(String filePath) {
|
||||
if (Helper.isNullOrEmpty(filePath)) {
|
||||
Snackbar.make(getView(), R.string.undetermined_image_filepath, Snackbar.LENGTH_LONG).setBackgroundTint(
|
||||
ContextCompat.getColor(getContext(), R.color.red)).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
Uri fileUri = Uri.fromFile(new File(filePath));
|
||||
if (coverFilePickerActive) {
|
||||
// cover selected
|
||||
if (filePath.equalsIgnoreCase(lastSelectedCoverFile)) {
|
||||
// previous selected cover was uploaded successfully
|
||||
return;
|
||||
}
|
||||
Glide.with(context.getApplicationContext()).load(fileUri).centerCrop().into(imageCover);
|
||||
} else if (thumbnailFilePickerActive) {
|
||||
if (filePath.equalsIgnoreCase(lastSelectedThumbnailFile)) {
|
||||
// previous selected thumbnail was uploaded successfully
|
||||
return;
|
||||
}
|
||||
// thumbnail selected
|
||||
Glide.with(context.getApplicationContext()).load(fileUri).apply(RequestOptions.circleCropTransform()).into(imageThumbnail);
|
||||
}
|
||||
|
||||
// Upload the image
|
||||
uploading = true;
|
||||
UploadImageTask task = new UploadImageTask(filePath, uploadProgress, new UploadImageTask.UploadThumbnailHandler() {
|
||||
@Override
|
||||
public void onSuccess(String url) {
|
||||
if (coverFilePickerActive) {
|
||||
coverUrl = url;
|
||||
lastSelectedCoverFile = filePath;
|
||||
} else if (thumbnailFilePickerActive) {
|
||||
thumbnailUrl = url;
|
||||
lastSelectedThumbnailFile = filePath;
|
||||
}
|
||||
|
||||
coverFilePickerActive = false;
|
||||
thumbnailFilePickerActive = false;
|
||||
uploading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
Snackbar.make(getView(), R.string.image_upload_failed, Snackbar.LENGTH_LONG).setBackgroundTint(
|
||||
ContextCompat.getColor(context, R.color.red)
|
||||
).show();
|
||||
coverFilePickerActive = false;
|
||||
thumbnailFilePickerActive = false;
|
||||
uploading = false;
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
coverFilePickerActive = false;
|
||||
thumbnailFilePickerActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onStoragePermissionGranted() {
|
||||
if (launchCoverSelectPending) {
|
||||
checkPermissionsAndLaunchFilePicker(true);
|
||||
} else if (launchThumbnailSelectPending) {
|
||||
checkPermissionsAndLaunchFilePicker(false);
|
||||
}
|
||||
}
|
||||
public void onStoragePermissionRefused() {
|
||||
Snackbar.make(getView(), R.string.storage_permission_rationale_images, Snackbar.LENGTH_LONG).setBackgroundTint(
|
||||
ContextCompat.getColor(getContext(), R.color.red)
|
||||
).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
MainActivity activity = (MainActivity) getContext();
|
||||
if (activity != null) {
|
||||
activity.hideSearchBar();
|
||||
activity.showNavigationBackIcon();
|
||||
activity.lockDrawer();
|
||||
activity.hideFloatingWalletBalance();
|
||||
activity.addWalletBalanceListener(this);
|
||||
|
||||
ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(editMode ? R.string.edit_channel : R.string.create_a_channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) getContext();
|
||||
activity.removeWalletBalanceListener(this);
|
||||
activity.restoreToggle();
|
||||
activity.showFloatingWalletBalance();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
checkParams();
|
||||
updateFieldsFromCurrentClaim();
|
||||
|
||||
String filterText = Helper.getValue(inputTagFilter.getText());
|
||||
updateSuggestedTags(filterText, SUGGESTED_LIMIT, true);
|
||||
}
|
||||
|
||||
private void checkNoAddedTags() {
|
||||
Helper.setViewVisibility(noTagsView, addedTagsAdapter == null || addedTagsAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
private void checkNoTagResults() {
|
||||
Helper.setViewVisibility(noTagResultsView, suggestedTagsAdapter == null || suggestedTagsAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
public void addTag(Tag tag) {
|
||||
if (addedTagsAdapter.getTags().contains(tag)) {
|
||||
Snackbar.make(getView(), getString(R.string.tag_already_added, tag.getName()), Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
tag.setFollowed(true);
|
||||
addedTagsAdapter.addTag(tag);
|
||||
if (suggestedTagsAdapter != null) {
|
||||
suggestedTagsAdapter.removeTag(tag);
|
||||
}
|
||||
updateSuggestedTags(currentFilter, SUGGESTED_LIMIT, false);
|
||||
|
||||
checkNoAddedTags();
|
||||
checkNoTagResults();
|
||||
}
|
||||
public void removeTag(Tag tag) {
|
||||
tag.setFollowed(false);
|
||||
addedTagsAdapter.removeTag(tag);
|
||||
updateSuggestedTags(currentFilter, SUGGESTED_LIMIT, false);
|
||||
checkNoAddedTags();
|
||||
checkNoTagResults();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalletBalanceUpdated(WalletBalance walletBalance) {
|
||||
if (walletBalance != null && inlineBalanceValue != null) {
|
||||
inlineBalanceValue.setText(Helper.shortCurrencyFormat(walletBalance.getAvailable().doubleValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setFilter(String filter) {
|
||||
currentFilter = filter;
|
||||
updateSuggestedTags(currentFilter, SUGGESTED_LIMIT, true);
|
||||
}
|
||||
|
||||
private void updateSuggestedTags(String filter, int limit, boolean clearPrevious) {
|
||||
UpdateSuggestedTagsTask task = new UpdateSuggestedTagsTask(filter, limit, addedTagsAdapter, suggestedTagsAdapter, clearPrevious, new UpdateSuggestedTagsTask.KnownTagsHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Tag> tags) {
|
||||
if (suggestedTagsAdapter == null) {
|
||||
suggestedTagsAdapter = new TagListAdapter(tags, getContext());
|
||||
suggestedTagsAdapter.setCustomizeMode(TagListAdapter.CUSTOMIZE_MODE_ADD);
|
||||
suggestedTagsAdapter.setClickListener(ChannelFormFragment.this);
|
||||
if (suggestedTagsList != null) {
|
||||
suggestedTagsList.setAdapter(suggestedTagsAdapter);
|
||||
}
|
||||
} else {
|
||||
suggestedTagsAdapter.setTags(tags);
|
||||
}
|
||||
|
||||
checkNoAddedTags();
|
||||
checkNoTagResults();
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private Claim buildChannelClaimToSave() {
|
||||
Claim claim = new Claim();
|
||||
if (!editMode) {
|
||||
String name = Helper.getValue(inputChannelName.getText());
|
||||
if (!name.startsWith("@")) {
|
||||
name = String.format("@%s", name);
|
||||
}
|
||||
claim.setName(name);
|
||||
} else if (currentClaim != null) {
|
||||
claim.setClaimId(currentClaim.getClaimId());
|
||||
}
|
||||
|
||||
Claim.ChannelMetadata metadata = new Claim.ChannelMetadata();
|
||||
metadata.setTitle(Helper.getValue(inputTitle.getText()));
|
||||
metadata.setDescription(Helper.getValue(inputDescription.getText()));
|
||||
metadata.setWebsiteUrl(Helper.getValue(inputWebsite.getText()));
|
||||
metadata.setEmail(Helper.getValue(inputEmail.getText()));
|
||||
|
||||
Claim.Resource cover = new Claim.Resource();
|
||||
cover.setUrl(coverUrl == null ? "" : coverUrl);
|
||||
Claim.Resource thumbnail = new Claim.Resource();
|
||||
thumbnail.setUrl(thumbnailUrl == null ? "" : thumbnailUrl);
|
||||
metadata.setThumbnail(thumbnail);
|
||||
metadata.setCover(cover);
|
||||
|
||||
List<Tag> addedTags = addedTagsAdapter != null ? new ArrayList<>(addedTagsAdapter.getTags()) : new ArrayList<>();
|
||||
metadata.setTags(Helper.getTagsForTagObjects(addedTags));
|
||||
|
||||
claim.setValue(metadata);
|
||||
return claim;
|
||||
}
|
||||
|
||||
private void preSave() {
|
||||
saveInProgress = true;
|
||||
Helper.setViewVisibility(linkShowOptional, View.GONE);
|
||||
Helper.setViewEnabled(linkCancel, false);
|
||||
Helper.setViewEnabled(buttonSave, false);
|
||||
}
|
||||
|
||||
private void postSave() {
|
||||
Helper.setViewVisibility(linkShowOptional, View.VISIBLE);
|
||||
Helper.setViewEnabled(linkCancel, true);
|
||||
Helper.setViewEnabled(buttonSave, true);
|
||||
saveInProgress = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTagClicked(Tag tag, int customizeMode) {
|
||||
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {
|
||||
addTag(tag);
|
||||
} else if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_REMOVE) {
|
||||
removeTag(tag);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,8 +14,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
|
@ -37,6 +35,7 @@ import io.lbry.browser.exceptions.LbryUriException;
|
|||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.tasks.ChannelSubscribeTask;
|
||||
import io.lbry.browser.tasks.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.ResolveTask;
|
||||
import io.lbry.browser.ui.BaseFragment;
|
||||
import io.lbry.browser.ui.controls.SolidIconView;
|
||||
|
@ -196,7 +195,10 @@ public class ChannelFragment extends BaseFragment {
|
|||
boolean isFollowing = Lbryio.isFollowing(claim);
|
||||
if (iconFollowUnfollow != null) {
|
||||
iconFollowUnfollow.setText(isFollowing ? R.string.fa_heart_broken : R.string.fa_heart);
|
||||
iconFollowUnfollow.setTextColor(ContextCompat.getColor(getContext(), isFollowing ? R.color.foreground : R.color.red));
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
iconFollowUnfollow.setTextColor(ContextCompat.getColor(context, isFollowing ? R.color.foreground : R.color.red));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +246,7 @@ public class ChannelFragment extends BaseFragment {
|
|||
|
||||
private void resolveUrl() {
|
||||
layoutDisplayArea.setVisibility(View.INVISIBLE);
|
||||
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, layoutResolving, new ResolveTask.ResolveResultHandler() {
|
||||
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, layoutResolving, new ClaimListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Claim> claims) {
|
||||
if (claims.size() > 0) {
|
||||
|
@ -300,8 +302,10 @@ public class ChannelFragment extends BaseFragment {
|
|||
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
|
||||
Helper.setIconViewBackgroundColor(noThumbnailView, bgColor, false, getContext());
|
||||
noThumbnailView.setVisibility(View.VISIBLE);
|
||||
if (claim.getName() != null) {
|
||||
textAlpha.setText(claim.getName().substring(1, 2));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (tabPager.getAdapter() == null) {
|
||||
|
@ -332,16 +336,20 @@ public class ChannelFragment extends BaseFragment {
|
|||
switch (position) {
|
||||
case 0:
|
||||
ChannelContentFragment contentFragment = ChannelContentFragment.class.newInstance();
|
||||
if (channelClaim != null) {
|
||||
contentFragment.setChannelId(channelClaim.getClaimId());
|
||||
}
|
||||
return contentFragment;
|
||||
|
||||
case 1:
|
||||
ChannelAboutFragment aboutFragment = ChannelAboutFragment.class.newInstance();
|
||||
try {
|
||||
Claim.ChannelMetadata metadata = (Claim.ChannelMetadata) channelClaim.getValue();
|
||||
if (metadata != null) {
|
||||
aboutFragment.setDescription(metadata.getDescription());
|
||||
aboutFragment.setEmail(metadata.getEmail());
|
||||
aboutFragment.setWebsite(metadata.getWebsiteUrl());
|
||||
}
|
||||
} catch (ClassCastException ex) {
|
||||
// pass
|
||||
}
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
package io.lbry.browser.ui.channel;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
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.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
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 java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
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.model.NavMenuItem;
|
||||
import io.lbry.browser.tasks.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.ClaimListTask;
|
||||
import io.lbry.browser.ui.BaseFragment;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
|
||||
public class ChannelManagerFragment extends BaseFragment implements ActionMode.Callback, SelectionModeListener, SdkStatusListener {
|
||||
|
||||
private Button buttonNewChannel;
|
||||
private FloatingActionButton fabNewChannel;
|
||||
private ActionMode actionMode;
|
||||
private View emptyView;
|
||||
private View layoutSdkInitializing;
|
||||
private ProgressBar loading;
|
||||
private ProgressBar bigLoading;
|
||||
private RecyclerView channelList;
|
||||
private ClaimListAdapter adapter;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_channel_manager, container, false);
|
||||
|
||||
|
||||
buttonNewChannel = root.findViewById(R.id.channel_manager_create_button);
|
||||
fabNewChannel = root.findViewById(R.id.channel_manager_fab_new_channel);
|
||||
buttonNewChannel.setOnClickListener(newChannelClickListener);
|
||||
fabNewChannel.setOnClickListener(newChannelClickListener);
|
||||
|
||||
emptyView = root.findViewById(R.id.channel_manager_empty_container);
|
||||
layoutSdkInitializing = root.findViewById(R.id.container_sdk_initializing);
|
||||
channelList = root.findViewById(R.id.channel_manager_list);
|
||||
LinearLayoutManager llm = new LinearLayoutManager(getContext());
|
||||
channelList.setLayoutManager(llm);
|
||||
loading = root.findViewById(R.id.channel_manager_list_loading);
|
||||
bigLoading = root.findViewById(R.id.channel_manager_list_big_loading);
|
||||
|
||||
layoutSdkInitializing.setVisibility(Lbry.SDK_READY ? View.GONE : View.VISIBLE);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private View.OnClickListener newChannelClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).openChannelForm(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) context).setWunderbarValue(null);
|
||||
}
|
||||
|
||||
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(fabNewChannel, View.VISIBLE);
|
||||
if (adapter != null && channelList != null) {
|
||||
channelList.setAdapter(adapter);
|
||||
}
|
||||
fetchChannels();
|
||||
}
|
||||
|
||||
public View getLoading() {
|
||||
return (adapter == null || adapter.getItemCount() == 0) ? bigLoading : loading;
|
||||
}
|
||||
|
||||
private void checkNoChannels() {
|
||||
Helper.setViewVisibility(emptyView, adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void fetchChannels() {
|
||||
Helper.setViewVisibility(emptyView, View.GONE);
|
||||
ClaimListTask task = new ClaimListTask(Claim.TYPE_CHANNEL, getLoading(), new ClaimListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Claim> claims) {
|
||||
Lbry.ownChannels = new ArrayList<>(claims);
|
||||
Context context = getContext();
|
||||
if (adapter == null) {
|
||||
adapter = new ClaimListAdapter(claims, context);
|
||||
adapter.setSelectionModeListener(ChannelManagerFragment.this);
|
||||
adapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
|
||||
@Override
|
||||
public void onClaimClicked(Claim claim) {
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).openChannelClaim(claim);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (channelList != null) {
|
||||
channelList.setAdapter(adapter);
|
||||
}
|
||||
} else {
|
||||
adapter.setItems(claims);
|
||||
}
|
||||
|
||||
checkNoChannels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
checkNoChannels();
|
||||
}
|
||||
});
|
||||
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(ChannelFormFragment.class, true, NavMenuItem.ID_ITEM_CHANNELS, 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_channels, 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;
|
||||
}
|
||||
}
|
|
@ -65,8 +65,13 @@ public class EditorsChoiceFragment extends BaseFragment {
|
|||
}
|
||||
|
||||
private Map<String, Object> buildContentOptions() {
|
||||
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_REPOST,
|
||||
null,
|
||||
|
|
|
@ -38,6 +38,7 @@ import io.lbry.browser.exceptions.LbryUriException;
|
|||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.tasks.ChannelSubscribeTask;
|
||||
import io.lbry.browser.tasks.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.ClaimSearchTask;
|
||||
import io.lbry.browser.tasks.FetchSubscriptionsTask;
|
||||
import io.lbry.browser.tasks.ResolveTask;
|
||||
|
@ -266,7 +267,6 @@ public class FollowingFragment extends BaseFragment implements
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
|
@ -389,8 +389,12 @@ public class FollowingFragment extends BaseFragment implements
|
|||
}
|
||||
|
||||
private Map<String, Object> buildContentOptions() {
|
||||
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_STREAM,
|
||||
|
@ -467,7 +471,7 @@ public class FollowingFragment extends BaseFragment implements
|
|||
private void fetchAndResolveChannelList() {
|
||||
buildChannelIdsAndUrls();
|
||||
if (channelIds.size() > 0) {
|
||||
ResolveTask resolveSubscribedTask = new ResolveTask(channelUrls, Lbry.LBRY_TV_CONNECTION_STRING, channelListLoading, new ResolveTask.ResolveResultHandler() {
|
||||
ResolveTask resolveSubscribedTask = new ResolveTask(channelUrls, Lbry.LBRY_TV_CONNECTION_STRING, channelListLoading, new ClaimListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Claim> claims) {
|
||||
updateChannelFilterListAdapter(claims, true);
|
||||
|
|
|
@ -21,6 +21,7 @@ import io.lbry.browser.R;
|
|||
import io.lbry.browser.adapter.ClaimListAdapter;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.ClaimCacheKey;
|
||||
import io.lbry.browser.tasks.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.ClaimSearchTask;
|
||||
import io.lbry.browser.tasks.LighthouseSearchTask;
|
||||
import io.lbry.browser.tasks.ResolveTask;
|
||||
|
@ -138,7 +139,7 @@ public class SearchFragment extends BaseFragment implements
|
|||
return;
|
||||
}
|
||||
|
||||
ResolveTask task = new ResolveTask(vanityUrl, Lbry.LBRY_TV_CONNECTION_STRING, null, new ResolveTask.ResolveResultHandler() {
|
||||
ResolveTask task = new ResolveTask(vanityUrl, Lbry.LBRY_TV_CONNECTION_STRING, null, new ClaimListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<Claim> claims) {
|
||||
if (claims.size() > 0) {
|
||||
|
|
|
@ -122,6 +122,7 @@ public class TransactionHistoryFragment extends BaseFragment implements Transact
|
|||
MainActivity activity = (MainActivity) getContext();
|
||||
if (activity != null) {
|
||||
activity.hideSearchBar();
|
||||
activity.hideFloatingWalletBalance();
|
||||
activity.showNavigationBackIcon();
|
||||
activity.lockDrawer();
|
||||
|
||||
|
@ -136,7 +137,9 @@ public class TransactionHistoryFragment extends BaseFragment implements Transact
|
|||
public void onStop() {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).restoreToggle();
|
||||
MainActivity activity = (MainActivity) context;
|
||||
activity.restoreToggle();
|
||||
activity.showFloatingWalletBalance();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
|
|
@ -51,8 +51,6 @@ import io.lbry.browser.utils.Lbryio;
|
|||
|
||||
public class WalletFragment extends BaseFragment implements SdkStatusListener, WalletBalanceListener {
|
||||
|
||||
private boolean sdkReady;
|
||||
|
||||
private View layoutAccountRecommended;
|
||||
private View layoutSdkInitializing;
|
||||
private View linkSkipAccount;
|
||||
|
@ -96,7 +94,7 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
|
|||
|
||||
loadingRecentContainer = root.findViewById(R.id.wallet_loading_recent_container);
|
||||
layoutAccountRecommended = root.findViewById(R.id.wallet_account_recommended_container);
|
||||
layoutSdkInitializing = root.findViewById(R.id.wallet_sdk_initializing_container);
|
||||
layoutSdkInitializing = root.findViewById(R.id.container_sdk_initializing);
|
||||
linkSkipAccount = root.findViewById(R.id.wallet_skip_account_link);
|
||||
buttonSignUp = root.findViewById(R.id.wallet_sign_up_button);
|
||||
|
||||
|
@ -441,7 +439,6 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
|
|||
}
|
||||
|
||||
public void onSdkReady() {
|
||||
sdkReady = true;
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).removeSdkStatusListener(this);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package io.lbry.browser.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
@ -9,7 +11,11 @@ import android.graphics.drawable.ColorDrawable;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -20,6 +26,7 @@ import org.json.JSONException;
|
|||
import org.json.JSONObject;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -46,6 +53,7 @@ public final class Helper {
|
|||
public static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded");
|
||||
public static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8");
|
||||
public static final int CONTENT_PAGE_SIZE = 25;
|
||||
public static final double MIN_DEPOSIT = 0.05;
|
||||
|
||||
public static boolean isNull(String value) {
|
||||
return value == null;
|
||||
|
@ -340,4 +348,192 @@ public final class Helper {
|
|||
}
|
||||
return String.format("%s %s", Build.MANUFACTURER, Build.MODEL);
|
||||
}
|
||||
|
||||
public static boolean channelExists(String channelName) {
|
||||
for (Claim claim : Lbry.ownChannels) {
|
||||
if (channelName.equalsIgnoreCase(claim.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getRealPathFromURI_API19(final Context context, final Uri uri) {
|
||||
return getRealPathFromURI_API19(context, uri, false);
|
||||
}
|
||||
/**
|
||||
* https://gist.github.com/HBiSoft/15899990b8cd0723c3a894c1636550a8
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
public static String getRealPathFromURI_API19(final Context context, final Uri uri, boolean folderPath) {
|
||||
|
||||
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
|
||||
// DocumentProvider
|
||||
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
|
||||
// ExternalStorageProvider
|
||||
if (isExternalStorageDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
// This is for checking Main Memory
|
||||
if ("primary".equalsIgnoreCase(type)) {
|
||||
if (split.length > 1) {
|
||||
return Environment.getExternalStorageDirectory() + "/" + split[1];
|
||||
} else {
|
||||
return Environment.getExternalStorageDirectory() + "/";
|
||||
}
|
||||
// This is for checking SD Card
|
||||
} else {
|
||||
return "storage" + "/" + docId.replace(":", "/");
|
||||
}
|
||||
|
||||
}
|
||||
// DownloadsProvider
|
||||
else if (isDownloadsDocument(uri)) {
|
||||
String fileName = getFilePath(context, uri);
|
||||
if (fileName != null) {
|
||||
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
|
||||
return folderPath ?
|
||||
String.format("%s/Download", extStorageDirectory) :
|
||||
String.format("%s/Download/%s", extStorageDirectory, fileName);
|
||||
}
|
||||
|
||||
String id = DocumentsContract.getDocumentId(uri);
|
||||
if (id.startsWith("raw:")) {
|
||||
id = id.replaceFirst("raw:", "");
|
||||
File file = new File(id);
|
||||
if (file.exists())
|
||||
return id;
|
||||
}
|
||||
|
||||
String[] contentUriPrefixesToTry = new String[]{
|
||||
"content://downloads/public_downloads",
|
||||
"content://downloads/my_downloads",
|
||||
"content://downloads/all_downloads"
|
||||
};
|
||||
|
||||
for (String contentUriPrefix : contentUriPrefixesToTry) {
|
||||
Uri contentUri = Helper.parseInt(id, -1) > 0 ?
|
||||
ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id)) :
|
||||
Uri.parse(contentUriPrefix);
|
||||
try {
|
||||
String path = getDataColumn(context, contentUri, null, null);
|
||||
if (path != null) {
|
||||
return path;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
// MediaProvider
|
||||
else if (isMediaDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
Uri contentUri = null;
|
||||
if ("image".equals(type)) {
|
||||
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("video".equals(type)) {
|
||||
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("audio".equals(type)) {
|
||||
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
|
||||
final String selection = "_id=?";
|
||||
final String[] selectionArgs = new String[]{
|
||||
split[1]
|
||||
};
|
||||
|
||||
return getDataColumn(context, contentUri, selection, selectionArgs);
|
||||
}
|
||||
}
|
||||
// MediaStore (and general)
|
||||
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
|
||||
// Return the remote address
|
||||
if (isGooglePhotosUri(uri))
|
||||
return uri.getLastPathSegment();
|
||||
|
||||
return getDataColumn(context, uri, null, null);
|
||||
}
|
||||
// File
|
||||
else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getFilePath(Context context, Uri uri) {
|
||||
Cursor cursor = null;
|
||||
final String[] projection = { MediaStore.MediaColumns.DISPLAY_NAME };
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
|
||||
return cursor.getString(index);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
|
||||
Cursor cursor = null;
|
||||
final String column = "_data";
|
||||
final String[] projection = {
|
||||
column
|
||||
};
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int index = cursor.getColumnIndexOrThrow(column);
|
||||
return cursor.getString(index);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is ExternalStorageProvider.
|
||||
*/
|
||||
public static boolean isExternalStorageDocument(Uri uri) {
|
||||
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is DownloadsProvider.
|
||||
*/
|
||||
public static boolean isDownloadsDocument(Uri uri) {
|
||||
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is MediaProvider.
|
||||
*/
|
||||
public static boolean isMediaDocument(Uri uri) {
|
||||
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is Google Photos.
|
||||
*/
|
||||
public static boolean isGooglePhotosUri(Uri uri) {
|
||||
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ public final class Lbry {
|
|||
public static WalletBalance walletBalance = new WalletBalance();
|
||||
public static List<Tag> knownTags = new ArrayList<>();
|
||||
public static List<Tag> followedTags = new ArrayList<>();
|
||||
public static List<Claim> ownClaims = new ArrayList<>();
|
||||
public static List<Claim> ownChannels = new ArrayList<>(); // Make this a subset of ownClaims?
|
||||
|
||||
public static final int TTL_CLAIM_SEARCH_VALUE = 120000; // 2-minute TTL for cache
|
||||
public static final String SDK_CONNECTION_STRING = "http://127.0.0.1:5279";
|
||||
|
@ -87,6 +89,12 @@ public final class Lbry {
|
|||
public static final String METHOD_PREFERENCE_GET = "preference_get";
|
||||
public static final String METHOD_PREFERENCE_SET = "preference_set";
|
||||
|
||||
public static final String METHOD_CHANNEL_ABANDON = "channel_abandon";
|
||||
public static final String METHOD_CHANNEL_CREATE = "channel_create";
|
||||
public static final String METHOD_CHANNEL_UPDATE = "channel_update";
|
||||
|
||||
public static final String METHOD_CLAIM_LIST = "claim_list";
|
||||
|
||||
public static KeyStore KEYSTORE;
|
||||
public static boolean SDK_READY = false;
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@ public class LbryUri {
|
|||
return (!Helper.isNullOrEmpty(channelName) && Helper.isNullOrEmpty(streamName)) || (!Helper.isNullOrEmpty(claimName) && claimName.startsWith("@"));
|
||||
}
|
||||
|
||||
public static boolean isNameValid(String name) {
|
||||
return !name.matches(REGEX_INVALID_URI);
|
||||
}
|
||||
|
||||
public static LbryUri tryParse(String url) {
|
||||
try {
|
||||
return parse(url, false);
|
||||
|
|
4
app/src/main/res/drawable/bg_channel_overlay_icon.xml
Normal file
4
app/src/main/res/drawable/bg_channel_overlay_icon.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<solid android:color="@color/overlay" />
|
||||
</shape>
|
9
app/src/main/res/drawable/bg_selected_list_item.xml
Normal file
9
app/src/main/res/drawable/bg_selected_list_item.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true">
|
||||
<color android:color="@color/nextLbryGreenSemiTransparent" />
|
||||
</item>
|
||||
<item>
|
||||
<color android:color="@android:color/transparent" />
|
||||
</item>
|
||||
</selector>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="@android:color/holo_blue_bright"/>
|
||||
<solid android:color="@color/overlay" />
|
||||
</shape>
|
31
app/src/main/res/layout/container_sdk_initializing.xml
Normal file
31
app/src/main/res/layout/container_sdk_initializing.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container_sdk_initializing"
|
||||
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/sdk_still_initializing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="16sp"
|
||||
android:textAlignment="center" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
57
app/src/main/res/layout/form_tag_search.xml
Normal file
57
app/src/main/res/layout/form_tag_search.xml
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/form_added_tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/form_no_added_tags"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/no_added_tags"
|
||||
android:textSize="14sp"
|
||||
android:textFontWeight="300"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0.5dp"
|
||||
android:background="@color/divider"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/form_suggested_tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/form_no_tag_results"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/form_no_tag_results"
|
||||
android:textSize="14sp"
|
||||
android:textFontWeight="300"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="16dp">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/form_tag_filter_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/search_for_more_tags"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="14sp"
|
||||
android:textFontWeight="300" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
333
app/src/main/res/layout/fragment_channel_form.xml
Normal file
333
app/src/main/res/layout/fragment_channel_form.xml
Normal file
|
@ -0,0 +1,333 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
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/pageBackground">
|
||||
<LinearLayout
|
||||
android:id="@+id/channel_form_display_area"
|
||||
android:clipChildren="false"
|
||||
android:elevation="4dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="10"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<RelativeLayout
|
||||
android:id="@+id/channel_form_cover_edit_area"
|
||||
android:clickable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="220dp">
|
||||
<ImageView
|
||||
android:id="@+id/channel_form_cover_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/default_channel_cover"
|
||||
android:scaleType="centerCrop" />
|
||||
<ImageView
|
||||
android:id="@+id/channel_form_cover_edit_icon"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:src="@drawable/ic_edit"
|
||||
android:tint="@color/white" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/channel_form_upload_progress"
|
||||
android:background="@color/channelCoverBackground"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:visibility="gone">
|
||||
<ProgressBar
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/uploading"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
<RelativeLayout
|
||||
android:id="@+id/channel_form_icon_container"
|
||||
android:foreground=" ?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_centerHorizontal="true">
|
||||
<RelativeLayout
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/bg_channel_icon"
|
||||
android:id="@+id/channel_form_no_thumbnail"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="90dp">
|
||||
<TextView
|
||||
android:id="@+id/channel_form_icon_alpha"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="48sp"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
</RelativeLayout>
|
||||
<ImageView
|
||||
android:id="@+id/channel_form_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<ImageView
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:src="@drawable/ic_edit"
|
||||
android:tint="@color/white" />
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/title">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/channel_form_input_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp">
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/channel_form_input_channel_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:hint="@string/channel_name"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<TextView
|
||||
android:id="@+id/channel_form_at_prefix"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="28dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:text="@string/at"
|
||||
android:visibility="gone" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/channel_form_input_layout_deposit"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/deposit">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/channel_form_input_deposit"
|
||||
android:fontFamily="@font/inter"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="numberDecimal" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/channel_form_input_currency"
|
||||
android:layout_toRightOf="@id/channel_form_input_layout_deposit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/lbc"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="10sp"
|
||||
android:textFontWeight="300" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/channel_form_inline_balance_container"
|
||||
android:layout_toRightOf="@id/channel_form_input_currency"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_marginTop="28dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="invisible">
|
||||
<io.lbry.browser.ui.controls.SolidIconView
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:text="@string/fa_coins" />
|
||||
<TextView
|
||||
android:id="@+id/channel_form_inline_balance_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textFontWeight="300"
|
||||
android:layout_marginLeft="2dp" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/deposit_remains_yours"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/channel_form_optional_fields_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/description">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/channel_form_input_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:inputType="textMultiLine"
|
||||
android:singleLine="false"
|
||||
android:scrollbars="vertical"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="@string/website">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/channel_form_input_website"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="@string/email">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/channel_form_input_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/tags"
|
||||
android:textFontWeight="600"
|
||||
android:textSize="14sp" />
|
||||
<include layout="@layout/form_tag_search" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp">
|
||||
<TextView
|
||||
android:id="@+id/channel_form_cancel_link"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="12sp"
|
||||
android:text="@string/cancel" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/channel_form_toggle_optional"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="24dp"
|
||||
android:layout_toLeftOf="@id/channel_form_save_button"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="12sp"
|
||||
android:text="@string/show_optional_fields" />
|
||||
<ProgressBar
|
||||
android:id="@+id/channel_form_save_progress"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="24dp"
|
||||
android:layout_toLeftOf="@+id/channel_form_save_button"
|
||||
android:visibility="gone" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/channel_form_save_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/save" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
72
app/src/main/res/layout/fragment_channel_manager.xml
Normal file
72
app/src/main/res/layout/fragment_channel_manager.xml
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?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">
|
||||
<ProgressBar
|
||||
android:id="@+id/channel_manager_list_big_loading"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
<ProgressBar
|
||||
android:id="@+id/channel_manager_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/channel_manager_list"
|
||||
android:clipToPadding="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<RelativeLayout
|
||||
android:id="@+id/channel_manager_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/channel_manager_create_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/create_a_channel" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
<include layout="@layout/container_sdk_initializing" />
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/channel_manager_fab_new_channel"
|
||||
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>
|
|
@ -30,35 +30,7 @@
|
|||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/wallet_sdk_initializing_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/sdk_still_initializing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="16sp"
|
||||
android:textAlignment="center" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
<include layout="@layout/container_sdk_initializing" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/wallet_account_recommended_container"
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:background="@drawable/bg_selected_list_item">
|
||||
<LinearLayout
|
||||
android:id="@+id/claim_repost_info"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -106,6 +107,20 @@
|
|||
android:textSize="14sp"
|
||||
android:textFontWeight="300" />
|
||||
</LinearLayout>
|
||||
<RelativeLayout
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/bg_channel_overlay_icon"
|
||||
android:id="@+id/claim_selected_overlay"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="90dp"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/ic_check"
|
||||
android:tint="@color/nextLbryGreen" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
@ -117,6 +117,20 @@
|
|||
android:textSize="14sp"
|
||||
android:textFontWeight="300" />
|
||||
</LinearLayout>
|
||||
<RelativeLayout
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/bg_stream_overlay_icon"
|
||||
android:id="@+id/claim_selected_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/ic_check"
|
||||
android:tint="@color/nextLbryGreen" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
@ -121,6 +121,20 @@
|
|||
android:textSize="14sp"
|
||||
android:textFontWeight="300" />
|
||||
</LinearLayout>
|
||||
<RelativeLayout
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/bg_stream_overlay_icon"
|
||||
android:id="@+id/claim_selected_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/ic_check"
|
||||
android:tint="@color/nextLbryGreen" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
|
16
app/src/main/res/menu/menu_claim_list.xml
Normal file
16
app/src/main/res/menu/menu_claim_list.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_edit"
|
||||
android:icon="@drawable/ic_edit"
|
||||
android:title="@string/edit"
|
||||
app:iconTint="@color/actionBarForeground"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/action_delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete"
|
||||
app:iconTint="@color/actionBarForeground"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
|
@ -25,6 +25,7 @@
|
|||
<color name="brighterLbryGreen">#40B887</color>
|
||||
<color name="lbryGreen">#2F9176</color>
|
||||
<color name="nextLbryGreen">#38D9A9</color>
|
||||
<color name="nextLbryGreenSemiTransparent">#3338D9A9</color>
|
||||
<color name="tagGreen">#329A7E</color>
|
||||
<color name="tagGrape">#77D510B8</color>
|
||||
|
||||
|
@ -49,4 +50,5 @@
|
|||
<color name="thumbnailPlaceholder">#D5D5D5</color>
|
||||
|
||||
<color name="caption">#CAEDB9</color>
|
||||
<color name="overlay">#CC333333</color>
|
||||
</resources>
|
|
@ -24,6 +24,7 @@
|
|||
<color name="brighterLbryGreen">#40B887</color>
|
||||
<color name="lbryGreen">#2F9176</color>
|
||||
<color name="nextLbryGreen">#38D9A9</color>
|
||||
<color name="nextLbryGreenSemiTransparent">#3338D9A9</color>
|
||||
<color name="tagGreen">#E3F6F1</color>
|
||||
<color name="tagGrape">#77F255DA</color>
|
||||
|
||||
|
@ -48,4 +49,5 @@
|
|||
<color name="thumbnailPlaceholder">#D5D5D5</color>
|
||||
|
||||
<color name="caption">#CAEDB9</color>
|
||||
<color name="overlay">#CC333333</color>
|
||||
</resources>
|
|
@ -194,7 +194,7 @@
|
|||
<string name="search_for_more_tags">Search for more tags</string>
|
||||
<string name="no_followed_tags">You have not followed any tags yet. Get started by adding tags that you are interested in!</string>
|
||||
<string name="no_tag_results">We could not find new tags that you\'re not following.</string>
|
||||
<string name="tag_already_followed">The \'%1$s\' tag has already been added.</string>
|
||||
<string name="tag_already_added">The \'%1$s\' tag has already been added.</string>
|
||||
<string name="send_a_tip">Send a tip</string>
|
||||
<string name="send_a_tip_to">Send a tip to %1$s</string>
|
||||
<string name="send_tip_info_content">This will appear as a tip for %1$s, which will boost its ability to be discovered while active. <a href="https://lbry.com/faq/tipping">Learn more</a>.</string>
|
||||
|
@ -225,6 +225,52 @@
|
|||
<string name="enable_sync">Enable sync</string>
|
||||
<string name="wallet_sync_op_failed">The wallet sync operation could not be completed at this time. Please try again later. If this problem persists, please send an email to hello@lbry.com.</string>
|
||||
|
||||
<!-- Forms -->
|
||||
<string name="no_added_tags">You have not added any tags yet. Add tags to improve discovery.</string>
|
||||
<string name="form_no_tag_results">We could not find new tags that have not been added yet.</string>
|
||||
|
||||
<!-- Channels -->
|
||||
<string name="no_channel_created">You have not created a channel.\nStart now by creating a new channel!</string>
|
||||
<string name="create_a_channel">Create a channel</string>
|
||||
<string name="edit_channel">Edit channel</string>
|
||||
<string name="delete_selection">Delete selection?</string>
|
||||
<string name="description">Description</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="show_extra">Show extra</string>
|
||||
<string name="hide_extra">Hide extra</string>
|
||||
<string name="show_optional_fields">Show optional fields</string>
|
||||
<string name="hide_optional_fields">Hide optional fields</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="channel_name">Channel name</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="at">\@</string>
|
||||
<string name="deposit">Deposit</string>
|
||||
<string name="deposit_remains_yours">This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.</string>
|
||||
<string name="storage_permission_rationale_images">LBRY requires access to load images from your device storage.</string>
|
||||
<string name="select_thumbnail">Select thumbnail</string>
|
||||
<string name="select_cover">Select cover image</string>
|
||||
<string name="undetermined_image_filepath">The file path could not be determined for the selected image. Please select an image in a different location.</string>
|
||||
<string name="wait_for_upload">Please wait for the current upload to finish.</string>
|
||||
<string name="image_upload_failed">The image upload request failed. Please try again.</string>
|
||||
<string name="uploading">Uploading...</string>
|
||||
<string name="please_enter_channel_name">Please enter a channel name.</string>
|
||||
<string name="channel_name_invalid_characters">Your channel name contains invalid characters.</string>
|
||||
<string name="channel_name_already_created">You have already created a channel with the same name.</string>
|
||||
<string name="please_enter_valid_deposit">Please enter a valid deposit amount.</string>
|
||||
<string name="deposit_more_than_balance">Deposit cannot be higher than your balance.</string>
|
||||
<string name="channel_save_failed">The channel save request failed. Please try again.</string>
|
||||
<string name="channel_save_successful">The channel was successfully saved.</string>
|
||||
<string name="channel_pending_blockchain">The channel is pending publish on the blockchain. You will be able to access or edit the channel in a few moments.</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>
|
||||
</plurals>
|
||||
<plurals name="confirm_delete_channels">
|
||||
<item quantity="one">Are you sure you want to delete the selected channel?</item>
|
||||
<item quantity="other">Are you sure you want to delete the selected channels?</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<string name="fa_gift"></string>
|
||||
<string name="fa_lock"></string>
|
||||
|
|
Loading…
Reference in a new issue