display accounts

This commit is contained in:
Thomas 2020-09-03 18:56:48 +02:00
parent 6d66b2f08b
commit 38e9d9f090
20 changed files with 463 additions and 115 deletions

View File

@ -16,7 +16,7 @@
<application
android:name=".FedilabTupe"
android:name=".FedilabTube"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"

View File

@ -21,12 +21,12 @@ import androidx.multidex.MultiDexApplication;
import net.gotev.uploadservice.UploadService;
public class FedilabTupe extends MultiDexApplication {
public class FedilabTube extends MultiDexApplication {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(FedilabTupe.this);
MultiDex.install(FedilabTube.this);
UploadService.NAMESPACE = BuildConfig.APPLICATION_ID;
}

View File

@ -14,6 +14,7 @@ package app.fedilab.fedilabtube;
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -112,9 +113,7 @@ public class MainActivity extends AppCompatActivity {
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
Account account = new AccountDAO(MainActivity.this, db).getUniqAccount(userId, instance);
if (account != null) {
new Thread(() -> {
new PeertubeAPI(MainActivity.this).refreshToken(account.getToken(), account.getInstance());
}).start();
new Thread(() -> new PeertubeAPI(MainActivity.this).refreshToken(account.getToken(), account.getInstance())).start();
}
} else {
instanceItem.setVisible(true);
@ -174,6 +173,7 @@ public class MainActivity extends AppCompatActivity {
}
}
@SuppressLint("ApplySharedPref")
private void showRadioButtonDialog() {
AlertDialog.Builder alt_bld = new AlertDialog.Builder(this);

View File

@ -0,0 +1,50 @@
package app.fedilab.fedilabtube.asynctasks;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of TubeLab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.os.AsyncTask;
import java.lang.ref.WeakReference;
import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.PeertubeAPI;
import app.fedilab.fedilabtube.interfaces.OnRetrieveAccountsInterface;
public class RetrieveAccountSubscriptionsAsyncTask extends AsyncTask<Void, Void, APIResponse> {
private OnRetrieveAccountsInterface listener;
private WeakReference<Context> contextReference;
private String max_id;
public RetrieveAccountSubscriptionsAsyncTask(Context context, String max_id, OnRetrieveAccountsInterface onRetrieveAccountsInterface) {
this.contextReference = new WeakReference<>(context);
this.max_id = max_id;
this.listener = onRetrieveAccountsInterface;
}
@Override
protected APIResponse doInBackground(Void... params) {
PeertubeAPI peertubeAPI = new PeertubeAPI(this.contextReference.get());
return peertubeAPI.getSubscriptionUsers(max_id);
}
@Override
protected void onPostExecute(APIResponse apiResponse) {
listener.onRetrieveAccounts(apiResponse);
}
}

View File

@ -24,9 +24,8 @@ import app.fedilab.fedilabtube.client.PeertubeAPI;
import app.fedilab.fedilabtube.interfaces.OnRetrieveAccountsInterface;
public class RetrieveAccountsAsyncTask extends AsyncTask<Void, Void, Void> {
public class RetrieveAccountsAsyncTask extends AsyncTask<Void, Void, APIResponse> {
private APIResponse apiResponse;
private OnRetrieveAccountsInterface listener;
private WeakReference<Context> contextReference;
private String name;
@ -39,16 +38,14 @@ public class RetrieveAccountsAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
protected APIResponse doInBackground(Void... params) {
PeertubeAPI peertubeAPI = new PeertubeAPI(this.contextReference.get());
apiResponse = peertubeAPI.getPeertubeChannel(name);
return null;
return peertubeAPI.getPeertubeChannel(name);
}
@Override
protected void onPostExecute(Void result) {
protected void onPostExecute(APIResponse apiResponse) {
listener.onRetrieveAccounts(apiResponse);
}
}

View File

@ -450,7 +450,9 @@ public class PeertubeAPI {
else
account.setNote("");
account.setUrl(accountObject.get("url").toString());
if (accountObject.has("url")) {
account.setUrl(accountObject.get("url").toString());
}
if (accountObject.has("avatar") && !accountObject.isNull("avatar")) {
account.setAvatar(accountObject.getJSONObject("avatar").get("path").toString());
account.setAvatar_static(accountObject.getJSONObject("avatar").get("path").toString());
@ -1168,7 +1170,7 @@ public class PeertubeAPI {
}
/**
* Retrieves subscription videos *synchronously*
* Retrieves subscriptions *synchronously*
*
* @param max_id String id max
* @return APIResponse
@ -1181,11 +1183,12 @@ public class PeertubeAPI {
if (max_id != null)
params.put("start", max_id);
params.put("sort", "-createdAt");
String response = httpsConnection.get("/users/me/subscriptions", 60, params, null);
String response = httpsConnection.get(getAbsoluteUrl("/users/me/subscriptions"), 10, params, prefKeyOauthTokenT);
JSONArray jsonArray = new JSONObject(response).getJSONArray("data");
accounts = parseAccountResponsePeertube(jsonArray);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
e.printStackTrace();
} catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) {
e.printStackTrace();
}
@ -1867,7 +1870,7 @@ public class PeertubeAPI {
String errorM = jsonObject.getString("error");
message = "Error " + statusCode + " : " + errorM;
} catch (JSONException e) {
if (error.getMessage().split(".").length > 0) {
if (error.getMessage() != null && error.getMessage().split(".").length > 0) {
String errorM = error.getMessage().split(".")[0];
message = "Error " + statusCode + " : " + errorM;
}

View File

@ -0,0 +1,160 @@
package app.fedilab.fedilabtube.drawer;
/* Copyright 2020 Thomas Schneider
*
* This file is a part of TubeLab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import app.fedilab.fedilabtube.R;
import app.fedilab.fedilabtube.ShowAccountActivity;
import app.fedilab.fedilabtube.client.PeertubeAPI;
import app.fedilab.fedilabtube.client.entities.Account;
import app.fedilab.fedilabtube.client.entities.Error;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.interfaces.OnPostActionInterface;
import es.dmoral.toasty.Toasty;
public class AccountsHorizontalListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements OnPostActionInterface {
private List<Account> accounts;
private Context context;
private AccountsHorizontalListAdapter accountsListAdapter;
public AccountsHorizontalListAdapter(List<Account> accounts) {
this.accounts = accounts;
this.accountsListAdapter = this;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
LayoutInflater layoutInflater = LayoutInflater.from(context);
return new ViewHolder(layoutInflater.inflate(R.layout.drawer_horizontal_account, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
final AccountsHorizontalListAdapter.ViewHolder holder = (AccountsHorizontalListAdapter.ViewHolder) viewHolder;
final Account account = accounts.get(position);
if (account.getDisplay_name() != null && !account.getDisplay_name().trim().equals(""))
holder.account_dn.setText(account.getDisplay_name());
else
holder.account_dn.setText(account.getUsername().replace("@", ""));
//Profile picture
Helper.loadGiF(context, account, holder.account_pp, 270);
holder.account_pp.setOnClickListener(v -> {
Intent intent = new Intent(context, ShowAccountActivity.class);
Bundle b = new Bundle();
b.putBoolean("peertubeaccount", true);
b.putBoolean("ischannel", true);
b.putString("targetedid", account.getAcct());
b.putParcelable("account", account);
intent.putExtras(b);
context.startActivity(intent);
});
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return accounts.size();
}
private Account getItemAt(int position) {
if (accounts.size() > position)
return accounts.get(position);
else
return null;
}
@Override
public void onPostAction(int statusCode, PeertubeAPI.StatusAction statusAction, String targetedId, Error error) {
if (error != null) {
Toasty.error(context, error.getError(), Toast.LENGTH_LONG).show();
return;
}
if (statusAction == PeertubeAPI.StatusAction.FOLLOW) {
/* if (action == RetrieveAccountsAsyncTask.Type.CHANNELS) {
SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
new InstancesDAO(context, db).insertInstance(accounts.get(0).getAcct().split("@")[1], accounts.get(0).getAcct().split("@")[0], "PEERTUBE_CHANNEL");
} else {
for (Account account : accounts) {
if (account.getId().equals(targetedId)) {
account.setFollowType(Account.followAction.FOLLOW);
account.setMakingAction(false);
}
}
accountsListAdapter.notifyDataSetChanged();
}*/
}
if (statusAction == PeertubeAPI.StatusAction.UNFOLLOW) {
for (Account account : accounts) {
if (account.getId().equals(targetedId)) {
account.setFollowType(Account.followAction.NOT_FOLLOW);
account.setMakingAction(false);
}
}
accountsListAdapter.notifyDataSetChanged();
}
}
private void notifyAccountChanged(Account account) {
for (int i = 0; i < accountsListAdapter.getItemCount(); i++) {
//noinspection ConstantConditions
if (accountsListAdapter.getItemAt(i) != null && accountsListAdapter.getItemAt(i).getId().equals(account.getId())) {
try {
accountsListAdapter.notifyItemChanged(i);
} catch (Exception ignored) {
}
}
}
}
private static class ViewHolder extends RecyclerView.ViewHolder {
ImageView account_pp;
TextView account_dn;
ViewHolder(View itemView) {
super(itemView);
account_pp = itemView.findViewById(R.id.account_pp);
account_dn = itemView.findViewById(R.id.account_dn);
}
}
}

View File

@ -46,7 +46,7 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou
private boolean flag_loading;
private Context context;
private AsyncTask<Void, Void, Void> asyncTask;
private AsyncTask<Void, Void, APIResponse> asyncTask;
private AccountsListAdapter accountsListAdapter;
private String max_id;
private List<Account> accounts;

View File

@ -42,22 +42,27 @@ import java.util.ArrayList;
import java.util.List;
import app.fedilab.fedilabtube.R;
import app.fedilab.fedilabtube.asynctasks.RetrieveAccountSubscriptionsAsyncTask;
import app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask;
import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeSearchAsyncTask;
import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.PeertubeAPI;
import app.fedilab.fedilabtube.client.entities.Account;
import app.fedilab.fedilabtube.client.entities.Error;
import app.fedilab.fedilabtube.client.entities.Peertube;
import app.fedilab.fedilabtube.drawer.AccountsHorizontalListAdapter;
import app.fedilab.fedilabtube.drawer.PeertubeAdapter;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.interfaces.OnPostActionInterface;
import app.fedilab.fedilabtube.interfaces.OnRetrieveAccountsInterface;
import app.fedilab.fedilabtube.interfaces.OnRetrieveFeedsInterface;
import es.dmoral.toasty.Toasty;
import static app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask.Type.POVERVIEW;
import static app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask.Type.PSUBSCRIPTIONS;
public class DisplayStatusFragment extends Fragment implements OnPostActionInterface, OnRetrieveFeedsInterface {
public class DisplayStatusFragment extends Fragment implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveAccountsInterface {
private LinearLayoutManager mLayoutManager;
@ -66,8 +71,10 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
private Context context;
private AsyncTask<Void, Void, Void> asyncTask;
private PeertubeAdapter peertubeAdapater;
private String max_id;
private AccountsHorizontalListAdapter accountsHorizontalListAdapter;
private String max_id, max_id_accounts;
private List<Peertube> peertubes;
private List<Account> accounts;
private RetrieveFeedsAsyncTask.Type type;
private RelativeLayout mainLoader, nextElementLoader, textviewNoAction;
private boolean firstLoad;
@ -78,7 +85,9 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
private boolean ischannel;
private View rootView;
private RecyclerView lv_status;
private RecyclerView lv_accounts;
private String targetedId;
private boolean check_ScrollingUp;
public DisplayStatusFragment() {
}
@ -90,6 +99,7 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
peertubes = new ArrayList<>();
accounts = new ArrayList<>();
context = getContext();
Bundle bundle = this.getArguments();
@ -111,10 +121,13 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
lv_status = rootView.findViewById(R.id.lv_status);
lv_accounts = rootView.findViewById(R.id.lv_accounts);
max_id = null;
max_id_accounts = null;
flag_loading = true;
firstLoad = true;
check_ScrollingUp = false;
assert context != null;
sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
@ -130,6 +143,12 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
peertubeAdapater = new PeertubeAdapter(this.peertubes);
lv_status.setAdapter(peertubeAdapater);
accountsHorizontalListAdapter = new AccountsHorizontalListAdapter(this.accounts);
LinearLayoutManager layoutManager
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
lv_accounts.setLayoutManager(layoutManager);
lv_accounts.setAdapter(accountsHorizontalListAdapter);
if (!Helper.isTablet(context)) {
mLayoutManager = new LinearLayoutManager(context);
lv_status.setLayoutManager(mLayoutManager);
@ -162,9 +181,39 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
}, 500);
}
lv_accounts.addOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (dy > 0) {
int visibleItemCount = mLayoutManager.getChildCount();
int totalItemCount = mLayoutManager.getItemCount();
if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) {
new RetrieveAccountSubscriptionsAsyncTask(context, max_id_accounts, DisplayStatusFragment.this).execute();
}
}
}
});
if (type != POVERVIEW) {
lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (type == PSUBSCRIPTIONS) {
if (dy > 0) {
if (check_ScrollingUp) {
lv_accounts.setVisibility(View.GONE);
final Handler handler = new Handler();
handler.postDelayed(() -> check_ScrollingUp = false, 300);
}
} else {
if (!check_ScrollingUp) {
lv_accounts.setVisibility(View.VISIBLE);
final Handler handler = new Handler();
handler.postDelayed(() -> check_ScrollingUp = true, 300);
}
}
}
if (mLayoutManager != null) {
int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (dy > 0) {
@ -207,7 +256,9 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
}
});
}
if (type == PSUBSCRIPTIONS) {
new RetrieveAccountSubscriptionsAsyncTask(context, max_id, DisplayStatusFragment.this).execute();
}
return rootView;
}
@ -254,6 +305,24 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter
asyncTask.cancel(true);
}
@Override
public void onRetrieveAccounts(APIResponse apiResponse) {
if (apiResponse != null && apiResponse.getAccounts() != null && apiResponse.getAccounts().size() > 0) {
if (lv_accounts.getVisibility() == View.GONE) {
lv_accounts.setVisibility(View.VISIBLE);
}
int previousPosition = accounts.size();
accounts.addAll(apiResponse.getAccounts());
accountsHorizontalListAdapter.notifyItemRangeInserted(previousPosition, apiResponse.getAccounts().size());
if (max_id_accounts == null)
max_id_accounts = "0";
//max_id needs to work like an offset
int tootPerPage = sharedpreferences.getInt(Helper.SET_VIDEOS_PER_PAGE, Helper.VIDEOS_PER_PAGE);
max_id_accounts = String.valueOf(Integer.parseInt(max_id_accounts) + tootPerPage);
}
}
@Override
public void onRetrieveFeeds(APIResponse apiResponse) {
//hide loaders

View File

@ -407,14 +407,12 @@ public class Helper {
}
public static void loadGiF(final Context context, Account account, final ImageView imageView) {
public static void loadGiF(final Context context, Account account, final ImageView imageView, int round) {
if (account == null || account.getAvatar() == null || account.getAvatar().compareTo("null") == 0) {
Glide.with(imageView.getContext())
.asDrawable()
.load(R.drawable.missing_peertube)
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(round)))
.into(imageView);
return;
}
@ -429,14 +427,14 @@ public class Helper {
Glide.with(imageView.getContext())
.load(url)
.thumbnail(0.1f)
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(round)))
.into(imageView);
} catch (Exception e) {
try {
Glide.with(imageView.getContext())
.asDrawable()
.load(R.drawable.missing_peertube)
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10)))
.apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(round)))
.into(imageView);
} catch (Exception ignored) {
@ -444,6 +442,10 @@ public class Helper {
}
}
public static void loadGiF(final Context context, Account account, final ImageView imageView) {
loadGiF(context, account, imageView, 10);
}
public static void loadGiF(final Context context, String url, final ImageView imageView) {

View File

@ -68,11 +68,11 @@ public class AccountDAO {
values.put(Sqlite.COL_HEADER_STATIC, account.getHeader_static());
values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(account.getCreated_at()));
values.put(Sqlite.COL_INSTANCE, account.getInstance());
if (account.getClient_id() != null && account.getClient_secret() != null ) {
if (account.getClient_id() != null && account.getClient_secret() != null) {
values.put(Sqlite.COL_CLIENT_ID, account.getClient_id());
values.put(Sqlite.COL_CLIENT_SECRET, account.getClient_secret());
}
if( account.getRefresh_token() != null) {
if (account.getRefresh_token() != null) {
values.put(Sqlite.COL_REFRESH_TOKEN, account.getRefresh_token());
}
if (account.getToken() != null)
@ -120,7 +120,7 @@ public class AccountDAO {
values.put(Sqlite.COL_CLIENT_ID, account.getClient_id());
values.put(Sqlite.COL_CLIENT_SECRET, account.getClient_secret());
}
if( account.getRefresh_token() != null) {
if (account.getRefresh_token() != null) {
values.put(Sqlite.COL_REFRESH_TOKEN, account.getRefresh_token());
}
if (account.getToken() != null)
@ -161,7 +161,7 @@ public class AccountDAO {
values.put(Sqlite.COL_CLIENT_ID, account.getClient_id());
values.put(Sqlite.COL_CLIENT_SECRET, account.getClient_secret());
}
if( account.getRefresh_token() != null) {
if (account.getRefresh_token() != null) {
values.put(Sqlite.COL_REFRESH_TOKEN, account.getRefresh_token());
}
if (account.getToken() != null)

View File

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z"/>
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z" />
</vector>

View File

@ -4,50 +4,58 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,10m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M16.3851,13.8501C17.4222,12.6992 18,11.4167 18,10C18,6.7409 15.2591,4 12,4C8.7409,4 6,6.7409 6,10C6,11.4186 6.5792,12.7028 7.6184,13.854C7.8034,14.059 8.1196,14.0752 8.3246,13.8902C8.5295,13.7051 8.5457,13.389 8.3607,13.184C7.4762,12.2041 7,11.1483 7,10C7,7.2932 9.2932,5 12,5C14.7068,5 17,7.2932 17,10C17,11.1467 16.525,12.201 15.6422,13.1807C15.4574,13.3859 15.4738,13.702 15.679,13.8869C15.8841,14.0717 16.2003,14.0553 16.3851,13.8501Z"
android:strokeWidth="1"
android:fillType="nonZero"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:startY="4"
android:startX="12"
android:endY="13.806534"
android:endX="12"
android:type="linear">
<item android:offset="0" android:color="#FF000000"/>
<item android:offset="1" android:color="#3F000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M17.5678,18.3077C20.316,16.4626 22,13.3733 22,10C22,4.4772 17.5228,0 12,0C6.4772,0 2,4.4772 2,10C2,13.3762 3.687,16.4679 6.439,18.3123C6.8978,18.6198 7.519,18.4971 7.8264,18.0383C8.1339,17.5796 8.0113,16.9584 7.5525,16.6509C5.3488,15.174 4,12.7021 4,10C4,5.5817 7.5817,2 12,2C16.4183,2 20,5.5817 20,10C20,12.6998 18.6536,15.1698 16.453,16.6472C15.9945,16.9551 15.8723,17.5764 16.1802,18.0349C16.488,18.4934 17.1093,18.6156 17.5678,18.3077Z"
android:strokeWidth="1"
android:fillType="nonZero"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:startY="0"
android:startX="12"
android:endY="18.221992"
android:endX="12"
android:type="linear">
<item android:offset="0" android:color="#FF000000"/>
<item android:offset="1" android:color="#3F000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M9.3292,15.9751C9.1474,14.8843 9.8983,14 10.9979,14L13.0021,14C14.1055,14 14.8534,14.8793 14.6708,15.9751L13.6634,22.0197C13.5731,22.5611 13.0573,23 12.501,23L11.499,23C10.9472,23 10.4277,22.5659 10.3366,22.0197L9.3292,15.9751Z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:fillColor="#000000"
android:fillType="evenOdd"
android:pathData="M12,10m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"
android:strokeWidth="1"
android:strokeColor="#00000000" />
<path
android:fillType="nonZero"
android:pathData="M16.3851,13.8501C17.4222,12.6992 18,11.4167 18,10C18,6.7409 15.2591,4 12,4C8.7409,4 6,6.7409 6,10C6,11.4186 6.5792,12.7028 7.6184,13.854C7.8034,14.059 8.1196,14.0752 8.3246,13.8902C8.5295,13.7051 8.5457,13.389 8.3607,13.184C7.4762,12.2041 7,11.1483 7,10C7,7.2932 9.2932,5 12,5C14.7068,5 17,7.2932 17,10C17,11.1467 16.525,12.201 15.6422,13.1807C15.4574,13.3859 15.4738,13.702 15.679,13.8869C15.8841,14.0717 16.2003,14.0553 16.3851,13.8501Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="12"
android:endY="13.806534"
android:startX="12"
android:startY="4"
android:type="linear">
<item
android:color="#FF000000"
android:offset="0" />
<item
android:color="#3F000000"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path
android:fillType="nonZero"
android:pathData="M17.5678,18.3077C20.316,16.4626 22,13.3733 22,10C22,4.4772 17.5228,0 12,0C6.4772,0 2,4.4772 2,10C2,13.3762 3.687,16.4679 6.439,18.3123C6.8978,18.6198 7.519,18.4971 7.8264,18.0383C8.1339,17.5796 8.0113,16.9584 7.5525,16.6509C5.3488,15.174 4,12.7021 4,10C4,5.5817 7.5817,2 12,2C16.4183,2 20,5.5817 20,10C20,12.6998 18.6536,15.1698 16.453,16.6472C15.9945,16.9551 15.8723,17.5764 16.1802,18.0349C16.488,18.4934 17.1093,18.6156 17.5678,18.3077Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="12"
android:endY="18.221992"
android:startX="12"
android:startY="0"
android:type="linear">
<item
android:color="#FF000000"
android:offset="0" />
<item
android:color="#3F000000"
android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#000000"
android:fillType="evenOdd"
android:pathData="M9.3292,15.9751C9.1474,14.8843 9.8983,14 10.9979,14L13.0021,14C14.1055,14 14.8534,14.8793 14.6708,15.9751L13.6634,22.0197C13.5731,22.5611 13.0573,23 12.501,23L11.499,23C10.9472,23 10.4277,22.5659 10.3366,22.0197L9.3292,15.9751Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -77,9 +77,9 @@
<ScrollView
android:id="@+id/peertube_information_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/video_comment_margin"
android:layout_marginEnd="@dimen/video_comment_margin"
android:layout_height="0dp"
android:layout_weight="2">
<LinearLayout
@ -226,9 +226,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="10dp"
android:baselineAligned="false"
android:orientation="horizontal"
android:visibility="gone"
android:baselineAligned="false">
android:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
@ -274,13 +274,13 @@
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="@string/add_public_comment"
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:maxLines="4"
android:overScrollMode="always"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical"
android:visibility="gone"
android:importantForAutofill="no" />
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

View File

@ -67,9 +67,8 @@
android:scaleType="centerCrop"
android:src="@drawable/default_banner"
app:layout_collapseMode="parallax"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/account_pp"
@ -81,8 +80,8 @@
android:background="@drawable/account_pp_border"
android:contentDescription="@string/profile_picture"
android:padding="2dp"
app:layout_constraintTop_toBottomOf="@+id/action_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/action_back"
app:layout_scrollFlags="scroll" />
<androidx.constraintlayout.widget.ConstraintLayout
@ -95,10 +94,10 @@
app:layout_constraintTop_toBottomOf="@+id/action_back">
<LinearLayout
android:layout_marginStart="10dp"
android:id="@+id/names_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@ -152,8 +151,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2020 Thomas Schneider
This file is a part of TubeLab
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
TubeLab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with TubeLab; if not,
see <http://www.gnu.org/licenses>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:orientation="vertical">
<ImageView
android:id="@+id/account_pp"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:contentDescription="@string/profile_picture"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/account_dn"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:ellipsize="end"
android:gravity="center"
android:padding="2dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="?colorAccent"
android:textSize="14sp" />
</LinearLayout>

View File

@ -19,8 +19,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:dividerHorizontal"
android:orientation="vertical"
android:gravity="bottom"
android:orientation="vertical"
android:showDividers="end">
<TextView

View File

@ -14,19 +14,32 @@
You should have received a copy of the GNU General Public License along with TubeLab; if not,
see <http://www.gnu.org/licenses>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android:fillViewport="true">
<RelativeLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context=".MainActivity">
<!-- Scrollview for displaying accounts in bubbles -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lv_accounts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="0dp"
android:layout_alignTop="@+id/lv_accounts"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/lv_accounts">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeContainer"
@ -36,7 +49,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lv_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:scrollbars="none" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</FrameLayout>
@ -45,7 +58,8 @@
android:id="@+id/no_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/no_action_text"
@ -80,12 +94,13 @@
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|center_horizontal"
android:gravity="bottom|center_horizontal"
android:visibility="gone">
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent">
<ProgressBar
android:layout_width="match_parent"
android:layout_height="match_parent"
android:indeterminate="true" />
</RelativeLayout>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -1,19 +1,20 @@
<?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:padding="@dimen/popup_padding"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:padding="@dimen/popup_padding">
<EditText
android:hint="@string/report_helper"
android:id="@+id/report_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/report_helper"
android:importantForAutofill="no"
android:inputType="textCapSentences|textMultiLine|textAutoCorrect"
android:minLines="3"
android:id="@+id/report_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:importantForAutofill="no"
android:inputType="textCapSentences|textMultiLine|textAutoCorrect" />
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,24 +1,25 @@
<?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:padding="@dimen/popup_padding"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:padding="@dimen/popup_padding">
<Button
android:id="@+id/report_video"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/report_video"
android:text="@string/report_video"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/report_account"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/report_account"
android:text="@string/report_account"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"