Playlist UI WIP

This commit is contained in:
digiwizkid 2022-01-08 15:26:48 +05:30
parent c7893ddd38
commit 96ec510f40
7 changed files with 470 additions and 201 deletions

View File

@ -3,9 +3,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="net.schueller.peertube"> package="net.schueller.peertube">
<!-- required to play video in background via notification --> <!-- required to play video in background via notification -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- connect to peertube server --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <!-- connect to peertube server -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- required for torrent downloading --> <uses-permission android:name="android.permission.INTERNET"/> <!-- required for torrent downloading -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application <application
android:name=".application.AppApplication" android:name=".application.AppApplication"
@ -21,22 +21,22 @@
<activity <activity
android:name=".activity.ServerAddressBookActivity" android:name=".activity.ServerAddressBookActivity"
android:label="@string/title_activity_server_address_book" android:label="@string/title_activity_server_address_book"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Video Lists --> android:theme="@style/AppTheme.NoActionBar"/> <!-- Video Lists -->
<activity <activity
android:name=".activity.VideoListActivity" android:name=".activity.VideoListActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/AppTheme.NoActionBar" android:theme="@style/AppTheme.NoActionBar"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.SEARCH" /> <action android:name="android.intent.action.SEARCH"/>
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.searchable" android:name="android.app.searchable"
android:resource="@xml/searchable" /> android:resource="@xml/searchable"/>
</activity> <!-- Video Player --> </activity> <!-- Video Player -->
<activity <activity
android:name=".activity.VideoPlayActivity" android:name=".activity.VideoPlayActivity"
@ -44,35 +44,40 @@
android:label="@string/title_activity_video_play" android:label="@string/title_activity_video_play"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:supportsPictureInPicture="true" android:supportsPictureInPicture="true"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Settings --> android:theme="@style/AppTheme.NoActionBar"/>
<!-- Playlist -->
<activity android:name=".activity.PlaylistActivity"
android:label="Playlist"
android:theme="@style/AppTheme.NoActionBar"/>
<!-- Settings -->
<activity <activity
android:name=".activity.SettingsActivity" android:name=".activity.SettingsActivity"
android:label="@string/title_activity_settings" android:label="@string/title_activity_settings"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Server Selection --> android:theme="@style/AppTheme.NoActionBar"/> <!-- Server Selection -->
<activity <activity
android:name=".activity.SearchServerActivity" android:name=".activity.SearchServerActivity"
android:label="@string/title_activity_select_server" android:label="@string/title_activity_select_server"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Me --> android:theme="@style/AppTheme.NoActionBar"/> <!-- Me -->
<activity <activity
android:name=".activity.MeActivity" android:name=".activity.MeActivity"
android:label="@string/title_activity_me" android:label="@string/title_activity_me"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Account --> android:theme="@style/AppTheme.NoActionBar"/> <!-- Account -->
<activity <activity
android:name=".activity.AccountActivity" android:name=".activity.AccountActivity"
android:label="@string/title_activity_account" android:label="@string/title_activity_account"
android:theme="@style/AppTheme.NoActionBar" /> <!-- Content provider for search suggestions --> android:theme="@style/AppTheme.NoActionBar"/> <!-- Content provider for search suggestions -->
<provider <provider
android:name=".provider.SearchSuggestionsProvider" android:name=".provider.SearchSuggestionsProvider"
android:authorities="net.schueller.peertube.provider.SearchSuggestionsProvider" android:authorities="net.schueller.peertube.provider.SearchSuggestionsProvider"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false"/>
<service android:name=".service.VideoPlayerService" /> <service android:name=".service.VideoPlayerService"/>
<receiver android:name="androidx.media.session.MediaButtonReceiver" <receiver android:name="androidx.media.session.MediaButtonReceiver"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" /> <action android:name="android.intent.action.MEDIA_BUTTON"/>
</intent-filter> </intent-filter>
</receiver> </receiver>

View File

