mirror of
https://framagit.org/tom79/fedilab-tube
synced 2025-02-09 08:38:50 +01:00
Allow to edit channel and playlists
This commit is contained in:
parent
bb2c129762
commit
c714e6a625
@ -31,6 +31,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.Format;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -874,6 +875,28 @@ public class PeertubeAPI {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a channel fot the authenticated user
|
||||
*
|
||||
* @param acct String
|
||||
* @param channelCreation ChannelCreation
|
||||
*/
|
||||
public void updateChannel(String acct, ChannelCreation channelCreation) throws HttpsConnection.HttpsConnectionException {
|
||||
actionCode = -1;
|
||||
try {
|
||||
HashMap<String, String> params = new HashMap<>();
|
||||
params.put("displayName", channelCreation.getDisplayName());
|
||||
params.put("name", channelCreation.getName());
|
||||
params.put("description", channelCreation.getDescription());
|
||||
params.put("support", channelCreation.getSupport());
|
||||
HttpsConnection httpsConnection = new HttpsConnection(context);
|
||||
httpsConnection.put(getAbsoluteUrl(String.format("/video-channels/%s", acct)), 30, params, prefKeyOauthTokenT);
|
||||
actionCode = httpsConnection.getActionCode();
|
||||
} catch (NoSuchAlgorithmException | IOException | KeyManagementException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Channel
|
||||
*
|
||||
|
@ -16,11 +16,20 @@ package app.fedilab.fedilabtube.client.entities;
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
public class ChannelCreation {
|
||||
private String id;
|
||||
private String displayName;
|
||||
private String name;
|
||||
private String description;
|
||||
private String support;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import android.text.util.Linkify;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
@ -33,6 +34,7 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
@ -43,6 +45,7 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.fedilab.fedilabtube.AccountActivity;
|
||||
import app.fedilab.fedilabtube.R;
|
||||
import app.fedilab.fedilabtube.ShowAccountActivity;
|
||||
import app.fedilab.fedilabtube.client.APIResponse;
|
||||
@ -59,6 +62,7 @@ import es.dmoral.toasty.Toasty;
|
||||
public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
public AllAccountsRemoved allAccountsRemoved;
|
||||
public EditAlertDialog editAlertDialog;
|
||||
private List<Account> accounts;
|
||||
private Context context;
|
||||
private AccountsListAdapter accountsListAdapter;
|
||||
@ -83,7 +87,8 @@ public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
final AccountsListAdapter.ViewHolder holder = (AccountsListAdapter.ViewHolder) viewHolder;
|
||||
final Account account = accounts.get(position);
|
||||
if (type == AccountsVM.accountFetch.CHANNEL) {
|
||||
holder.account_action.show();
|
||||
holder.account_action.hide();
|
||||
holder.more_actions.setVisibility(View.VISIBLE);
|
||||
holder.account_action.setImageResource(R.drawable.ic_baseline_delete_24);
|
||||
holder.account_action.setContentDescription(context.getString(R.string.delete_channel));
|
||||
holder.account_action.setOnClickListener(view -> {
|
||||
@ -99,15 +104,10 @@ public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
new PeertubeAPI(context).deleteChannel(account.getAcct());
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
DisplayPlaylistsFragment displayPlaylistsFragment;
|
||||
if (context == null)
|
||||
return;
|
||||
displayPlaylistsFragment = (DisplayPlaylistsFragment) ((AppCompatActivity) context).getSupportFragmentManager().findFragmentByTag("CHANNELS");
|
||||
final FragmentTransaction ft = ((AppCompatActivity) context).getSupportFragmentManager().beginTransaction();
|
||||
if (displayPlaylistsFragment != null) {
|
||||
ft.detach(displayPlaylistsFragment);
|
||||
ft.attach(displayPlaylistsFragment);
|
||||
ft.commit();
|
||||
accounts.remove(account);
|
||||
notifyDataSetChanged();
|
||||
if (accounts.size() == 0) {
|
||||
allAccountsRemoved.onAllAccountsRemoved();
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
@ -169,6 +169,65 @@ public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
holder.account_action.setImageResource(R.drawable.ic_baseline_volume_mute_24);
|
||||
}
|
||||
|
||||
holder.more_actions.setOnClickListener(view -> {
|
||||
PopupMenu popup = new PopupMenu(context, holder.more_actions);
|
||||
popup.getMenuInflater()
|
||||
.inflate(R.menu.playlist_menu, popup.getMenu());
|
||||
popup.setOnMenuItemClickListener(item -> {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_delete:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(context.getString(R.string.action_channel_delete) + ": " + account.getAcct());
|
||||
builder.setMessage(context.getString(R.string.action_channel_confirm_delete));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
accounts.remove(account);
|
||||
notifyDataSetChanged();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
new PeertubeAPI(context).deleteChannel(account.getAcct());
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
DisplayPlaylistsFragment displayPlaylistsFragment;
|
||||
if (context == null)
|
||||
return;
|
||||
displayPlaylistsFragment = (DisplayPlaylistsFragment) ((AppCompatActivity) context).getSupportFragmentManager().findFragmentByTag("CHANNELS");
|
||||
final FragmentTransaction ft = ((AppCompatActivity) context).getSupportFragmentManager().beginTransaction();
|
||||
if (displayPlaylistsFragment != null) {
|
||||
ft.detach(displayPlaylistsFragment);
|
||||
ft.attach(displayPlaylistsFragment);
|
||||
ft.commit();
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
} catch (HttpsConnection.HttpsConnectionException e) {
|
||||
e.printStackTrace();
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
if (e.getMessage() != null) {
|
||||
Toasty.error(context, e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}
|
||||
}).start();
|
||||
dialog.dismiss();
|
||||
})
|
||||
.setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
break;
|
||||
case R.id.action_edit:
|
||||
if (context instanceof AccountActivity) {
|
||||
editAlertDialog.show(account);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
popup.show();
|
||||
});
|
||||
|
||||
holder.account_pp.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(context, ShowAccountActivity.class);
|
||||
@ -243,6 +302,10 @@ public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
void onAllAccountsRemoved();
|
||||
}
|
||||
|
||||
public interface EditAlertDialog {
|
||||
void show(Account account);
|
||||
}
|
||||
|
||||
private static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView account_pp;
|
||||
TextView account_ac;
|
||||
@ -252,6 +315,7 @@ public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
TextView account_sc;
|
||||
TextView account_fgc;
|
||||
TextView account_frc;
|
||||
ImageButton more_actions;
|
||||
LinearLayout account_info;
|
||||
FloatingActionButton account_action;
|
||||
LinearLayout account_container;
|
||||
@ -268,6 +332,7 @@ public class AccountsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
|
||||
account_frc = itemView.findViewById(R.id.account_frc);
|
||||
account_action = itemView.findViewById(R.id.account_action);
|
||||
account_info = itemView.findViewById(R.id.account_info);
|
||||
more_actions = itemView.findViewById(R.id.more_actions);
|
||||
account_container = itemView.findViewById(R.id.account_container);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
@ -52,11 +51,12 @@ import app.fedilab.fedilabtube.client.PeertubeAPI;
|
||||
import app.fedilab.fedilabtube.client.entities.Account;
|
||||
import app.fedilab.fedilabtube.client.entities.ChannelCreation;
|
||||
import app.fedilab.fedilabtube.drawer.AccountsListAdapter;
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.viewmodel.AccountsVM;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
||||
|
||||
public class DisplayAccountsFragment extends Fragment implements AccountsListAdapter.AllAccountsRemoved {
|
||||
public class DisplayAccountsFragment extends Fragment implements AccountsListAdapter.AllAccountsRemoved, AccountsListAdapter.EditAlertDialog {
|
||||
|
||||
private boolean flag_loading;
|
||||
private Context context;
|
||||
@ -97,78 +97,7 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda
|
||||
|
||||
if (getActivity() != null) {
|
||||
action_button = getActivity().findViewById(R.id.action_button);
|
||||
action_button.setOnClickListener(view -> {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
LayoutInflater inflater1 = ((Activity) context).getLayoutInflater();
|
||||
View dialogView = inflater1.inflate(R.layout.add_channel, new LinearLayout(context), false);
|
||||
dialogBuilder.setView(dialogView);
|
||||
EditText display_name = dialogView.findViewById(R.id.display_name);
|
||||
EditText name = dialogView.findViewById(R.id.name);
|
||||
EditText description = dialogView.findViewById(R.id.description);
|
||||
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
|
||||
if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0 && name.getText() != null && name.getText().toString().trim().length() > 0) {
|
||||
|
||||
ChannelCreation channelCreation = new ChannelCreation();
|
||||
channelCreation.setDisplayName(display_name.getText().toString().trim());
|
||||
channelCreation.setName(name.getText().toString().trim());
|
||||
if (description.getText() != null && description.getText().toString().trim().length() > 0) {
|
||||
channelCreation.setDescription(description.getText().toString().trim());
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
new PeertubeAPI(context).createChannel(channelCreation);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
DisplayPlaylistsFragment displayPlaylistsFragment;
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
displayPlaylistsFragment = (DisplayPlaylistsFragment) getActivity().getSupportFragmentManager().findFragmentByTag("CHANNELS");
|
||||
final FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
|
||||
if (displayPlaylistsFragment != null) {
|
||||
ft.detach(displayPlaylistsFragment);
|
||||
ft.attach(displayPlaylistsFragment);
|
||||
ft.commit();
|
||||
}
|
||||
action_button.setEnabled(true);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
} catch (HttpsConnection.HttpsConnectionException e) {
|
||||
action_button.setEnabled(true);
|
||||
e.printStackTrace();
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
if (e.getMessage() != null) {
|
||||
Toasty.error(context, e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}
|
||||
}).start();
|
||||
|
||||
dialog.dismiss();
|
||||
action_button.setEnabled(false);
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.error_display_name_channel), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
});
|
||||
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
|
||||
|
||||
AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.setTitle(getString(R.string.action_channel_create));
|
||||
alertDialog.setOnDismissListener(dialogInterface -> {
|
||||
//Hide keyboard
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(display_name.getWindowToken(), 0);
|
||||
});
|
||||
if (alertDialog.getWindow() != null)
|
||||
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
alertDialog.show();
|
||||
});
|
||||
action_button.setOnClickListener(view -> manageAlert(null));
|
||||
}
|
||||
lv_accounts = rootView.findViewById(R.id.lv_elements);
|
||||
lv_accounts.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));
|
||||
@ -179,6 +108,7 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda
|
||||
nextElementLoader.setVisibility(View.GONE);
|
||||
accountsListAdapter = new AccountsListAdapter(accountFetch, this.accounts);
|
||||
accountsListAdapter.allAccountsRemoved = this;
|
||||
accountsListAdapter.editAlertDialog = this;
|
||||
lv_accounts.setAdapter(accountsListAdapter);
|
||||
TextView no_action_text = rootView.findViewById(R.id.no_action_text);
|
||||
if (accountFetch == AccountsVM.accountFetch.MUTED) {
|
||||
@ -312,4 +242,98 @@ public class DisplayAccountsFragment extends Fragment implements AccountsListAda
|
||||
public void onAllAccountsRemoved() {
|
||||
textviewNoAction.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
public void manageAlert(ChannelCreation oldChannelValues) {
|
||||
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
LayoutInflater inflater1 = ((Activity) context).getLayoutInflater();
|
||||
View dialogView = inflater1.inflate(R.layout.add_channel, new LinearLayout(context), false);
|
||||
dialogBuilder.setView(dialogView);
|
||||
EditText display_name = dialogView.findViewById(R.id.display_name);
|
||||
EditText name = dialogView.findViewById(R.id.name);
|
||||
EditText description = dialogView.findViewById(R.id.description);
|
||||
if (oldChannelValues != null) {
|
||||
display_name.setText(oldChannelValues.getDisplayName());
|
||||
name.setText(oldChannelValues.getName());
|
||||
description.setText(oldChannelValues.getDescription());
|
||||
}
|
||||
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
|
||||
if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0 && name.getText() != null && name.getText().toString().trim().length() > 0) {
|
||||
|
||||
ChannelCreation channelCreation = new ChannelCreation();
|
||||
channelCreation.setDisplayName(display_name.getText().toString().trim());
|
||||
channelCreation.setName(name.getText().toString().trim());
|
||||
if (description.getText() != null && description.getText().toString().trim().length() > 0) {
|
||||
channelCreation.setDescription(description.getText().toString().trim());
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
if (oldChannelValues == null) {
|
||||
new PeertubeAPI(context).createChannel(channelCreation);
|
||||
} else {
|
||||
new PeertubeAPI(context).updateChannel(name + "@" + Helper.getLiveInstance(context), channelCreation);
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
Account channel = new Account();
|
||||
channel.setAcct(channelCreation.getName() + "@" + Helper.getLiveInstance(context));
|
||||
channel.setUsername(channelCreation.getName());
|
||||
channel.setDisplay_name(channelCreation.getDisplayName());
|
||||
channel.setNote(channelCreation.getDescription());
|
||||
accounts.add(0, channel);
|
||||
accountsListAdapter.notifyItemInserted(0);
|
||||
action_button.setEnabled(true);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
} catch (HttpsConnection.HttpsConnectionException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
action_button.setEnabled(true);
|
||||
if (e.getMessage() != null) {
|
||||
Toasty.error(context, e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
}
|
||||
}).start();
|
||||
|
||||
dialog.dismiss();
|
||||
action_button.setEnabled(false);
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.error_display_name_channel), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
});
|
||||
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
|
||||
AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.setTitle(getString(R.string.action_channel_create));
|
||||
alertDialog.setOnDismissListener(dialogInterface -> {
|
||||
//Hide keyboard
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(display_name.getWindowToken(), 0);
|
||||
});
|
||||
if (alertDialog.getWindow() != null)
|
||||
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
alertDialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Account account) {
|
||||
ChannelCreation oldChannelValues = new ChannelCreation();
|
||||
oldChannelValues.setName(account.getUsername());
|
||||
oldChannelValues.setDescription(account.getNote());
|
||||
oldChannelValues.setDisplayName(account.getDisplay_name());
|
||||
oldChannelValues.setId(account.getId());
|
||||
manageAlert(oldChannelValues);
|
||||
}
|
||||
}
|
||||
|
@ -168,19 +168,14 @@ public class DisplayPlaylistsFragment extends Fragment {
|
||||
playlistElement.setDescription(playlist.getDescription());
|
||||
new Thread(() -> {
|
||||
try {
|
||||
new PeertubeAPI(context).createPlaylist(playlistElement);
|
||||
String returnedId = new PeertubeAPI(context).createPlaylist(playlistElement);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> {
|
||||
DisplayPlaylistsFragment displayPlaylistsFragment;
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
displayPlaylistsFragment = (DisplayPlaylistsFragment) getActivity().getSupportFragmentManager().findFragmentByTag("PLAYLISTS");
|
||||
final FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
|
||||
if (displayPlaylistsFragment != null) {
|
||||
ft.detach(displayPlaylistsFragment);
|
||||
ft.attach(displayPlaylistsFragment);
|
||||
ft.commit();
|
||||
}
|
||||
playlist.setId(returnedId);
|
||||
playlists.add(0, playlist);
|
||||
playlistAdapter.notifyDataSetChanged();
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
add_new.setEnabled(true);
|
||||
|
@ -147,6 +147,15 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/more_actions"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/display_more"
|
||||
android:src="@drawable/ic_baseline_more_vert_24"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/account_action"
|
||||
|
Loading…
x
Reference in New Issue
Block a user