diff --git a/app/build.gradle b/app/build.gradle index 40e2fe5..d32d640 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { minSdkVersion 21 targetSdkVersion 30 - versionCode 28 - versionName "1.9.0-beta-1" + versionCode 29 + versionName "1.9.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/fdroid_full/play/release-notes/en-US/default.txt b/app/src/fdroid_full/play/release-notes/en-US/default.txt index 1fc5403..d48358c 100644 --- a/app/src/fdroid_full/play/release-notes/en-US/default.txt +++ b/app/src/fdroid_full/play/release-notes/en-US/default.txt @@ -2,11 +2,14 @@ Added: - Allow to search channels - Show storage quota - Warning on Playing NSFW videos +- Swipe to change timelines Changed: - Improve comment threads +- Comment composer in full-screen - Swipe to change timeline Fixed: - Status bar for fullscreen not removed +- Filter for subscriptions not working with remote accounts - Some crashes \ 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 85d85b5..634cbe8 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/AllPlaylistsActivity.java @@ -14,7 +14,12 @@ 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.pm.PackageManager; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -27,19 +32,19 @@ import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -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 androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; import java.util.ArrayList; import java.util.HashMap; @@ -54,11 +59,15 @@ import app.fedilab.fedilabtube.client.data.ChannelData; import app.fedilab.fedilabtube.client.data.PlaylistData.Playlist; import app.fedilab.fedilabtube.client.entities.Item; import app.fedilab.fedilabtube.client.entities.PlaylistParams; +import app.fedilab.fedilabtube.databinding.ActivityAllPlaylistBinding; +import app.fedilab.fedilabtube.databinding.AddPlaylistBinding; import app.fedilab.fedilabtube.drawer.PlaylistAdapter; +import app.fedilab.fedilabtube.helper.Helper; import app.fedilab.fedilabtube.viewmodel.ChannelsVM; import app.fedilab.fedilabtube.viewmodel.PlaylistsVM; import es.dmoral.toasty.Toasty; +import static app.fedilab.fedilabtube.PeertubeUploadActivity.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE; import static app.fedilab.fedilabtube.helper.Helper.peertubeInformation; @@ -66,40 +75,37 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA PlaylistAdapter playlistAdapter; - private RelativeLayout mainLoader; - private RelativeLayout textviewNoAction; private HashMap privacyToSend; - private Spinner set_upload_channel; - private Spinner set_upload_privacy; private String idChannel; private List playlists; private Playlist playlistToEdit; private List myChannels; private ChannelData.Channel selectedChannel; + private static final int PICK_AVATAR = 467; + private AddPlaylistBinding bindingDialog; + private Uri inputData; + private ActivityAllPlaylistBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_all_playlist); + binding = ActivityAllPlaylistBinding.inflate(getLayoutInflater()); + View viewRoot = binding.getRoot(); + setContentView(viewRoot); if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); setTitle(R.string.playlists); - textviewNoAction = findViewById(R.id.no_action); - mainLoader = findViewById(R.id.loader); - RelativeLayout nextElementLoader = findViewById(R.id.loading_next_items); - mainLoader.setVisibility(View.VISIBLE); - nextElementLoader.setVisibility(View.GONE); + binding.loader.setVisibility(View.VISIBLE); + binding.loadingNextItems.setVisibility(View.GONE); idChannel = null; PlaylistsVM viewModel = new ViewModelProvider(AllPlaylistsActivity.this).get(PlaylistsVM.class); viewModel.manage(PlaylistsVM.action.GET_PLAYLISTS, null, null).observe(AllPlaylistsActivity.this, apiResponse -> manageVIewPlaylists(PlaylistsVM.action.GET_PLAYLISTS, apiResponse)); - FloatingActionButton add_new = findViewById(R.id.add_new); - LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies()); if (privaciesInit.size() > 0) { @@ -110,13 +116,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA playlists = new ArrayList<>(); - RecyclerView lv_playlist = findViewById(R.id.lv_playlist); playlistAdapter = new PlaylistAdapter(playlists, false); playlistAdapter.allPlaylistRemoved = this; - lv_playlist.setAdapter(playlistAdapter); + binding.lvPlaylist.setAdapter(playlistAdapter); LinearLayoutManager mLayoutManager = new LinearLayoutManager(AllPlaylistsActivity.this); - lv_playlist.setLayoutManager(mLayoutManager); - add_new.setOnClickListener(view -> manageAlert(null)); + binding.lvPlaylist.setLayoutManager(mLayoutManager); + binding.addNew.setOnClickListener(view -> manageAlert(null)); } @Override @@ -135,7 +140,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA public void manageVIewPlaylists(PlaylistsVM.action actionType, APIResponse apiResponse) { - mainLoader.setVisibility(View.GONE); + binding.loader.setVisibility(View.GONE); if (apiResponse.getError() != null) { Toasty.error(AllPlaylistsActivity.this, apiResponse.getError().getError(), Toast.LENGTH_LONG).show(); return; @@ -144,9 +149,9 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA if (apiResponse.getPlaylists() != null && apiResponse.getPlaylists().size() > 0) { playlists.addAll(apiResponse.getPlaylists()); playlistAdapter.notifyDataSetChanged(); - textviewNoAction.setVisibility(View.GONE); + binding.noAction.setVisibility(View.GONE); } else { - textviewNoAction.setVisibility(View.VISIBLE); + binding.noAction.setVisibility(View.VISIBLE); } } } @@ -155,37 +160,53 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA playlistToEdit = playlistParam; AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AllPlaylistsActivity.this); - LayoutInflater inflater1 = getLayoutInflater(); - View dialogView = inflater1.inflate(R.layout.add_playlist, new LinearLayout(AllPlaylistsActivity.this), false); - dialogBuilder.setView(dialogView); - EditText display_name = dialogView.findViewById(R.id.display_name); - EditText description = dialogView.findViewById(R.id.description); - set_upload_channel = dialogView.findViewById(R.id.set_upload_channel); - set_upload_privacy = dialogView.findViewById(R.id.set_upload_privacy); + bindingDialog = AddPlaylistBinding.inflate(LayoutInflater.from(AllPlaylistsActivity.this), null, false); + dialogBuilder.setView(bindingDialog.getRoot()); + + dialogBuilder.setView(bindingDialog.getRoot()); + ChannelsVM viewModelC = new ViewModelProvider(AllPlaylistsActivity.this).get(ChannelsVM.class); viewModelC.get(RetrofitPeertubeAPI.DataType.MY_CHANNELS, null).observe(AllPlaylistsActivity.this, this::manageVIewChannels); - display_name.setFilters(new InputFilter[]{new InputFilter.LengthFilter(120)}); - description.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1000)}); + bindingDialog.displayName.setFilters(new InputFilter[]{new InputFilter.LengthFilter(120)}); + bindingDialog.description.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1000)}); if (playlistToEdit != null) { - display_name.setText(playlistToEdit.getDisplayName()); - description.setText(playlistToEdit.getDescription()); + bindingDialog.displayName.setText(playlistToEdit.getDisplayName()); + bindingDialog.description.setText(playlistToEdit.getDescription()); } dialogBuilder.setPositiveButton(R.string.validate, null); dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); AlertDialog alertDialog = dialogBuilder.create(); + + bindingDialog.selectFile.setOnClickListener(v -> { + if (ContextCompat.checkSelfPermission(AllPlaylistsActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != + PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(AllPlaylistsActivity.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("*/*"); + String[] mimetypes = {"image/*"}; + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes); + startActivityForResult(intent, PICK_AVATAR); + }); + Helper.loadGiF(AllPlaylistsActivity.this, playlistParam.getThumbnailPath(), bindingDialog.profilePicture); alertDialog.setOnShowListener(dialogInterface -> { Button button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); button.setOnClickListener(view -> { - if (display_name.getText() != null && display_name.getText().toString().trim().length() > 0) { + if (bindingDialog.displayName.getText() != null && bindingDialog.displayName.getText().toString().trim().length() > 0) { PlaylistParams playlistElement = new PlaylistParams(); - playlistElement.setDisplayName(display_name.getText().toString().trim()); - if (description.getText() != null && description.getText().toString().trim().length() > 0) { - playlistElement.setDescription(description.getText().toString().trim()); + playlistElement.setDisplayName(bindingDialog.displayName.getText().toString().trim()); + if (bindingDialog.description.getText() != null && bindingDialog.description.getText().toString().trim().length() > 0) { + playlistElement.setDescription(bindingDialog.description.getText().toString().trim()); } playlistElement.setVideoChannelId(idChannel); String label; @@ -203,11 +224,11 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA new Thread(() -> { String playlistId; if (playlistToEdit == null) { - APIResponse apiResponse = new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.CREATE_PLAYLIST, null, playlistElement, null); + APIResponse apiResponse = new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.CREATE_PLAYLIST, null, playlistElement, inputData); playlistId = apiResponse.getActionReturn(); } else { playlistId = playlistToEdit.getId(); - new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.UPDATE_PLAYLIST, playlistId, playlistElement, null); + new RetrofitPeertubeAPI(AllPlaylistsActivity.this).createOrUpdatePlaylist(PlaylistsVM.action.UPDATE_PLAYLIST, playlistId, playlistElement, inputData); } Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = () -> { @@ -247,7 +268,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA //Hide keyboard InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); assert imm != null; - imm.hideSoftInputFromWindow(display_name.getWindowToken(), 0); + imm.hideSoftInputFromWindow(bindingDialog.displayName.getWindowToken(), 0); }); if (alertDialog.getWindow() != null) alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); @@ -255,6 +276,24 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_AVATAR && resultCode == Activity.RESULT_OK) { + if (data == null || data.getData() == null) { + Toasty.error(AllPlaylistsActivity.this, getString(R.string.toot_select_image_error), Toast.LENGTH_LONG).show(); + return; + } + inputData = data.getData(); + Glide.with(AllPlaylistsActivity.this) + .load(inputData) + .thumbnail(0.1f) + .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners(10))) + .into(bindingDialog.profilePicture); + + } + } + public void manageVIewChannels(APIResponse apiResponse) { if (apiResponse.getError() != null || apiResponse.getChannels() == null || apiResponse.getChannels().size() == 0) { if (apiResponse.getError() != null && apiResponse.getError().getError() != null) @@ -280,7 +319,7 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA ArrayAdapter adapterChannel = new ArrayAdapter<>(AllPlaylistsActivity.this, android.R.layout.simple_spinner_dropdown_item, channelName); - set_upload_channel.setAdapter(adapterChannel); + bindingDialog.setUploadChannel.setAdapter(adapterChannel); LinkedHashMap translations = null; @@ -308,19 +347,19 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA ArrayAdapter adapterPrivacies = new ArrayAdapter<>(AllPlaylistsActivity.this, android.R.layout.simple_spinner_dropdown_item, privaciesA); - set_upload_privacy.setAdapter(adapterPrivacies); + bindingDialog.setUploadPrivacy.setAdapter(adapterPrivacies); if (playlistToEdit != null) { Item privacy = playlistToEdit.getPrivacy(); if (privacy.getId() > 0) { - set_upload_privacy.setSelection(privacy.getId() - 1); + bindingDialog.setUploadPrivacy.setSelection(privacy.getId() - 1); } } else { - set_upload_privacy.setSelection(2); + bindingDialog.setUploadPrivacy.setSelection(2); } //Manage privacies - set_upload_privacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + bindingDialog.setUploadPrivacy.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { LinkedHashMap privaciesCheck = new LinkedHashMap<>(peertubeInformation.getPrivacies()); @@ -348,12 +387,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA Item privacy = playlistToEdit.getPrivacy(); if (privacy.getId() > 0) { - set_upload_privacy.setSelection(privacy.getId() - 1); + bindingDialog.setUploadPrivacy.setSelection(privacy.getId() - 1); } } //Manage languages - set_upload_channel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + bindingDialog.setUploadChannel.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { idChannel = channelId[position]; @@ -378,12 +417,12 @@ public class AllPlaylistsActivity extends AppCompatActivity implements PlaylistA } k++; } - set_upload_channel.setSelection(position); + bindingDialog.setUploadChannel.setSelection(position); } } @Override public void onAllPlaylistRemoved() { - textviewNoAction.setVisibility(View.VISIBLE); + binding.noAction.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java index 872504f..86c6c95 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/MainActivity.java @@ -398,7 +398,6 @@ public class MainActivity extends AppCompatActivity { }).start(); } - @Override public boolean onCreateOptionsMenu(@NotNull Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java index fc54476..c7495b2 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java @@ -31,7 +31,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -1446,21 +1445,31 @@ public class RetrofitPeertubeAPI { * @param playlistParams PlaylistParams * @return APIResponse */ - public APIResponse createOrUpdatePlaylist(PlaylistsVM.action apiAction, String playlistId, PlaylistParams playlistParams, File thumbnail) { + public APIResponse createOrUpdatePlaylist(PlaylistsVM.action apiAction, String playlistId, PlaylistParams playlistParams, Uri thumbnail) { PeertubeService peertubeService = init(); APIResponse apiResponse = new APIResponse(); MultipartBody.Part body = null; + + MultipartBody.Part bodyThumbnail = null; if (thumbnail != null) { - RequestBody requestFile = RequestBody.create(thumbnail, MediaType.parse("multipart/form-data")); - body = MultipartBody.Part.createFormData("image", thumbnail.getName(), requestFile); + DocumentFile documentFile = DocumentFile.fromSingleUri(_context, thumbnail); + String avatarfileName = null; + if (documentFile != null) { + avatarfileName = documentFile.getName(); + } + try { + bodyThumbnail = createFile("thumbnailfile", thumbnail, avatarfileName); + } catch (IOException e) { + e.printStackTrace(); + } } try { RequestBody displayName = RequestBody.create(playlistParams.getDisplayName(), MediaType.parse("text/plain")); RequestBody description = RequestBody.create(playlistParams.getDescription(), MediaType.parse("text/plain")); RequestBody channelId = RequestBody.create(playlistParams.getVideoChannelId(), MediaType.parse("text/plain")); if (apiAction == PlaylistsVM.action.CREATE_PLAYLIST) { - Call stringCall = peertubeService.addPlaylist(getToken(), displayName, description, playlistParams.getPrivacy(), channelId, body); + Call stringCall = peertubeService.addPlaylist(getToken(), displayName, description, playlistParams.getPrivacy(), channelId, bodyThumbnail); Response response = stringCall.execute(); if (response.isSuccessful() && response.body() != null) { apiResponse.setActionReturn(response.body().getVideoPlaylist().getId()); @@ -1469,7 +1478,7 @@ public class RetrofitPeertubeAPI { } } else if (apiAction == PlaylistsVM.action.UPDATE_PLAYLIST) { - Call stringCall = peertubeService.updatePlaylist(getToken(), playlistId, displayName, description, playlistParams.getPrivacy(), channelId, body); + Call stringCall = peertubeService.updatePlaylist(getToken(), playlistId, displayName, description, playlistParams.getPrivacy(), channelId, bodyThumbnail); Response response = stringCall.execute(); if (response.isSuccessful()) { apiResponse.setActionReturn(response.body()); diff --git a/app/src/main/res/layout/add_playlist.xml b/app/src/main/res/layout/add_playlist.xml index 7a6a912..159e933 100644 --- a/app/src/main/res/layout/add_playlist.xml +++ b/app/src/main/res/layout/add_playlist.xml @@ -20,6 +20,30 @@ android:orientation="vertical" android:padding="15dp"> + + + + +