@ -27,7 +27,9 @@ import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import com.squareup.picasso.Picasso;
import net.schueller.peertube.R; import net.schueller.peertube.R;
import net.schueller.peertube.helper.APIUrlHelper; import net.schueller.peertube.helper.APIUrlHelper;
import net.schueller.peertube.helper.ErrorHelper; import net.schueller.peertube.helper.ErrorHelper;
@ -36,18 +38,12 @@ import net.schueller.peertube.model.Me;
import net.schueller.peertube.network.GetUserService; import net.schueller.peertube.network.GetUserService;
import net.schueller.peertube.network.RetrofitInstance; import net.schueller.peertube.network.RetrofitInstance;
import net.schueller.peertube.network.Session; import net.schueller.peertube.network.Session;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import com.squareup.picasso.Picasso;
import java.util.Objects;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
import java.util.Objects;
import static net.schueller.peertube.application.AppApplication.getContext; import static net.schueller.peertube.application.AppApplication.getContext;
public class MeActivity extends CommonActivity { public class MeActivity extends CommonActivity {
@ -85,11 +81,16 @@ public class MeActivity extends CommonActivity {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_close_24); getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_baseline_close_24);
LinearLayout account = findViewById(R.id.a_me_account_line); LinearLayout account = findViewById(R.id.a_me_account_line);
LinearLayout playlist = findViewById(R.id.a_me_playlist);
LinearLayout settings = findViewById(R.id.a_me_settings); LinearLayout settings = findViewById(R.id.a_me_settings);
LinearLayout help = findViewById(R.id.a_me_helpnfeedback); LinearLayout help = findViewById(R.id.a_me_helpnfeedback);
TextView logout = findViewById(R.id.a_me_logout); TextView logout = findViewById(R.id.a_me_logout);
playlist.setOnClickListener(view -> {
Intent playlistActivity = new Intent(getContext(), PlaylistActivity.class);
startActivity(playlistActivity);
});
settings.setOnClickListener(view -> { settings.setOnClickListener(view -> {
Intent settingsActivity = new Intent(getContext(), SettingsActivity.class); Intent settingsActivity = new Intent(getContext(), SettingsActivity.class);
@ -124,7 +125,7 @@ public class MeActivity extends CommonActivity {
call.enqueue(new Callback<Me>() { call.enqueue(new Callback<Me>() {
LinearLayout account = findViewById(R.id.a_me_account_line); final LinearLayout account = findViewById(R.id.a_me_account_line);
@Override @Override
public void onResponse(@NonNull Call<Me> call, @NonNull Response<Me> response) { public void onResponse(@NonNull Call<Me> call, @NonNull Response<Me> response) {
@ -162,7 +163,7 @@ public class MeActivity extends CommonActivity {
@Override @Override
public void onFailure(@NonNull Call<Me> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<Me> call, @NonNull Throwable t) {
ErrorHelper.showToastFromCommunicationError( MeActivity.this, t ); ErrorHelper.showToastFromCommunicationError(MeActivity.this, t);
account.setVisibility(View.GONE); account.setVisibility(View.GONE);
} }
}); });

View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.schueller.peertube.activity
import android.app.AlertDialog
import android.content.DialogInterface
import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import net.schueller.peertube.R
import net.schueller.peertube.adapter.PlaylistAdapter
import net.schueller.peertube.database.Video
import net.schueller.peertube.database.VideoViewModel
import net.schueller.peertube.databinding.ActivityPlaylistBinding
class PlaylistActivity : CommonActivity() {
private val TAG = "PlaylistAct"
private val mVideoViewModel: VideoViewModel by viewModels()
private lateinit var mBinding: ActivityPlaylistBinding
override fun onSupportNavigateUp(): Boolean {
finish() // close this activity as oppose to navigating up
return false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityPlaylistBinding.inflate(layoutInflater)
setContentView(mBinding.root)
// Setting toolbar as the ActionBar with setSupportActionBar() call
setSupportActionBar(mBinding.toolBarServerAddressBook)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.ic_baseline_close_24)
}
showServers()
}
private fun onVideoClick(video: Video) {
Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show()
}
private fun showServers() {
val adapter = PlaylistAdapter(mutableListOf(), { onVideoClick(it) }).also {
mBinding.serverListRecyclerview.adapter = it
}
// Delete items on swipe
val helper = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
AlertDialog.Builder(this@PlaylistActivity)
.setTitle("Remove Video")
.setMessage("Are you sure you want to remove this video from playlist?")
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
val position = viewHolder.bindingAdapterPosition
val video = adapter.getVideoAtPosition(position)
// Delete the video
mVideoViewModel.delete(video)
}
.setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int -> adapter.notifyItemChanged(viewHolder.bindingAdapterPosition) }
.setIcon(android.R.drawable.ic_dialog_alert)
.show()
}
})
helper.attachToRecyclerView(mBinding.serverListRecyclerview)
// Update the cached copy of the words in the adapter.
mVideoViewModel.allVideos.observe(this, { videos: List<Video> ->
adapter.setVideos(videos)
})
}
companion object
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.schueller.peertube.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import net.schueller.peertube.database.Video
import net.schueller.peertube.databinding.RowPlaylistBinding
class PlaylistAdapter(private val mVideos: MutableList<Video>, private val onClick: (Video) -> Unit) : RecyclerView.Adapter<PlaylistAdapter.VideoViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoViewHolder {
val binding = RowPlaylistBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return VideoViewHolder(binding)
}
override fun onBindViewHolder(holder: VideoViewHolder, position: Int) {
holder.bind(mVideos[position])
}
fun setVideos(videos: List<Video>) {
mVideos.clear()
mVideos.addAll(videos)
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return mVideos.size
}
inner class VideoViewHolder(private val binding: RowPlaylistBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(video: Video) {
binding.videoName.text = video.videoName
binding.videoDescription.text = video.videoDescription
binding.root.setOnClickListener { onClick(video) }
}
}
fun getVideoAtPosition(position: Int): Video {
return mVideos[position]
}
}

View File

@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".activity.MeActivity" tools:context=".activity.MeActivity"
android:orientation="vertical"> android:orientation="vertical">
@ -17,13 +16,12 @@
android:id="@+id/tool_bar_me" android:id="@+id/tool_bar_me"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:elevation="4dp" /> android:elevation="4dp"/>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -72,7 +70,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="" android:text=""
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"/>
<TextView <TextView
android:id="@+id/a_me_email" android:id="@+id/a_me_email"
@ -80,7 +78,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="" android:text=""
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"/>
<TextView <TextView
android:drawablePadding="16dp" android:drawablePadding="16dp"
@ -88,7 +86,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/me_logout_button" android:text="@string/me_logout_button"
android:id="@+id/a_me_logout" android:id="@+id/a_me_logout"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"/>
</LinearLayout> </LinearLayout>
@ -101,8 +99,26 @@
android:layout_height="1dp" android:layout_height="1dp"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:background="@android:color/darker_gray" /> android:background="@android:color/darker_gray"/>
<LinearLayout
android:id="@+id/a_me_playlist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:orientation="horizontal">
<TextView
android:drawableStart="@drawable/ic_baseline_settings_24"
android:drawablePadding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Playlist"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"/>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/a_me_settings" android:id="@+id/a_me_settings"
@ -120,7 +136,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/title_activity_settings" android:text="@string/title_activity_settings"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"/>
</LinearLayout> </LinearLayout>
@ -140,36 +156,33 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/me_help_and_feedback_button" android:text="@string/me_help_and_feedback_button"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
<!-- <LinearLayout-->
<!-- android:layout_marginBottom="0dp"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:orientation="vertical">-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/account_username"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="" />-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- <LinearLayout--> <!-- android:id="@+id/account_email"-->
<!-- android:layout_marginBottom="0dp"--> <!-- android:layout_width="match_parent"-->
<!-- android:layout_width="match_parent"--> <!-- android:layout_height="wrap_content"-->
<!-- android:layout_height="wrap_content"--> <!-- android:text="" />-->
<!-- android:orientation="vertical">--> <!-- </LinearLayout>-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/account_username"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="" />-->
<!-- <androidx.appcompat.widget.AppCompatTextView-->
<!-- android:id="@+id/account_email"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="" />-->
<!-- </LinearLayout>-->
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.ServerAddressBookActivity"
android:id="@+id/server_book">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_server_address_book"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tool_bar_server_address_book"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
android:elevation="4dp"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/server_list_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
tools:listitem="@layout/row_playlist"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="0dp"
card_view:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:padding="12dp">
<TextView
android:id="@+id/video_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:layout_constraintTop_toTopOf="parent"
card_view:layout_constraintStart_toStartOf="parent"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"
tools:text="@tools:sample/lorem"
/>
<TextView
android:id="@+id/video_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:ellipsize="end"
card_view:layout_constraintTop_toBottomOf="@id/video_name"
card_view:layout_constraintStart_toStartOf="parent"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead"
tools:text="@tools:sample/lorem"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>