diff --git a/app/build.gradle b/app/build.gradle index fd59e47..cca1a94 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,13 +3,13 @@ apply plugin: 'com.android.application' apply plugin: "androidx.navigation.safeargs" android { - compileSdkVersion 29 - buildToolsVersion "29.0.3" + compileSdkVersion 30 + buildToolsVersion "30.0.2" defaultConfig { applicationId "app.fedilab.fedilabtube" minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 3 versionName "1.0.2" multiDexEnabled true @@ -41,8 +41,9 @@ dependencies { implementation "androidx.multidex:multidex:2.0.1" implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.preference:preference:1.1.1' implementation 'com.google.android.material:material:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0' implementation 'androidx.vectordrawable:vectordrawable:1.1.0' implementation 'androidx.navigation:navigation-fragment:2.3.0' implementation "androidx.fragment:fragment:1.2.5" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d7d6854..fcee910 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -49,8 +49,12 @@ android:name=".ShowAccountActivity" android:configChanges="orientation|screenSize" android:label="@string/app_name" - android:theme="@style/AppThemeNoActionBar" android:windowSoftInputMode="stateAlwaysHidden" /> + + + + - + diff --git a/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java new file mode 100644 index 0000000..b3c351d --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/AccountActivity.java @@ -0,0 +1,256 @@ +package app.fedilab.fedilabtube; +/* 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 . */ + +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.text.style.UnderlineSpan; +import android.view.MenuItem; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import com.google.android.material.tabs.TabLayout; + +import org.jetbrains.annotations.NotNull; + +import app.fedilab.fedilabtube.asynctasks.RetrieveAccountsAsyncTask; +import app.fedilab.fedilabtube.client.entities.Account; +import app.fedilab.fedilabtube.fragment.DisplayAccountsFragment; +import app.fedilab.fedilabtube.fragment.DisplayNotificationsFragment; +import app.fedilab.fedilabtube.helper.Helper; +import app.fedilab.fedilabtube.sqlite.AccountDAO; +import app.fedilab.fedilabtube.sqlite.Sqlite; + + +public class AccountActivity extends AppCompatActivity { + + + private ViewPager mPager; + private TabLayout tabLayout; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + + setContentView(R.layout.activity_account); + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + + SpannableString content_create = new SpannableString(getString(R.string.join_peertube)); + content_create.setSpan(new UnderlineSpan(), 0, content_create.length(), 0); + content_create.setSpan(new ForegroundColorSpan(ContextCompat.getColor(AccountActivity.this, R.color.colorAccent)), 0, content_create.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + String instance = Helper.getLiveInstance(AccountActivity.this); + + TextView instanceView = findViewById(R.id.instance); + Account account = new AccountDAO(AccountActivity.this, db).getUniqAccount(userId, instance); + if (account == null) { + account = new AccountDAO(AccountActivity.this, db).getUniqAccount(userId, Helper.getPeertubeUrl(instance)); + } + + + if (account == null) { + Helper.logoutCurrentUser(AccountActivity.this, null); + return; + } + + ImageView profile_picture = findViewById(R.id.profile_picture); + TextView username = findViewById(R.id.username); + TextView displayname = findViewById(R.id.displayname); + + setTitle(String.format("@%s", account.getUsername())); + + Helper.loadGiF(AccountActivity.this, account, profile_picture); + username.setText(String.format("@%s", account.getUsername())); + displayname.setText(account.getDisplay_name()); + + instanceView.setText(account.getInstance()); + + Button logout_button = findViewById(R.id.logout_button); + Account finalAccount = account; + logout_button.setOnClickListener(v -> { + AlertDialog.Builder dialogBuilderLogoutAccount = new AlertDialog.Builder(AccountActivity.this); + dialogBuilderLogoutAccount.setMessage(getString(R.string.logout_account_confirmation, finalAccount.getUsername())); + dialogBuilderLogoutAccount.setPositiveButton(R.string.action_logout, (dialog, id) -> { + Helper.logoutCurrentUser(AccountActivity.this, finalAccount); + dialog.dismiss(); + }); + dialogBuilderLogoutAccount.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); + AlertDialog alertDialogLogoutAccount = dialogBuilderLogoutAccount.create(); + alertDialogLogoutAccount.show(); + }); + + Button settings = findViewById(R.id.settings); + settings.setOnClickListener(v -> { + Intent intent = new Intent(AccountActivity.this, SettingsActivity.class); + startActivity(intent); + }); + + tabLayout = findViewById(R.id.account_tabLayout); + mPager = findViewById(R.id.account_viewpager); + tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.title_notifications))); + tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.title_muted))); + tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.title_channel))); + + + mPager.setOffscreenPageLimit(3); + + + mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + TabLayout.Tab tab = tabLayout.getTabAt(position); + if (tab != null) + tab.select(); + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + + + tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + mPager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + Fragment fragment = null; + if (mPager.getAdapter() != null) + fragment = (Fragment) mPager.getAdapter().instantiateItem(mPager, tab.getPosition()); + switch (tab.getPosition()) { + case 0: + if (fragment != null) { + DisplayNotificationsFragment displayNotificationsFragment = ((DisplayNotificationsFragment) fragment); + displayNotificationsFragment.scrollToTop(); + } + break; + case 1: + case 2: + if (fragment != null) { + DisplayAccountsFragment displayAccountsFragment = ((DisplayAccountsFragment) fragment); + displayAccountsFragment.scrollToTop(); + } + break; + } + } + }); + + PagerAdapter mPagerAdapter = new AccountsPagerAdapter(getSupportFragmentManager()); + mPager.setAdapter(mPagerAdapter); + + } + + @Override + protected void onResume() { + super.onResume(); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + + /** + * Pager adapter for three tabs (notifications, muted, blocked) + */ + private class AccountsPagerAdapter extends FragmentStatePagerAdapter { + + AccountsPagerAdapter(FragmentManager fm) { + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + } + + @NotNull + @Override + public Fragment getItem(int position) { + Bundle bundle = new Bundle(); + switch (position) { + case 1: + case 2: + DisplayAccountsFragment displayAccountsFragment = new DisplayAccountsFragment(); + if (position == 1) { + bundle.putSerializable("accountFetch", RetrieveAccountsAsyncTask.accountFetch.MUTED); + } else { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + String instance = Helper.getLiveInstance(AccountActivity.this); + Account account = new AccountDAO(AccountActivity.this, db).getUniqAccount(userId, instance); + bundle.putString("name", account.getUsername() + "@" + account.getInstance()); + bundle.putSerializable("accountFetch", RetrieveAccountsAsyncTask.accountFetch.CHANNEL); + } + displayAccountsFragment.setArguments(bundle); + return displayAccountsFragment; + default: + return new DisplayNotificationsFragment(); + } + } + + + @Override + public int getCount() { + return 3; + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java index 7343f46..b397990 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java @@ -104,9 +104,11 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies()); - Map.Entry entryInt = privaciesInit.entrySet().iterator().next(); - privacyToSend = new HashMap<>(); - privacyToSend.put(entryInt.getKey(), entryInt.getValue()); + if (privaciesInit.size() > 0) { + Map.Entry entryInt = privaciesInit.entrySet().iterator().next(); + privacyToSend = new HashMap<>(); + privacyToSend.put(entryInt.getKey(), entryInt.getValue()); + } add_new.setOnClickListener(view -> { @@ -176,7 +178,6 @@ public class AllPlaylistsActivity extends AppCompatActivity implements OnPlaylis public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, Exception exception) { // your code here - exception.printStackTrace(); } @Override diff --git a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java index aef8d5b..8a18d04 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/LoginActivity.java @@ -16,7 +16,6 @@ package app.fedilab.fedilabtube; import android.content.Intent; import android.content.SharedPreferences; -import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.Bundle; import android.text.SpannableString; @@ -24,51 +23,32 @@ import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.style.UnderlineSpan; import android.view.MenuItem; -import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.textfield.TextInputLayout; -import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.List; -import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeNotificationsAsyncTask; import app.fedilab.fedilabtube.asynctasks.UpdateAccountInfoAsyncTask; -import app.fedilab.fedilabtube.client.APIResponse; import app.fedilab.fedilabtube.client.HttpsConnection; -import app.fedilab.fedilabtube.client.entities.Account; -import app.fedilab.fedilabtube.client.entities.PeertubeNotification; -import app.fedilab.fedilabtube.drawer.PeertubeNotificationsListAdapter; import app.fedilab.fedilabtube.helper.Helper; -import app.fedilab.fedilabtube.interfaces.OnRetrievePeertubeNotificationsInterface; -import app.fedilab.fedilabtube.sqlite.AccountDAO; -import app.fedilab.fedilabtube.sqlite.Sqlite; import es.dmoral.toasty.Toasty; -public class LoginActivity extends AppCompatActivity implements OnRetrievePeertubeNotificationsInterface { +public class LoginActivity extends AppCompatActivity { //Peertube notification type @@ -82,23 +62,11 @@ public class LoginActivity extends AppCompatActivity implements OnRetrievePeertu public static int MY_VIDEO_IMPORT_ERROR = 8; private static String client_id; private static String client_secret; - // public static int NEW_USER_REGISTRATION = 9; - //public static int NEW_FOLLOW = 10; - // public static int COMMENT_MENTION = 11; - LinearLayoutManager mLayoutManager; private EditText login_uid; private EditText login_passwd; private Button connectionButton; private String actionToken; - private boolean flag_loading; - private PeertubeNotificationsListAdapter notificationsListAdapter; - private String max_id; - private List notifications; - private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; - private boolean firstLoad; - private SwipeRefreshLayout swipeRefreshLayout; - private boolean swiped; - private AsyncTask asyncTask; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -153,99 +121,6 @@ public class LoginActivity extends AppCompatActivity implements OnRetrievePeertu } } }); - LinearLayout connected = findViewById(R.id.connected); - LinearLayout not_connected = findViewById(R.id.not_connected); - - if (Helper.isLoggedIn(LoginActivity.this)) { - not_connected.setVisibility(View.GONE); - connected.setVisibility(View.VISIBLE); - SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); - SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - String instance = Helper.getLiveInstance(LoginActivity.this); - - TextView instanceView = findViewById(R.id.instance); - Account account = new AccountDAO(LoginActivity.this, db).getUniqAccount(userId, instance); - if (account == null) { - account = new AccountDAO(LoginActivity.this, db).getUniqAccount(userId, Helper.getPeertubeUrl(instance)); - } - if (account != null) { - ImageView profile_picture = findViewById(R.id.profile_picture); - TextView username = findViewById(R.id.username); - TextView displayname = findViewById(R.id.displayname); - - Helper.loadGiF(LoginActivity.this, account, profile_picture); - username.setText(String.format("@%s", account.getUsername())); - displayname.setText(account.getDisplay_name()); - - instanceView.setText(account.getInstance()); - - Button logout_button = findViewById(R.id.logout_button); - Account finalAccount = account; - logout_button.setOnClickListener(v -> { - AlertDialog.Builder dialogBuilderLogoutAccount = new AlertDialog.Builder(LoginActivity.this); - dialogBuilderLogoutAccount.setMessage(getString(R.string.logout_account_confirmation, finalAccount.getUsername())); - dialogBuilderLogoutAccount.setPositiveButton(R.string.action_logout, (dialog, id) -> { - Helper.logoutCurrentUser(LoginActivity.this, finalAccount); - dialog.dismiss(); - }); - dialogBuilderLogoutAccount.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); - AlertDialog alertDialogLogoutAccount = dialogBuilderLogoutAccount.create(); - alertDialogLogoutAccount.show(); - }); - } else { - Helper.logoutCurrentUser(LoginActivity.this, null); - } - - max_id = null; - firstLoad = true; - flag_loading = true; - notifications = new ArrayList<>(); - swiped = false; - swipeRefreshLayout = findViewById(R.id.swipeContainer); - - RecyclerView lv_notifications = findViewById(R.id.lv_notifications); - mainLoader = findViewById(R.id.loader); - nextElementLoader = findViewById(R.id.loading_next_notifications); - textviewNoAction = findViewById(R.id.no_action); - mainLoader.setVisibility(View.VISIBLE); - nextElementLoader.setVisibility(View.GONE); - notificationsListAdapter = new PeertubeNotificationsListAdapter(this.notifications); - lv_notifications.setAdapter(notificationsListAdapter); - mLayoutManager = new LinearLayoutManager(LoginActivity.this); - lv_notifications.setLayoutManager(mLayoutManager); - lv_notifications.addOnScrollListener(new RecyclerView.OnScrollListener() { - public void onScrolled(@NotNull RecyclerView recyclerView, int dx, int dy) { - if (dy > 0) { - int visibleItemCount = mLayoutManager.getChildCount(); - int totalItemCount = mLayoutManager.getItemCount(); - int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); - if (firstVisibleItem + visibleItemCount == totalItemCount) { - if (!flag_loading) { - flag_loading = true; - asyncTask = new RetrievePeertubeNotificationsAsyncTask(LoginActivity.this, null, max_id, LoginActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - nextElementLoader.setVisibility(View.VISIBLE); - } - } else { - nextElementLoader.setVisibility(View.GONE); - } - } - } - }); - - - swipeRefreshLayout.setOnRefreshListener(() -> { - max_id = null; - firstLoad = true; - flag_loading = true; - swiped = true; - asyncTask = new RetrievePeertubeNotificationsAsyncTask(LoginActivity.this, null, null, LoginActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - }); - asyncTask = new RetrievePeertubeNotificationsAsyncTask(LoginActivity.this, null, max_id, LoginActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } else { - connected.setVisibility(View.GONE); - not_connected.setVisibility(View.VISIBLE); - } connectionButton.setOnClickListener(v -> { @@ -431,50 +306,7 @@ public class LoginActivity extends AppCompatActivity implements OnRetrievePeertu @Override public void onDestroy() { super.onDestroy(); - if (asyncTask != null && !asyncTask.isCancelled()) { - asyncTask.cancel(true); - } } - @Override - public void onRetrievePeertubeNotifications(APIResponse apiResponse, Account account) { - mainLoader.setVisibility(View.GONE); - nextElementLoader.setVisibility(View.GONE); - if (apiResponse.getError() != null) { - Toasty.error(LoginActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); - flag_loading = false; - swipeRefreshLayout.setRefreshing(false); - swiped = false; - return; - } - - int previousPosition = notifications.size(); - max_id = apiResponse.getMax_id(); - List notifications = apiResponse.getPeertubeNotifications(); - if (!swiped && firstLoad && (notifications == null || notifications.size() == 0)) - textviewNoAction.setVisibility(View.VISIBLE); - else - textviewNoAction.setVisibility(View.GONE); - if (swiped) { - if (previousPosition > 0) { - this.notifications.subList(0, previousPosition).clear(); - notificationsListAdapter.notifyItemRangeRemoved(0, previousPosition); - } - swiped = false; - } - - if (notifications != null && notifications.size() > 0) { - this.notifications.addAll(notifications); - notificationsListAdapter.notifyItemRangeInserted(previousPosition, notifications.size()); - } else { - if (firstLoad) - textviewNoAction.setVisibility(View.VISIBLE); - } - swipeRefreshLayout.setRefreshing(false); - firstLoad = false; - //The initial call comes from a classic tab refresh - flag_loading = (max_id == null); - } - } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java index 7908865..17ae74b 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java @@ -39,14 +39,18 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import org.jetbrains.annotations.NotNull; +import java.util.LinkedHashMap; + import app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeInformationAsyncTask; import app.fedilab.fedilabtube.client.PeertubeAPI; import app.fedilab.fedilabtube.client.entities.Account; +import app.fedilab.fedilabtube.client.entities.PeertubeInformation; import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.sqlite.AccountDAO; import app.fedilab.fedilabtube.sqlite.Sqlite; +import static app.fedilab.fedilabtube.asynctasks.RetrievePeertubeInformationAsyncTask.peertubeInformation; import static app.fedilab.fedilabtube.helper.Helper.academies; public class MainActivity extends AppCompatActivity { @@ -64,6 +68,13 @@ public class MainActivity extends AppCompatActivity { } try { + peertubeInformation = new PeertubeInformation(); + peertubeInformation.setCategories(new LinkedHashMap<>()); + peertubeInformation.setLanguages(new LinkedHashMap<>()); + peertubeInformation.setLicences(new LinkedHashMap<>()); + peertubeInformation.setPrivacies(new LinkedHashMap<>()); + peertubeInformation.setPlaylistPrivacies(new LinkedHashMap<>()); + peertubeInformation.setTranslations(new LinkedHashMap<>()); new RetrievePeertubeInformationAsyncTask(MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } catch (Exception ignored) { } @@ -131,11 +142,13 @@ public class MainActivity extends AppCompatActivity { MenuItem uploadItem = menu.findItem(R.id.action_upload); MenuItem myVideosItem = menu.findItem(R.id.action_myvideos); MenuItem playslistItem = menu.findItem(R.id.action_playlist); + MenuItem historyItem = menu.findItem(R.id.action_history); if (Helper.isLoggedIn(MainActivity.this)) { instanceItem.setVisible(false); uploadItem.setVisible(true); myVideosItem.setVisible(true); playslistItem.setVisible(true); + historyItem.setVisible(true); final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); String instance = Helper.getLiveInstance(MainActivity.this); @@ -149,6 +162,7 @@ public class MainActivity extends AppCompatActivity { uploadItem.setVisible(false); myVideosItem.setVisible(false); playslistItem.setVisible(false); + historyItem.setVisible(false); } return true; } @@ -159,7 +173,12 @@ public class MainActivity extends AppCompatActivity { showRadioButtonDialog(); return true; } else if (item.getItemId() == R.id.action_account) { - Intent intent = new Intent(MainActivity.this, LoginActivity.class); + Intent intent; + if (Helper.isLoggedIn(MainActivity.this)) { + intent = new Intent(MainActivity.this, AccountActivity.class); + } else { + intent = new Intent(MainActivity.this, LoginActivity.class); + } startActivity(intent); return true; } else if (item.getItemId() == R.id.action_upload) { @@ -173,6 +192,13 @@ public class MainActivity extends AppCompatActivity { intent.putExtras(bundle); startActivity(intent); return true; + } else if (item.getItemId() == R.id.action_history) { + Intent intent = new Intent(MainActivity.this, MyVideosActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.PEERTUBE_HISTORY); + intent.putExtras(bundle); + startActivity(intent); + return true; } else if (item.getItemId() == R.id.action_playlist) { Intent intent = new Intent(MainActivity.this, AllPlaylistsActivity.class); startActivity(intent); diff --git a/app/src/main/java/app/fedilab/fedilabtube/MyVideosActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MyVideosActivity.java index eda9919..a0f12d9 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MyVideosActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MyVideosActivity.java @@ -47,6 +47,8 @@ public class MyVideosActivity extends AppCompatActivity implements OnRetrieveFee setTitle(R.string.my_videos); } else if (type == RetrieveFeedsAsyncTask.Type.PSUBSCRIPTIONS) { setTitle(R.string.subscriptions); + } else if (type == RetrieveFeedsAsyncTask.Type.PEERTUBE_HISTORY) { + setTitle(R.string.my_history); } if (savedInstanceState == null) { diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java index c3deb1b..25e2c67 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java @@ -201,9 +201,9 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee getSupportActionBar().setDisplayHomeAsUpEnabled(true); - mode = sharedpreferences.getInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_DIRECT); - if (mode != Helper.VIDEO_MODE_WEBVIEW && mode != Helper.VIDEO_MODE_DIRECT) - mode = Helper.VIDEO_MODE_DIRECT; + mode = sharedpreferences.getInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_NORMAL); + if (mode != Helper.VIDEO_MODE_WEBVIEW && mode != Helper.VIDEO_MODE_NORMAL) + mode = Helper.VIDEO_MODE_NORMAL; if (mode == Helper.VIDEO_MODE_WEBVIEW) { webview_video.setVisibility(View.VISIBLE); playerView.setVisibility(View.GONE); @@ -366,7 +366,7 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee loader.setVisibility(View.GONE); return; } - if (apiResponse.getPeertubes() == null || apiResponse.getPeertubes().get(0) == null || apiResponse.getPeertubes().get(0).getFileUrl(null, apiResponse.getPeertubes().get(0).isStreamService()) == null) { + if (apiResponse.getPeertubes() == null || apiResponse.getPeertubes().get(0) == null || apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this) == null) { Toasty.error(PeertubeActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); loader.setVisibility(View.GONE); return; @@ -374,7 +374,6 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee peertube = apiResponse.getPeertubes().get(0); //TODO: currently streaming service gives the wrong values for duration - peertube.setStreamService(false); new ManagePlaylistsAsyncTask(PeertubeActivity.this, GET_PLAYLIST_FOR_VIDEO, null, peertube.getId(), null, PeertubeActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -536,7 +535,7 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee e.printStackTrace(); } - if (mode == Helper.VIDEO_MODE_DIRECT) { + if (mode == Helper.VIDEO_MODE_NORMAL) { int video_cache = sharedpreferences.getInt(Helper.SET_VIDEO_CACHE, Helper.DEFAULT_VIDEO_CACHE_MB); ProgressiveMediaSource videoSource; @@ -544,11 +543,11 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(PeertubeActivity.this, Util.getUserAgent(PeertubeActivity.this, null), null); videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory) - .createMediaSource(Uri.parse(apiResponse.getPeertubes().get(0).getFileUrl(null, apiResponse.getPeertubes().get(0).isStreamService()))); + .createMediaSource(Uri.parse(apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this))); } else { CacheDataSourceFactory cacheDataSourceFactory = new CacheDataSourceFactory(PeertubeActivity.this); videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory) - .createMediaSource(Uri.parse(apiResponse.getPeertubes().get(0).getFileUrl(null, apiResponse.getPeertubes().get(0).isStreamService()))); + .createMediaSource(Uri.parse(apiResponse.getPeertubes().get(0).getFileUrl(null, PeertubeActivity.this))); } player = ExoPlayerFactory.newSimpleInstance(PeertubeActivity.this); @@ -564,10 +563,10 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee if (ContextCompat.checkSelfPermission(PeertubeActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(PeertubeActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(PeertubeActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE); } else { - Helper.manageDownloads(PeertubeActivity.this, peertube.getFileDownloadUrl(null, peertube.isStreamService())); + Helper.manageDownloads(PeertubeActivity.this, peertube.getFileDownloadUrl(null, PeertubeActivity.this)); } } else { - Helper.manageDownloads(PeertubeActivity.this, peertube.getFileDownloadUrl(null, peertube.isStreamService())); + Helper.manageDownloads(PeertubeActivity.this, peertube.getFileDownloadUrl(null, PeertubeActivity.this)); } }); SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); @@ -714,7 +713,7 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee PlayerControlView controlView = playerView.findViewById(R.id.exo_controller); resolution = controlView.findViewById(R.id.resolution); resolution.setText(String.format("%sp", res)); - if (mode == Helper.VIDEO_MODE_DIRECT) { + if (mode == Helper.VIDEO_MODE_NORMAL) { if (player != null) player.release(); player = ExoPlayerFactory.newSimpleInstance(PeertubeActivity.this); @@ -726,11 +725,11 @@ public class PeertubeActivity extends AppCompatActivity implements OnRetrievePee DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(PeertubeActivity.this, Util.getUserAgent(PeertubeActivity.this, null), null); videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory) - .createMediaSource(Uri.parse(peertube.getFileUrl(res, peertube.isStreamService()))); + .createMediaSource(Uri.parse(peertube.getFileUrl(res, PeertubeActivity.this))); } else { CacheDataSourceFactory cacheDataSourceFactory = new CacheDataSourceFactory(PeertubeActivity.this); videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory) - .createMediaSource(Uri.parse(peertube.getFileUrl(res, peertube.isStreamService()))); + .createMediaSource(Uri.parse(peertube.getFileUrl(res, PeertubeActivity.this))); } player.prepare(videoSource); player.seekTo(0, position); diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java index f4b1e0e..def2414 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeEditUploadActivity.java @@ -14,27 +14,47 @@ package app.fedilab.fedilabtube; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.Manifest; +import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; +import android.widget.ImageView; import android.widget.Spinner; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import com.bumptech.glide.Glide; + +import net.gotev.uploadservice.MultipartUploadRequest; +import net.gotev.uploadservice.ServerResponse; +import net.gotev.uploadservice.UploadInfo; +import net.gotev.uploadservice.UploadNotificationConfig; +import net.gotev.uploadservice.UploadStatusDelegate; + +import java.io.FileNotFoundException; +import java.net.MalformedURLException; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import app.fedilab.fedilabtube.asynctasks.PostActionAsyncTask; import app.fedilab.fedilabtube.asynctasks.PostPeertubeAsyncTask; @@ -58,6 +78,8 @@ import static app.fedilab.fedilabtube.asynctasks.RetrievePeertubeInformationAsyn public class PeertubeEditUploadActivity extends AppCompatActivity implements OnRetrievePeertubeInterface, OnPostActionInterface { + private final int PICK_IMAGE = 50378; + private final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 724; HashMap categoryToSend; HashMap licenseToSend; HashMap privacyToSend; @@ -71,6 +93,9 @@ public class PeertubeEditUploadActivity extends AppCompatActivity implements OnR private LinkedHashMap channels; private String videoId; private Account channel; + private ImageView p_video_preview; + private Button set_preview; + private Peertube peertube; @Override protected void onCreate(Bundle savedInstanceState) { @@ -99,9 +124,10 @@ public class PeertubeEditUploadActivity extends AppCompatActivity implements OnR p_video_title = findViewById(R.id.p_video_title); p_video_description = findViewById(R.id.p_video_description); p_video_tags = findViewById(R.id.p_video_tags); + p_video_preview = findViewById(R.id.p_video_preview); set_upload_nsfw = findViewById(R.id.set_upload_nsfw); set_upload_enable_comments = findViewById(R.id.set_upload_enable_comments); - + set_preview = findViewById(R.id.set_preview); set_upload_delete.setOnClickListener(v -> { AlertDialog.Builder builderInner; @@ -201,6 +227,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity implements OnR channels = new LinkedHashMap<>(); + setTitle(R.string.edit_video); } @@ -216,7 +243,7 @@ public class PeertubeEditUploadActivity extends AppCompatActivity implements OnR } //Peertube video - Peertube peertube = apiResponse.getPeertubes().get(0); + peertube = apiResponse.getPeertubes().get(0); if (peertube.isUpdate()) { Toasty.success(PeertubeEditUploadActivity.this, getString(R.string.toast_peertube_video_updated), Toast.LENGTH_LONG).show(); @@ -231,6 +258,27 @@ public class PeertubeEditUploadActivity extends AppCompatActivity implements OnR privacyToSend = peertube.getPrivacy(); categoryToSend = peertube.getCategory(); + Glide.with(PeertubeEditUploadActivity.this) + .load("https://" + peertube.getInstance() + peertube.getThumbnailPath()) + .into(p_video_preview); + + set_preview.setOnClickListener(v -> { + if (ContextCompat.checkSelfPermission(PeertubeEditUploadActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != + PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(PeertubeEditUploadActivity.this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); + return; + } + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("image/jpg"); + String[] mimetypes = {"image/jpg", "image/jpeg"}; + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes); + startActivityForResult(intent, PICK_IMAGE); + + }); + if (languageToSend == null) { LinkedHashMap languages = new LinkedHashMap<>(peertubeInformation.getLanguages()); Map.Entry entryString = languages.entrySet().iterator().next(); @@ -498,6 +546,74 @@ public class PeertubeEditUploadActivity extends AppCompatActivity implements OnR } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) { + if (data == null || data.getData() == null) { + Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show(); + return; + } + UploadNotificationConfig uploadConfig = new UploadNotificationConfig(); + uploadConfig.getCompleted().autoClear = true; + try { + SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); + Uri uri = data.getData(); + try { + String uploadId = UUID.randomUUID().toString(); + new MultipartUploadRequest(PeertubeEditUploadActivity.this, uploadId, "https://" + Helper.getLiveInstance(PeertubeEditUploadActivity.this) + "/api/v1/" + String.format("/videos/%s", peertube.getId())) + .addFileToUpload(uri.toString().replace("file://", ""), "previewfile") + .setMethod("PUT") + .addHeader("Authorization", "Bearer " + token) + .setNotificationConfig(uploadConfig) + .setMaxRetries(2) + .setDelegate(new UploadStatusDelegate() { + @Override + public void onProgress(Context context, UploadInfo uploadInfo) { + // your code here + } + + @Override + public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, + Exception exception) { + Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + } + + @Override + public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) { + Glide.with(PeertubeEditUploadActivity.this) + .load(uri) + .into(p_video_preview); + } + + @Override + public void onCancelled(Context context, UploadInfo uploadInfo) { + // your code here + } + }) + .startUpload(); + } catch (FileNotFoundException e) { + Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + e.printStackTrace(); + } + } catch (MalformedURLException e) { + Toasty.error(PeertubeEditUploadActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); + e.printStackTrace(); + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + @Override public void onRetrievePeertubeComments(APIResponse apiResponse) { diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java index 4ddb615..289da05 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeUploadActivity.java @@ -15,7 +15,6 @@ package app.fedilab.fedilabtube; * see . */ import android.Manifest; -import android.annotation.SuppressLint; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; @@ -42,15 +41,8 @@ import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import net.gotev.uploadservice.MultipartUploadRequest; -import net.gotev.uploadservice.ServerResponse; -import net.gotev.uploadservice.UploadInfo; import net.gotev.uploadservice.UploadNotificationAction; import net.gotev.uploadservice.UploadNotificationConfig; -import net.gotev.uploadservice.UploadServiceSingleBroadcastReceiver; -import net.gotev.uploadservice.UploadStatusDelegate; - -import org.json.JSONException; -import org.json.JSONObject; import java.io.File; import java.util.Date; @@ -71,7 +63,7 @@ import es.dmoral.toasty.Toasty; import static app.fedilab.fedilabtube.asynctasks.RetrievePeertubeInformationAsyncTask.peertubeInformation; -public class PeertubeUploadActivity extends AppCompatActivity implements OnRetrievePeertubeInterface, UploadStatusDelegate { +public class PeertubeUploadActivity extends AppCompatActivity implements OnRetrievePeertubeInterface { private final int PICK_IVDEO = 52378; @@ -85,7 +77,7 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri private String filename; private HashMap privacyToSend; private HashMap channelToSend; - private UploadServiceSingleBroadcastReceiver uploadReceiver; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -105,10 +97,7 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri new RetrievePeertubeChannelsAsyncTask(PeertubeUploadActivity.this, PeertubeUploadActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); channels = new HashMap<>(); - - uploadReceiver = new UploadServiceSingleBroadcastReceiver(this); - uploadReceiver.register(this); - + setTitle(R.string.upload_video); } @Override @@ -122,6 +111,7 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri set_upload_submit.setEnabled(true); uri = data.getData(); + String uriString = uri.toString(); File myFile = new File(uriString); filename = null; @@ -151,7 +141,6 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri @Override public void onDestroy() { super.onDestroy(); - uploadReceiver.unregister(this); } @Override @@ -327,7 +316,6 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri filename = video_title.getText().toString().trim(); } String uploadId = UUID.randomUUID().toString(); - uploadReceiver.setUploadID(uploadId); new MultipartUploadRequest(PeertubeUploadActivity.this, uploadId, "https://" + Helper.getLiveInstance(PeertubeUploadActivity.this) + "/api/v1/videos/upload") .addFileToUpload(uri.toString().replace("file://", ""), "videofile") .addHeader("Authorization", "Bearer " + token) @@ -338,7 +326,7 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri .addParameter("nsfw", "false") .addParameter("commentsEnabled", "true") .addParameter("waitTranscoding", "true") - .setMaxRetries(2) + .setMaxRetries(3) .startUpload(); finish(); } catch (Exception exc) { @@ -347,37 +335,4 @@ public class PeertubeUploadActivity extends AppCompatActivity implements OnRetri } }); } - - - @Override - public void onProgress(Context context, UploadInfo uploadInfo) { - // your code here - } - - @Override - public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, - Exception exception) { - // your code here - exception.printStackTrace(); - } - - @SuppressLint("ApplySharedPref") - @Override - public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) { - try { - JSONObject response = new JSONObject(serverResponse.getBodyAsString()); - String videoID = response.getJSONObject("video").get("id").toString(); - SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedpreferences.edit(); - editor.putString(Helper.VIDEO_ID, videoID); - editor.commit(); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - @Override - public void onCancelled(Context context, UploadInfo uploadInfo) { - // your code here - } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/SettingsActivity.java b/app/src/main/java/app/fedilab/fedilabtube/SettingsActivity.java new file mode 100644 index 0000000..529a4b0 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/SettingsActivity.java @@ -0,0 +1,43 @@ +package app.fedilab.fedilabtube; + +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.appcompat.app.AppCompatActivity; + +import app.fedilab.fedilabtube.fragment.SettingsFragment; + +/* 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 . */ + +public class SettingsActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java index 6c23d23..41300e5 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/ShowAccountActivity.java @@ -23,16 +23,20 @@ import android.os.Bundle; import android.text.Html; import android.text.SpannableString; import android.text.method.LinkMovementMethod; +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.EditText; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -40,7 +44,6 @@ import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; -import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.tabs.TabLayout; import org.jetbrains.annotations.NotNull; @@ -49,9 +52,9 @@ import java.util.ArrayList; import java.util.List; import app.fedilab.fedilabtube.asynctasks.PostActionAsyncTask; -import app.fedilab.fedilabtube.asynctasks.RetrieveAccountsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrieveRelationshipAsyncTask; +import app.fedilab.fedilabtube.asynctasks.RetrieveSingleAccountAsyncTask; import app.fedilab.fedilabtube.client.APIResponse; import app.fedilab.fedilabtube.client.PeertubeAPI; import app.fedilab.fedilabtube.client.entities.Account; @@ -123,10 +126,8 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi statusDrawerParams.setStatuses(statuses); statusListAdapter = new StatusListAdapter(statusDrawerParams); - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); + if (getSupportActionBar() != null) { - getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_arrow_white_24); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @@ -135,18 +136,51 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi if (account != null) { - ManageAccount(); - new RetrieveAccountsAsyncTask(ShowAccountActivity.this, account.getAcct(), RetrieveAccountsAsyncTask.actionType.CHANNEL, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + manageAccount(); + new RetrieveSingleAccountAsyncTask(ShowAccountActivity.this, account.getAcct(), RetrieveSingleAccountAsyncTask.actionType.CHANNEL, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + new RetrieveSingleAccountAsyncTask(ShowAccountActivity.this, accountId, RetrieveSingleAccountAsyncTask.actionType.CHANNEL, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } @Override - public boolean onSupportNavigateUp() { - onBackPressed(); + public boolean onCreateOptionsMenu(@NotNull Menu menu) { + getMenuInflater().inflate(R.menu.main_account, menu); + if (!Helper.isLoggedIn(ShowAccountActivity.this)) { + menu.findItem(R.id.action_mute).setVisible(false); + } return true; } - private void ManageAccount() { + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } else if (item.getItemId() == R.id.action_mute) { + new PostActionAsyncTask(ShowAccountActivity.this, PeertubeAPI.StatusAction.MUTE, account.getchannelOwner() != null ? account.getchannelOwner().getAcct() : account.getAcct(), ShowAccountActivity.this).execute(); + } else if (item.getItemId() == R.id.action_report) { + androidx.appcompat.app.AlertDialog.Builder dialogBuilder = new androidx.appcompat.app.AlertDialog.Builder(ShowAccountActivity.this); + LayoutInflater inflater1 = getLayoutInflater(); + View dialogView = inflater1.inflate(R.layout.popup_report, new LinearLayout(ShowAccountActivity.this), false); + dialogBuilder.setView(dialogView); + EditText report_content = dialogView.findViewById(R.id.report_content); + dialogBuilder.setNeutralButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); + dialogBuilder.setPositiveButton(R.string.report, (dialog, id) -> { + if (report_content.getText().toString().trim().length() == 0) { + Toasty.info(ShowAccountActivity.this, getString(R.string.report_comment_size), Toasty.LENGTH_LONG).show(); + } else { + new PostActionAsyncTask(ShowAccountActivity.this, PeertubeAPI.StatusAction.REPORT_ACCOUNT, account.getId(), report_content.getText().toString(), ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + dialog.dismiss(); + } + }); + androidx.appcompat.app.AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); + } + return super.onOptionsItemSelected(item); + } + + private void manageAccount() { SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE); String accountIdRelation = account.getAcct(); @@ -154,28 +188,9 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi retrieveRelationship = new RetrieveRelationshipAsyncTask(ShowAccountActivity.this, accountIdRelation, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - TextView actionbar_title = findViewById(R.id.show_account_title); - if (account.getAcct() != null) - actionbar_title.setText(account.getAcct()); - ImageView pp_actionBar = findViewById(R.id.pp_actionBar); - if (account.getAvatar() != null) { - Helper.loadGiF(ShowAccountActivity.this, account, pp_actionBar); - - } - final AppBarLayout appBar = findViewById(R.id.appBar); + setTitle(account.getAcct()); - appBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { - if (pp_actionBar != null) { - if (Math.abs(verticalOffset) - appBar.getTotalScrollRange() == 0) { - if (pp_actionBar.getVisibility() == View.GONE) - pp_actionBar.setVisibility(View.VISIBLE); - } else { - if (pp_actionBar.getVisibility() == View.VISIBLE) - pp_actionBar.setVisibility(View.GONE); - } - } - }); mPager = findViewById(R.id.account_viewpager); if (!ischannel) { tabLayout.addTab(tabLayout.newTab().setText(getString(R.string.videos))); @@ -387,13 +402,24 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi Intent intentBC = new Intent(Helper.RECEIVE_ACTION); intentBC.putExtras(b); } - retrieveRelationship = new RetrieveRelationshipAsyncTask(ShowAccountActivity.this, target, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (statusAction == PeertubeAPI.StatusAction.UNFOLLOW || statusAction == PeertubeAPI.StatusAction.FOLLOW) { + retrieveRelationship = new RetrieveRelationshipAsyncTask(ShowAccountActivity.this, target, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else if (statusAction == PeertubeAPI.StatusAction.MUTE) { + Toasty.info(ShowAccountActivity.this, getString(R.string.muted_done), Toast.LENGTH_LONG).show(); + } } @Override public void onRetrieveAccounts(APIResponse apiResponse) { if (apiResponse.getAccounts() != null && apiResponse.getAccounts().size() == 1) { Account account = apiResponse.getAccounts().get(0); + if (this.account == null) { + this.account = account; + manageAccount(); + } + if (account.getchannelOwner() != null) { + this.account.setchannelOwner(account.getchannelOwner()); + } subscriber_count.setText(getString(R.string.followers_count, Helper.withSuffix(account.getFollowers_count()))); subscriber_count.setVisibility(View.VISIBLE); manageNotes(account); @@ -424,7 +450,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi } /** - * Pager adapter for the 4 fragments + * Pager adapter for the 2 fragments */ private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/PostActionAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/PostActionAsyncTask.java index 3bccc88..294a718 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/PostActionAsyncTask.java +++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/PostActionAsyncTask.java @@ -65,9 +65,10 @@ public class PostActionAsyncTask extends AsyncTask { protected Void doInBackground(Void... params) { PeertubeAPI peertubeAPI = new PeertubeAPI(contextReference.get()); - if (apiAction == PeertubeAPI.StatusAction.FOLLOW || apiAction == PeertubeAPI.StatusAction.UNFOLLOW) + if (apiAction == PeertubeAPI.StatusAction.FOLLOW || apiAction == PeertubeAPI.StatusAction.UNFOLLOW + || apiAction == PeertubeAPI.StatusAction.MUTE || apiAction == PeertubeAPI.StatusAction.UNMUTE) { statusCode = peertubeAPI.postAction(apiAction, targetedId); - else if (apiAction == PeertubeAPI.StatusAction.RATEVIDEO) + } else if (apiAction == PeertubeAPI.StatusAction.RATEVIDEO) statusCode = peertubeAPI.postRating(targetedId, comment); else if (apiAction == PeertubeAPI.StatusAction.PEERTUBECOMMENT) statusCode = peertubeAPI.postComment(targetedId, comment); diff --git a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java index 4633c9b..2cb5303 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java +++ b/app/src/main/java/app/fedilab/fedilabtube/asynctasks/RetrieveAccountsAsyncTask.java @@ -28,12 +28,12 @@ public class RetrieveAccountsAsyncTask extends AsyncTask contextReference; - private String name; - private actionType type; + private String max_id; + private accountFetch type; - public RetrieveAccountsAsyncTask(Context context, String name, actionType type, OnRetrieveAccountsInterface onRetrieveAccountsInterface) { + public RetrieveAccountsAsyncTask(Context context, String max_id, accountFetch type, OnRetrieveAccountsInterface onRetrieveAccountsInterface) { this.contextReference = new WeakReference<>(context); - this.name = name; + this.max_id = max_id; this.listener = onRetrieveAccountsInterface; this.type = type; } @@ -41,10 +41,12 @@ public class RetrieveAccountsAsyncTask extends AsyncTask { +public class RetrievePeertubeNotificationsAsyncTask extends AsyncTask { - private APIResponse apiResponse; private String max_id; private Account account; private OnRetrievePeertubeNotificationsInterface listener; @@ -44,24 +43,26 @@ public class RetrievePeertubeNotificationsAsyncTask extends AsyncTask. */ + +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 RetrieveSingleAccountAsyncTask extends AsyncTask { + + private OnRetrieveAccountsInterface listener; + private WeakReference contextReference; + private String name; + private actionType type; + + public RetrieveSingleAccountAsyncTask(Context context, String name, actionType type, OnRetrieveAccountsInterface onRetrieveAccountsInterface) { + this.contextReference = new WeakReference<>(context); + this.name = name; + this.listener = onRetrieveAccountsInterface; + this.type = type; + } + + @Override + protected APIResponse doInBackground(Void... params) { + PeertubeAPI peertubeAPI = new PeertubeAPI(this.contextReference.get()); + if (type == actionType.ACCOUNT) { + return peertubeAPI.getPeertubeChannel(name); + } else if (type == actionType.CHANNEL) { + return peertubeAPI.getPeertubeChannelInfo(name); + } else { + return null; + } + } + + @Override + protected void onPostExecute(APIResponse apiResponse) { + listener.onRetrieveAccounts(apiResponse); + } + + public enum actionType { + ACCOUNT, + CHANNEL + } + +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java index 8360760..896e6d6 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeAPI.java @@ -45,6 +45,7 @@ import java.util.Objects; import app.fedilab.fedilabtube.R; import app.fedilab.fedilabtube.client.entities.Account; import app.fedilab.fedilabtube.client.entities.AccountCreation; +import app.fedilab.fedilabtube.client.entities.ChannelCreation; import app.fedilab.fedilabtube.client.entities.Error; import app.fedilab.fedilabtube.client.entities.Instance; import app.fedilab.fedilabtube.client.entities.Peertube; @@ -167,6 +168,7 @@ public class PeertubeAPI { peertubeAccountNotification.setDisplayName(channel.getString("displayName")); peertubeAccountNotification.setName(channel.getString("name")); peertubeAccountNotification.setId(channel.getString("id")); + peertubeAccountNotification.setHost(channel.getString("host")); if (channel.has("avatar")) { peertubeAccountNotification.setAvatar(channel.getJSONObject("avatar").getString("path")); } @@ -255,13 +257,11 @@ public class PeertubeAPI { peertube.setCommentsEnabled(resobj.getBoolean("commentsEnabled")); } catch (Exception ignored) { } - try { peertube.setCreated_at(Helper.mstStringToDate(resobj.getString("createdAt"))); } catch (ParseException e) { e.printStackTrace(); } - try { LinkedHashMap langue = new LinkedHashMap<>(); LinkedHashMap category = new LinkedHashMap<>(); @@ -271,7 +271,6 @@ public class PeertubeAPI { license.put(resobj.getJSONObject("licence").getInt("id"), resobj.getJSONObject("licence").getString("label")); privacy.put(resobj.getJSONObject("privacy").getInt("id"), resobj.getJSONObject("privacy").getString("label")); langue.put(resobj.getJSONObject("language").getString("id"), resobj.getJSONObject("language").getString("label")); - peertube.setCategory(category); peertube.setLicense(license); peertube.setLanguage(langue); @@ -345,7 +344,6 @@ public class PeertubeAPI { resolutions.add(attObj.getJSONObject("resolution").getString("id")); } peertube.setResolution(resolutions); - peertube.setStreamService(true); } else { JSONArray files = resobj.getJSONArray("files"); for (int j = 0; j < files.length(); j++) { @@ -353,7 +351,6 @@ public class PeertubeAPI { resolutions.add(attObj.getJSONObject("resolution").getString("id")); } peertube.setResolution(resolutions); - peertube.setStreamService(false); } try { LinkedHashMap langue = new LinkedHashMap<>(); @@ -433,6 +430,9 @@ public class PeertubeAPI { account.setHost(accountObject.get("host").toString()); account.setSocial("PEERTUBE"); account.setInstance(accountObject.getString("host")); + if (accountObject.has("ownerAccount")) { + account.setchannelOwner(parseAccountResponsePeertube(accountObject.getJSONObject("ownerAccount"))); + } if (accountObject.has("createdAt")) account.setCreated_at(Helper.mstStringToDate(accountObject.get("createdAt").toString())); else @@ -849,6 +849,45 @@ public class PeertubeAPI { return apiResponse; } + /** + * Create a channel fot the authenticated user + * + * @param channelCreation channelCreation + */ + public void createChannel(ChannelCreation channelCreation) throws HttpsConnection.HttpsConnectionException { + actionCode = -1; + try { + HashMap 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.post(getAbsoluteUrl("/video-channels"), 30, params, prefKeyOauthTokenT); + actionCode = httpsConnection.getActionCode(); + } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { + e.printStackTrace(); + } + } + + /** + * Delete a Channel + * + * @param channelId String, the channel id + * @return int + */ + public int deleteChannel(String channelId) throws HttpsConnection.HttpsConnectionException { + try { + HttpsConnection httpsConnection = new HttpsConnection(context); + httpsConnection.delete(getAbsoluteUrl(String.format("/video-channels/%s", channelId)), 60, null, prefKeyOauthTokenT); + actionCode = httpsConnection.getActionCode(); + } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { + e.printStackTrace(); + } + return actionCode; + } + + /*** * Verifiy credential of the authenticated user *synchronously* * @return Account @@ -1207,6 +1246,32 @@ public class PeertubeAPI { return apiResponse; } + /** + * Retrieves muted accounts *synchronously* + * + * @param max_id String id max + * @return APIResponse + */ + public APIResponse getMuted(String max_id) { + List accounts = new ArrayList<>(); + try { + HttpsConnection httpsConnection = new HttpsConnection(context); + HashMap params = new HashMap<>(); + if (max_id != null) + params.put("start", max_id); + params.put("sort", "-createdAt"); + String response = httpsConnection.get(getAbsoluteUrl("/users/me/blocklist/accounts"), 10, params, prefKeyOauthTokenT); + JSONArray jsonArray = new JSONObject(response).getJSONArray("data"); + accounts = parseBlockedAccountResponsePeertube(jsonArray); + } catch (HttpsConnection.HttpsConnectionException e) { + setError(e.getStatusCode(), e); + e.printStackTrace(); + } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { + e.printStackTrace(); + } + apiResponse.setAccounts(accounts); + return apiResponse; + } /** * Retrieves overview videos *synchronously* @@ -1525,6 +1590,15 @@ public class PeertubeAPI { action = String.format("/users/me/subscriptions/%s", targetedId); actionCall = "DELETE"; break; + case MUTE: + action = "/users/me/blocklist/accounts"; + params = new HashMap<>(); + params.put("accountName", targetedId); + break; + case UNMUTE: + action = String.format("/users/me/blocklist/accounts/%s", targetedId); + actionCall = "DELETE"; + break; case RATEVIDEO: action = String.format("/videos/%s/rate", targetedId); params = new HashMap<>(); @@ -1568,6 +1642,7 @@ public class PeertubeAPI { actionCode = httpsConnection.getActionCode(); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); + e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { e.printStackTrace(); } @@ -1632,6 +1707,29 @@ public class PeertubeAPI { return apiResponse; } + + /** + * Create a Playlist + * + * @param playlistElement PlaylistElement, the playlist elements + * @return int + */ + public int createPlaylist(PlaylistElement playlistElement) throws HttpsConnection.HttpsConnectionException { + try { + HttpsConnection httpsConnection = new HttpsConnection(context); + HashMap params = new HashMap<>(); + params.put("videoChannelId", playlistElement.getVideoChannelId()); + params.put("privacy", playlistElement.getPrivacy()); + params.put("displayName", playlistElement.getDisplayName()); + httpsConnection.post(getAbsoluteUrl("/video-playlists/"), 60, params, prefKeyOauthTokenT); + actionCode = httpsConnection.getActionCode(); + } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { + e.printStackTrace(); + } + return actionCode; + } + + /** * Delete a Playlist * @@ -1898,6 +1996,25 @@ public class PeertubeAPI { return playlists; } + + private List parseBlockedAccountResponsePeertube(JSONArray jsonArray) { + List accounts = new ArrayList<>(); + try { + int i = 0; + while (i < jsonArray.length()) { + if (jsonArray.getJSONObject(i).has("blockedAccount")) { + JSONObject resobj = jsonArray.getJSONObject(i).getJSONObject("blockedAccount"); + Account account = parseAccountResponsePeertube(resobj); + accounts.add(account); + } + i++; + } + } catch (JSONException e) { + setDefaultError(e); + } + return accounts; + } + private List parseAccountResponsePeertube(JSONArray jsonArray) { List accounts = new ArrayList<>(); try { @@ -1967,6 +2084,8 @@ public class PeertubeAPI { public enum StatusAction { FOLLOW, UNFOLLOW, + MUTE, + UNMUTE, RATEVIDEO, PEERTUBECOMMENT, PEERTUBEREPLY, diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/Account.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/Account.java index da16d54..f60f444 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/Account.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/Account.java @@ -64,7 +64,7 @@ public class Account implements Parcelable { private boolean isFollowing; private followAction followType = followAction.NOTHING; private boolean isMakingAction = false; - private Account moved_to_account; + private Account channelOwner; private boolean muting_notifications; private String host; private boolean isBot; @@ -115,7 +115,7 @@ public class Account implements Parcelable { int tmpFollowType = in.readInt(); this.followType = tmpFollowType == -1 ? null : followAction.values()[tmpFollowType]; this.isMakingAction = in.readByte() != 0; - this.moved_to_account = in.readParcelable(Account.class.getClassLoader()); + this.channelOwner = in.readParcelable(Account.class.getClassLoader()); this.muting_notifications = in.readByte() != 0; this.host = in.readString(); this.isBot = in.readByte() != 0; @@ -167,7 +167,7 @@ public class Account implements Parcelable { dest.writeByte(this.isFollowing ? (byte) 1 : (byte) 0); dest.writeInt(this.followType == null ? -1 : this.followType.ordinal()); dest.writeByte(this.isMakingAction ? (byte) 1 : (byte) 0); - dest.writeParcelable(this.moved_to_account, flags); + dest.writeParcelable(this.channelOwner, flags); dest.writeByte(this.muting_notifications ? (byte) 1 : (byte) 0); dest.writeString(this.host); dest.writeByte(this.isBot ? (byte) 1 : (byte) 0); @@ -201,12 +201,12 @@ public class Account implements Parcelable { isMakingAction = makingAction; } - public Account getMoved_to_account() { - return moved_to_account; + public Account getchannelOwner() { + return channelOwner; } - public void setMoved_to_account(Account moved_to_account) { - this.moved_to_account = moved_to_account; + public void setchannelOwner(Account moved_to_account) { + this.channelOwner = moved_to_account; } public boolean isMuting_notifications() { diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/ChannelCreation.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/ChannelCreation.java new file mode 100644 index 0000000..68b8cb6 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/ChannelCreation.java @@ -0,0 +1,55 @@ +package app.fedilab.fedilabtube.client.entities; + +/* 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 . */ + +public class ChannelCreation { + private String displayName; + private String name; + private String description; + private String support; + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getSupport() { + return support; + } + + public void setSupport(String support) { + this.support = support; + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/Peertube.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/Peertube.java index 6a8dd87..545363c 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/Peertube.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/Peertube.java @@ -14,12 +14,17 @@ package app.fedilab.fedilabtube.client.entities; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.content.Context; +import android.content.SharedPreferences; + import org.json.JSONObject; import java.util.Date; import java.util.HashMap; import java.util.List; +import app.fedilab.fedilabtube.helper.Helper; + @SuppressWarnings("unused") public class Peertube { @@ -54,7 +59,6 @@ public class Peertube { private String headerType = null; private String headerTypeValue = null; private JSONObject cache; - private boolean streamService; public Peertube() { } @@ -173,11 +177,13 @@ public class Peertube { this.account = account; } - public String getFileUrl(String resolution, boolean streamService) { + public String getFileUrl(String resolution, Context context) { if (resolution == null) resolution = this.getResolution().get(0); if (resolution == null) return null; + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean streamService = sharedpreferences.getInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_NORMAL) == Helper.VIDEO_MODE_STREAMING; if (streamService) { return "https://" + this.host + "/static/streaming-playlists/hls/" + getUuid() + "/" + getUuid() + "-" + resolution + "-fragmented.mp4"; } else { @@ -205,11 +211,13 @@ public class Peertube { } - public String getFileDownloadUrl(String resolution, boolean streamService) { + public String getFileDownloadUrl(String resolution, Context context) { if (resolution == null) resolution = this.getResolution().get(0); if (resolution == null) return null; + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + boolean streamService = sharedpreferences.getInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_NORMAL) == Helper.VIDEO_MODE_STREAMING; if (streamService) { return "https://" + this.host + "/download/streaming-playlists/hls/videos/" + getUuid() + "/" + getUuid() + "-" + resolution + "-fragmented.mp4"; } else { @@ -347,12 +355,4 @@ public class Peertube { public void setHeaderTypeValue(String headerTypeValue) { this.headerTypeValue = headerTypeValue; } - - public boolean isStreamService() { - return streamService; - } - - public void setStreamService(boolean streamService) { - this.streamService = streamService; - } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/PlaylistElement.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/PlaylistElement.java index 5e71d0e..a3f2044 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/PlaylistElement.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/PlaylistElement.java @@ -19,6 +19,10 @@ public class PlaylistElement { private String playlistElementId; private String playlistId; + private String videoChannelId; + private String privacy; + private String displayName; + private String description; private long startTimestamp; private long stopTimestamp; @@ -53,4 +57,36 @@ public class PlaylistElement { public void setStopTimestamp(long stopTimestamp) { this.stopTimestamp = stopTimestamp; } + + public String getVideoChannelId() { + return videoChannelId; + } + + public void setVideoChannelId(String videoChannelId) { + this.videoChannelId = videoChannelId; + } + + public String getPrivacy() { + return privacy; + } + + public void setPrivacy(String privacy) { + this.privacy = privacy; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java b/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java index 0259b6a..5bf92c7 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java +++ b/app/src/main/java/app/fedilab/fedilabtube/drawer/AccountsListAdapter.java @@ -14,10 +14,13 @@ package app.fedilab.fedilabtube.drawer; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.text.Html; import android.text.util.Linkify; import android.view.LayoutInflater; @@ -29,6 +32,8 @@ import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentTransaction; import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -37,9 +42,13 @@ import java.util.List; import app.fedilab.fedilabtube.R; import app.fedilab.fedilabtube.ShowAccountActivity; +import app.fedilab.fedilabtube.asynctasks.PostActionAsyncTask; +import app.fedilab.fedilabtube.asynctasks.RetrieveAccountsAsyncTask; +import app.fedilab.fedilabtube.client.HttpsConnection; import app.fedilab.fedilabtube.client.PeertubeAPI; import app.fedilab.fedilabtube.client.entities.Account; import app.fedilab.fedilabtube.client.entities.Error; +import app.fedilab.fedilabtube.fragment.DisplayPlaylistsFragment; import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.interfaces.OnPostActionInterface; import es.dmoral.toasty.Toasty; @@ -47,17 +56,18 @@ import es.dmoral.toasty.Toasty; public class AccountsListAdapter extends RecyclerView.Adapter implements OnPostActionInterface { + public AllAccountsRemoved allAccountsRemoved; private List accounts; - private Context context; private AccountsListAdapter accountsListAdapter; + private RetrieveAccountsAsyncTask.accountFetch type; - public AccountsListAdapter(String targetedId, List accounts) { + public AccountsListAdapter(RetrieveAccountsAsyncTask.accountFetch type, List accounts) { this.accounts = accounts; this.accountsListAdapter = this; + this.type = type; } - @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -70,10 +80,58 @@ public class AccountsListAdapter extends RecyclerView.Adapter { + 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(); + }); + } else if (type == RetrieveAccountsAsyncTask.accountFetch.MUTED) { + holder.account_action.setOnClickListener(v -> new PostActionAsyncTask(context, PeertubeAPI.StatusAction.UNMUTE, account.getAcct(), AccountsListAdapter.this).execute()); + } else { + holder.account_action.hide(); + } if (account.getDisplay_name() != null && !account.getDisplay_name().trim().equals("")) holder.account_dn.setText(account.getDisplay_name()); @@ -96,15 +154,16 @@ public class AccountsListAdapter extends RecyclerView.Adapter { + if (type == RetrieveAccountsAsyncTask.accountFetch.MUTED) { + holder.account_action.show(); + holder.account_action.setImageResource(R.drawable.ic_baseline_volume_mute_24); + } - }); holder.account_pp.setOnClickListener(v -> { Intent intent = new Intent(context, ShowAccountActivity.class); @@ -117,6 +176,7 @@ public class AccountsListAdapter extends RecyclerView.Adapter position) - return accounts.get(position); - else - return null; - } - @Override public void onPostAction(int statusCode, PeertubeAPI.StatusAction statusAction, String targetedId, Error error) { if (error != null) { @@ -144,18 +197,28 @@ public class AccountsListAdapter extends RecyclerView.Adapter { Intent intent = new Intent(context, ShowAccountActivity.class); Bundle b = new Bundle(); - b.putBoolean("peertubeaccount", true); - b.putString("accountId", finalAccountAction1.getName()); + b.putString("accountId", finalAccountAction1.getName() + "@" + finalAccountAction1.getHost()); + b.putBoolean("ischannel", true); intent.putExtras(b); context.startActivity(intent); }); } else if (notification.getPeertubeComment() != null) { //Comment Notification - String profileUrl = "https://" + Helper.getLiveInstance(context) + notification.getPeertubeComment().getPeertubeAccountNotification().getAvatar(); + String profileUrl = notification.getPeertubeComment().getPeertubeAccountNotification().getAvatar(); Helper.loadGiF(context, profileUrl, holder.peertube_notif_pp); accountAction = notification.getPeertubeComment().getPeertubeAccountNotification(); videoAction = notification.getPeertubeComment().getPeertubeVideoNotification(); @@ -113,7 +113,7 @@ public class PeertubeNotificationsListAdapter extends RecyclerView.Adapter { Intent intent = new Intent(context, PlaylistsActivity.class); @@ -101,7 +96,8 @@ public class PlaylistAdapter extends BaseAdapter implements OnPlaylistActionInte context.startActivity(intent); }); - holder.search_container.setOnLongClickListener(v -> { + + holder.action_delete.setOnClickListener(v -> { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(context.getString(R.string.action_lists_delete) + ": " + playlist.getDisplayName()); builder.setMessage(context.getString(R.string.action_lists_confirm_delete)); @@ -116,8 +112,6 @@ public class PlaylistAdapter extends BaseAdapter implements OnPlaylistActionInte }) .setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss()) .show(); - - return false; }); return convertView; } @@ -130,6 +124,7 @@ public class PlaylistAdapter extends BaseAdapter implements OnPlaylistActionInte private static class ViewHolder { LinearLayout search_container; TextView search_title; + FloatingActionButton action_delete; } diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java index 1364ad4..bd0875e 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayAccountsFragment.java @@ -14,35 +14,51 @@ package app.fedilab.fedilabtube.fragment; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.RelativeLayout; +import android.widget.TextView; 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.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + import java.util.ArrayList; import java.util.List; import app.fedilab.fedilabtube.R; import app.fedilab.fedilabtube.asynctasks.RetrieveAccountsAsyncTask; +import app.fedilab.fedilabtube.asynctasks.RetrieveSingleAccountAsyncTask; import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.HttpsConnection; +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.interfaces.OnRetrieveAccountsInterface; import es.dmoral.toasty.Toasty; -public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccountsInterface { +public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccountsInterface, AccountsListAdapter.AllAccountsRemoved { private boolean flag_loading; private Context context; @@ -53,24 +69,25 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; private boolean firstLoad; private SwipeRefreshLayout swipeRefreshLayout; - private String targetedId, name; + private String name; private boolean swiped; private RecyclerView lv_accounts; private View rootView; + private RetrieveAccountsAsyncTask.accountFetch accountFetch; + private FloatingActionButton action_button; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - rootView = inflater.inflate(R.layout.fragment_accounts, container, false); + rootView = inflater.inflate(R.layout.fragment_recyclerview, container, false); context = getContext(); Bundle bundle = this.getArguments(); accounts = new ArrayList<>(); if (bundle != null) { - if (bundle.containsKey("tag")) - targetedId = bundle.getString("tag", null); - else - targetedId = bundle.getString("targetedid", null); + if (bundle.containsKey("accountFetch")) { + accountFetch = (RetrieveAccountsAsyncTask.accountFetch) bundle.getSerializable("accountFetch"); + } name = bundle.getString("name", null); } max_id = null; @@ -81,16 +98,95 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); - lv_accounts = rootView.findViewById(R.id.lv_accounts); + 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(); + }); + } + lv_accounts = rootView.findViewById(R.id.lv_elements); lv_accounts.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); mainLoader = rootView.findViewById(R.id.loader); - nextElementLoader = rootView.findViewById(R.id.loading_next_accounts); + nextElementLoader = rootView.findViewById(R.id.loading_next); textviewNoAction = rootView.findViewById(R.id.no_action); mainLoader.setVisibility(View.VISIBLE); nextElementLoader.setVisibility(View.GONE); - accountsListAdapter = new AccountsListAdapter(targetedId, this.accounts); + accountsListAdapter = new AccountsListAdapter(accountFetch, this.accounts); + accountsListAdapter.allAccountsRemoved = this; lv_accounts.setAdapter(accountsListAdapter); - + TextView no_action_text = rootView.findViewById(R.id.no_action_text); + if (accountFetch == RetrieveAccountsAsyncTask.accountFetch.MUTED) { + no_action_text.setText(context.getString(R.string.no_muted)); + } final LinearLayoutManager mLayoutManager; mLayoutManager = new LinearLayoutManager(context); lv_accounts.setLayoutManager(mLayoutManager); @@ -103,7 +199,12 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou if (firstVisibleItem + visibleItemCount == totalItemCount) { if (!flag_loading) { flag_loading = true; - asyncTask = new RetrieveAccountsAsyncTask(context, name, RetrieveAccountsAsyncTask.actionType.ACCOUNT, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (accountFetch == null) { + asyncTask = new RetrieveSingleAccountAsyncTask(context, name, RetrieveSingleAccountAsyncTask.actionType.ACCOUNT, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + String param = accountFetch == RetrieveAccountsAsyncTask.accountFetch.CHANNEL ? name : max_id; + asyncTask = new RetrieveAccountsAsyncTask(context, param, accountFetch, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } nextElementLoader.setVisibility(View.VISIBLE); } } else { @@ -114,10 +215,25 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou }); swipeRefreshLayout.setOnRefreshListener(this::pullToRefresh); - asyncTask = new RetrieveAccountsAsyncTask(context, name, RetrieveAccountsAsyncTask.actionType.ACCOUNT, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (accountFetch == null) { + asyncTask = new RetrieveSingleAccountAsyncTask(context, name, RetrieveSingleAccountAsyncTask.actionType.ACCOUNT, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + String param = accountFetch == RetrieveAccountsAsyncTask.accountFetch.CHANNEL ? name : null; + asyncTask = new RetrieveAccountsAsyncTask(context, param, accountFetch, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } return rootView; } + @Override + public void onResume() { + super.onResume(); + if (accountFetch == RetrieveAccountsAsyncTask.accountFetch.CHANNEL) { + action_button.setVisibility(View.VISIBLE); + } else { + action_button.setVisibility(View.GONE); + } + } + @Override public void onDestroyView() { super.onDestroyView(); @@ -169,7 +285,7 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou max_id = apiResponse.getMax_id(); if (swiped) { - accountsListAdapter = new AccountsListAdapter(targetedId, this.accounts); + accountsListAdapter = new AccountsListAdapter(accountFetch, this.accounts); lv_accounts.setAdapter(accountsListAdapter); swiped = false; } @@ -189,7 +305,16 @@ public class DisplayAccountsFragment extends Fragment implements OnRetrieveAccou flag_loading = true; swiped = true; swipeRefreshLayout.setRefreshing(true); - asyncTask = new RetrieveAccountsAsyncTask(context, name, RetrieveAccountsAsyncTask.actionType.ACCOUNT, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (accountFetch == null) { + asyncTask = new RetrieveSingleAccountAsyncTask(context, name, RetrieveSingleAccountAsyncTask.actionType.ACCOUNT, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + String param = accountFetch == RetrieveAccountsAsyncTask.accountFetch.CHANNEL ? name : null; + asyncTask = new RetrieveAccountsAsyncTask(context, param, accountFetch, DisplayAccountsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } } + @Override + public void onAllAccountsRemoved() { + textviewNoAction.setVisibility(View.VISIBLE); + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java new file mode 100644 index 0000000..14dab02 --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayNotificationsFragment.java @@ -0,0 +1,192 @@ +package app.fedilab.fedilabtube.fragment; +/* 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 . */ + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.fedilabtube.R; +import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeNotificationsAsyncTask; +import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.entities.Account; +import app.fedilab.fedilabtube.client.entities.PeertubeNotification; +import app.fedilab.fedilabtube.drawer.PeertubeNotificationsListAdapter; +import app.fedilab.fedilabtube.interfaces.OnRetrievePeertubeNotificationsInterface; +import es.dmoral.toasty.Toasty; + + +public class DisplayNotificationsFragment extends Fragment implements OnRetrievePeertubeNotificationsInterface { + + private boolean flag_loading; + private Context context; + private AsyncTask asyncTask; + private PeertubeNotificationsListAdapter peertubeNotificationsListAdapter; + private String max_id; + private List notifications; + private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; + private boolean firstLoad; + private SwipeRefreshLayout swipeRefreshLayout; + private boolean swiped; + private RecyclerView lv_notifications; + private View rootView; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + rootView = inflater.inflate(R.layout.fragment_recyclerview, container, false); + + context = getContext(); + notifications = new ArrayList<>(); + max_id = null; + firstLoad = true; + flag_loading = true; + swiped = false; + + swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); + + + lv_notifications = rootView.findViewById(R.id.lv_elements); + lv_notifications.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); + mainLoader = rootView.findViewById(R.id.loader); + nextElementLoader = rootView.findViewById(R.id.loading_next); + textviewNoAction = rootView.findViewById(R.id.no_action); + mainLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.GONE); + peertubeNotificationsListAdapter = new PeertubeNotificationsListAdapter(this.notifications); + lv_notifications.setAdapter(peertubeNotificationsListAdapter); + + final LinearLayoutManager mLayoutManager; + mLayoutManager = new LinearLayoutManager(context); + lv_notifications.setLayoutManager(mLayoutManager); + lv_notifications.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + if (dy > 0) { + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (firstVisibleItem + visibleItemCount == totalItemCount) { + if (!flag_loading) { + flag_loading = true; + asyncTask = new RetrievePeertubeNotificationsAsyncTask(context, null, max_id, DisplayNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } + }); + swipeRefreshLayout.setOnRefreshListener(this::pullToRefresh); + + asyncTask = new RetrievePeertubeNotificationsAsyncTask(context, null, null, DisplayNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + return rootView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + @Override + public void onCreate(Bundle saveInstance) { + super.onCreate(saveInstance); + } + + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + this.context = context; + } + + public void onDestroy() { + super.onDestroy(); + if (asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING) + asyncTask.cancel(true); + } + + public void scrollToTop() { + if (lv_notifications != null) + lv_notifications.setAdapter(peertubeNotificationsListAdapter); + } + + + public void pullToRefresh() { + max_id = null; + notifications = new ArrayList<>(); + firstLoad = true; + flag_loading = true; + swiped = true; + swipeRefreshLayout.setRefreshing(true); + asyncTask = new RetrievePeertubeNotificationsAsyncTask(context, null, null, DisplayNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + @Override + public void onRetrievePeertubeNotifications(APIResponse apiResponse, Account account) { + mainLoader.setVisibility(View.GONE); + nextElementLoader.setVisibility(View.GONE); + if (apiResponse.getError() != null) { + Toasty.error(context, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); + flag_loading = false; + swipeRefreshLayout.setRefreshing(false); + swiped = false; + return; + } + + int previousPosition = notifications.size(); + max_id = apiResponse.getMax_id(); + List notifications = apiResponse.getPeertubeNotifications(); + if (!swiped && firstLoad && (notifications == null || notifications.size() == 0)) + textviewNoAction.setVisibility(View.VISIBLE); + else + textviewNoAction.setVisibility(View.GONE); + if (swiped) { + if (previousPosition > 0) { + this.notifications.subList(0, previousPosition).clear(); + peertubeNotificationsListAdapter.notifyItemRangeRemoved(0, previousPosition); + } + swiped = false; + } + + if (notifications != null && notifications.size() > 0) { + this.notifications.addAll(notifications); + peertubeNotificationsListAdapter.notifyItemRangeInserted(previousPosition, notifications.size()); + } else { + if (firstLoad) + textviewNoAction.setVisibility(View.VISIBLE); + } + swipeRefreshLayout.setRefreshing(false); + firstLoad = false; + //The initial call comes from a classic tab refresh + flag_loading = (max_id == null); + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java index 95fc27c..cc7212f 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayPlaylistsFragment.java @@ -16,11 +16,11 @@ package app.fedilab.fedilabtube.fragment; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; -import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.text.InputFilter; import android.view.LayoutInflater; import android.view.View; @@ -43,15 +43,8 @@ import androidx.fragment.app.FragmentTransaction; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import net.gotev.uploadservice.MultipartUploadRequest; -import net.gotev.uploadservice.ServerResponse; -import net.gotev.uploadservice.UploadInfo; -import net.gotev.uploadservice.UploadNotificationConfig; -import net.gotev.uploadservice.UploadStatusDelegate; - import org.jetbrains.annotations.NotNull; -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -64,10 +57,12 @@ import app.fedilab.fedilabtube.R; import app.fedilab.fedilabtube.asynctasks.ManagePlaylistsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeChannelsAsyncTask; import app.fedilab.fedilabtube.client.APIResponse; +import app.fedilab.fedilabtube.client.HttpsConnection; +import app.fedilab.fedilabtube.client.PeertubeAPI; import app.fedilab.fedilabtube.client.entities.Account; import app.fedilab.fedilabtube.client.entities.Playlist; +import app.fedilab.fedilabtube.client.entities.PlaylistElement; import app.fedilab.fedilabtube.drawer.PlaylistAdapter; -import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.interfaces.OnPlaylistActionInterface; import app.fedilab.fedilabtube.interfaces.OnRetrievePeertubeInterface; import es.dmoral.toasty.Toasty; @@ -113,11 +108,6 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi asyncTask = new ManagePlaylistsAsyncTask(context, ManagePlaylistsAsyncTask.action.GET_PLAYLIST, null, null, null, DisplayPlaylistsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); add_new = rootView.findViewById(R.id.add_new); - - LinkedHashMap translations = null; - if (peertubeInformation != null && peertubeInformation.getTranslations() != null) - translations = new LinkedHashMap<>(peertubeInformation.getTranslations()); - LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies()); Map.Entry entryInt = privaciesInit.entrySet().iterator().next(); privacyToSend = new HashMap<>(); @@ -131,7 +121,6 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi if (add_new != null) { add_new.setOnClickListener(view -> { - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); LayoutInflater inflater1 = ((Activity) context).getLayoutInflater(); View dialogView = inflater1.inflate(R.layout.add_playlist, new LinearLayout(context), false); @@ -147,97 +136,79 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi display_name.setFilters(new InputFilter[]{new InputFilter.LengthFilter(120)}); description.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1000)}); - dialogBuilder.setPositiveButton(R.string.validate, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { + dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { - if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0) { + if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0) { - Playlist playlist = new Playlist(); - playlist.setDisplayName(display_name.getText().toString().trim()); - if (description.getText() != null && description.getText().toString().trim().length() > 0) { - playlist.setDescription(description.getText().toString().trim()); - } - String idChannel = null; - if (channelToSend != null) { - Map.Entry channelM = channelToSend.entrySet().iterator().next(); - idChannel = channelM.getValue(); - if (idChannel.length() > 0) - playlist.setVideoChannelId(idChannel); - } - Map.Entry privacyM = privacyToSend.entrySet().iterator().next(); - String label = privacyM.getValue(); - String idPrivacy = String.valueOf(privacyM.getKey()); - if (label.equals("Public") && (playlist.getVideoChannelId() == null || playlist.getVideoChannelId().equals(""))) { - Toasty.error(context, context.getString(R.string.error_channel_mandatory), Toast.LENGTH_LONG).show(); - } else { - if (privacyToSend != null) { - playlist.setPrivacy(privacyToSend); - } - //new ManagePlaylistsAsyncTask(context, ManagePlaylistsAsyncTask.action.CREATE_PLAYLIST, playlist, null, null, DisplayPlaylistsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - UploadNotificationConfig uploadConfig = new UploadNotificationConfig(); - uploadConfig.getCompleted().autoClear = true; - try { - String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); - new MultipartUploadRequest(context, "https://" + Helper.getLiveInstance(context) + "/api/v1/video-playlists/") - //.addFileToUpload(uri.toString().replace("file://",""), "videofile") - .addHeader("Authorization", "Bearer " + token) - .setNotificationConfig(uploadConfig) - // .addParameter("name", filename) - .addParameter("videoChannelId", idChannel) - .addParameter("privacy", idPrivacy) - .addParameter("displayName", playlist.getDisplayName()) - .addParameter("description", playlist.getDescription()) - .setMaxRetries(1) - .setDelegate(new UploadStatusDelegate() { - @Override - public void onProgress(Context context, UploadInfo uploadInfo) { - // your code here - } - - @Override - public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, - Exception exception) { - // your code here - exception.printStackTrace(); - } - - @Override - public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) { - 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(); - } - } - - @Override - public void onCancelled(Context context, UploadInfo uploadInfo) { - // your code here - } - }) - .startUpload(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - - dialog.dismiss(); - add_new.setEnabled(false); - } - } else { - Toasty.error(context, context.getString(R.string.error_display_name), Toast.LENGTH_LONG).show(); + Playlist playlist = new Playlist(); + playlist.setDisplayName(display_name.getText().toString().trim()); + if (description.getText() != null && description.getText().toString().trim().length() > 0) { + playlist.setDescription(description.getText().toString().trim()); } + String idChannel = null; + if (channelToSend != null) { + Map.Entry channelM = channelToSend.entrySet().iterator().next(); + idChannel = channelM.getValue(); + if (idChannel.length() > 0) + playlist.setVideoChannelId(idChannel); + } + Map.Entry privacyM = privacyToSend.entrySet().iterator().next(); + String label = privacyM.getValue(); + String idPrivacy = String.valueOf(privacyM.getKey()); + if (label.equals("Public") && (playlist.getVideoChannelId() == null || playlist.getVideoChannelId().equals(""))) { + Toasty.error(context, context.getString(R.string.error_channel_mandatory), Toast.LENGTH_LONG).show(); + } else { + if (privacyToSend != null) { + playlist.setPrivacy(privacyToSend); + } + PlaylistElement playlistElement = new PlaylistElement(); + playlistElement.setVideoChannelId(idChannel); + playlistElement.setPrivacy(idPrivacy); + playlistElement.setDisplayName(playlist.getDisplayName()); + playlistElement.setDescription(playlist.getDescription()); + new Thread(() -> { + try { + 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(); + } + }; + mainHandler.post(myRunnable); + add_new.setEnabled(true); + } 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(); + } + add_new.setEnabled(true); + }; + mainHandler.post(myRunnable); + } + }).start(); + dialog.dismiss(); + add_new.setEnabled(false); + } + } else { + Toasty.error(context, context.getString(R.string.error_display_name), Toast.LENGTH_LONG).show(); } + }); dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); - AlertDialog alertDialog = dialogBuilder.create(); alertDialog.setTitle(getString(R.string.action_playlist_create)); alertDialog.setOnDismissListener(dialogInterface -> { diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayStatusFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayStatusFragment.java index 4ff0343..c194832 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayStatusFragment.java +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/DisplayStatusFragment.java @@ -44,7 +44,7 @@ import java.util.ArrayList; import java.util.List; import app.fedilab.fedilabtube.R; -import app.fedilab.fedilabtube.asynctasks.RetrieveAccountSubscriptionsAsyncTask; +import app.fedilab.fedilabtube.asynctasks.RetrieveAccountsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrieveFeedsAsyncTask; import app.fedilab.fedilabtube.asynctasks.RetrievePeertubeSearchAsyncTask; import app.fedilab.fedilabtube.client.APIResponse; @@ -192,7 +192,7 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter int visibleItemCount = mLayoutManager.getChildCount(); int totalItemCount = mLayoutManager.getItemCount(); if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { - new RetrieveAccountSubscriptionsAsyncTask(context, max_id_accounts, DisplayStatusFragment.this).execute(); + new RetrieveAccountsAsyncTask(context, max_id_accounts, RetrieveAccountsAsyncTask.accountFetch.SUBSCRIPTION, DisplayStatusFragment.this).execute(); } } } @@ -261,7 +261,7 @@ public class DisplayStatusFragment extends Fragment implements OnPostActionInter }); } if (type == PSUBSCRIPTIONS) { - new RetrieveAccountSubscriptionsAsyncTask(context, max_id, DisplayStatusFragment.this).execute(); + new RetrieveAccountsAsyncTask(context, max_id, RetrieveAccountsAsyncTask.accountFetch.SUBSCRIPTION, DisplayStatusFragment.this).execute(); } display_all.setOnClickListener(v -> { diff --git a/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java b/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java new file mode 100644 index 0000000..31139fc --- /dev/null +++ b/app/src/main/java/app/fedilab/fedilabtube/fragment/SettingsFragment.java @@ -0,0 +1,109 @@ +package app.fedilab.fedilabtube.fragment; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.fragment.app.FragmentActivity; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + +import java.util.Arrays; +import java.util.List; + +import app.fedilab.fedilabtube.R; +import app.fedilab.fedilabtube.helper.Helper; +import es.dmoral.toasty.Toasty; + +/* 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 . */ + +public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.main_preferences); + createPref(); + } + + + @Override + public void onResume() { + super.onResume(); + + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.compareTo(getString(R.string.set_video_mode_choice)) == 0) { + ListPreference set_video_mode_choice = findPreference(getString(R.string.set_video_mode_choice)); + if (set_video_mode_choice != null && getActivity() != null) { + SharedPreferences sharedpreferences = getActivity().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedpreferences.edit(); + switch (set_video_mode_choice.getValue()) { + case "0": + editor.putInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_NORMAL); + break; + case "1": + editor.putInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_STREAMING); + break; + case "2": + editor.putInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_WEBVIEW); + break; + } + editor.apply(); + } + } + } + + private void createPref() { + getPreferenceScreen().removeAll(); + addPreferencesFromResource(R.xml.main_preferences); + PreferenceScreen preferenceScreen = getPreferenceScreen(); + FragmentActivity context = getActivity(); + assert context != null; + if (preferenceScreen == null) { + Toasty.error(getActivity(), getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); + return; + } + + //****** Video mode ******* + ListPreference set_video_mode_choice = findPreference(getString(R.string.set_video_mode_choice)); + List array = Arrays.asList(getResources().getStringArray(R.array.settings_video_mode)); + CharSequence[] entries = array.toArray(new CharSequence[0]); + CharSequence[] entryValues = new CharSequence[3]; + final SharedPreferences sharedpref = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + int video_mode = sharedpref.getInt(Helper.SET_VIDEO_MODE, Helper.VIDEO_MODE_NORMAL); + entryValues[0] = String.valueOf(Helper.VIDEO_MODE_NORMAL); + entryValues[1] = String.valueOf(Helper.VIDEO_MODE_STREAMING); + entryValues[2] = String.valueOf(Helper.VIDEO_MODE_WEBVIEW); + if (set_video_mode_choice != null) { + set_video_mode_choice.setEntries(entries); + set_video_mode_choice.setEntryValues(entryValues); + set_video_mode_choice.setValueIndex(video_mode); + } + + } +} diff --git a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java index 8ebf56f..3160b56 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java +++ b/app/src/main/java/app/fedilab/fedilabtube/helper/Helper.java @@ -72,10 +72,13 @@ public class Helper { public static final int RELOAD_MYVIDEOS = 10; public static final String SET_VIDEO_MODE = "set_video_mode"; - public static final int VIDEO_MODE_TORRENT = 0; - public static final int VIDEO_MODE_WEBVIEW = 1; - public static final int VIDEO_MODE_DIRECT = 2; + public static final int VIDEO_MODE_NORMAL = 0; + public static final int VIDEO_MODE_STREAMING = 1; + public static final int VIDEO_MODE_WEBVIEW = 2; + public static final int VIDEO_MODE_TORRENT = 3; public static final int ADD_USER_INTENT = 5; + public static final int VIDEO_UPLOADED_INTENT = 6; + public static final String VIDEO_UPLOAD_ID = "VIDEO_UPLOAD_ID"; public static final String SET_SHARE_DETAILS = "set_share_details"; public static final int DEFAULT_VIDEO_CACHE_MB = 100; public static final String TAG = "mastodon_etalab"; @@ -239,6 +242,9 @@ public class Helper { public static String getLiveInstance(Context context) { final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); String acad = sharedpreferences.getString(Helper.PREF_INSTANCE, "tube.ac-lyon.fr"); + if (acad == null) { + acad = "tube.ac-lyon.fr"; + } if (acad.startsWith("tube-")) { return acad; } else { @@ -449,6 +455,14 @@ public class Helper { public static void loadGiF(final Context context, String url, final ImageView imageView) { + if (url == null || url.trim().toLowerCase().compareTo("null") == 0) { + Glide.with(imageView.getContext()) + .asDrawable() + .load(R.drawable.missing_peertube) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))) + .into(imageView); + return; + } if (url.startsWith("/")) { url = Helper.getLiveInstance(context) + url; } @@ -668,4 +682,5 @@ public class Helper { return context.getResources().getBoolean(R.bool.is_tablet); } + } diff --git a/app/src/main/java/app/fedilab/fedilabtube/services/PeertubeUploadReceiver.java b/app/src/main/java/app/fedilab/fedilabtube/services/PeertubeUploadReceiver.java index d059ef7..a31f5e5 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/services/PeertubeUploadReceiver.java +++ b/app/src/main/java/app/fedilab/fedilabtube/services/PeertubeUploadReceiver.java @@ -14,6 +14,7 @@ package app.fedilab.fedilabtube.services; * You should have received a copy of the GNU General Public License along with TubeLab; if not, * see . */ +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -43,9 +44,9 @@ public class PeertubeUploadReceiver extends UploadServiceBroadcastReceiver { @Override public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, Exception exception) { - // your code here } + @SuppressLint("ApplySharedPref") @Override public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) { try { diff --git a/app/src/main/res/drawable/ic_baseline_arrow_white_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_white_24.xml index fa122e1..5d09b98 100644 --- a/app/src/main/res/drawable/ic_baseline_arrow_white_24.xml +++ b/app/src/main/res/drawable/ic_baseline_arrow_white_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/app/src/main/res/drawable/ic_baseline_delete_24.xml b/app/src/main/res/drawable/ic_baseline_delete_24.xml new file mode 100644 index 0000000..c710ac7 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_delete_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_history_24.xml b/app/src/main/res/drawable/ic_baseline_history_24.xml new file mode 100644 index 0000000..d42359c --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_history_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_slow_motion_video_24.xml b/app/src/main/res/drawable/ic_baseline_slow_motion_video_24.xml new file mode 100644 index 0000000..1804da2 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_slow_motion_video_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_volume_mute_24.xml b/app/src/main/res/drawable/ic_baseline_volume_mute_24.xml new file mode 100644 index 0000000..1f8aef5 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_volume_mute_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml new file mode 100644 index 0000000..135dbdf --- /dev/null +++ b/app/src/main/res/layout/activity_account.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + +