Add to playlist feature initial commit
This commit is contained in:
parent
4b1efade40
commit
c7893ddd38
@ -30,28 +30,26 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.gson.JsonObject
|
||||
import com.mikepenz.iconics.Iconics.Builder
|
||||
import com.squareup.picasso.Picasso
|
||||
import net.schueller.peertube.R.color
|
||||
import net.schueller.peertube.R.string
|
||||
import net.schueller.peertube.R
|
||||
import net.schueller.peertube.R.*
|
||||
import net.schueller.peertube.activity.AccountActivity
|
||||
import net.schueller.peertube.activity.VideoListActivity
|
||||
import net.schueller.peertube.activity.VideoPlayActivity
|
||||
import net.schueller.peertube.databinding.*
|
||||
import net.schueller.peertube.fragment.VideoMetaDataFragment
|
||||
import net.schueller.peertube.helper.APIUrlHelper
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getCreatorAvatar
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getCreatorString
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getDuration
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getMetaString
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getOwnerString
|
||||
import com.mikepenz.iconics.Iconics.Builder
|
||||
import net.schueller.peertube.R
|
||||
import net.schueller.peertube.R.id
|
||||
import net.schueller.peertube.R.menu
|
||||
import net.schueller.peertube.databinding.*
|
||||
import net.schueller.peertube.fragment.VideoMetaDataFragment
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getCreatorAvatar
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getCreatorString
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getTagsString
|
||||
import net.schueller.peertube.helper.MetaDataHelper.isChannel
|
||||
import net.schueller.peertube.intents.Intents
|
||||
import net.schueller.peertube.model.*
|
||||
import net.schueller.peertube.model.ui.VideoMetaViewItem
|
||||
import net.schueller.peertube.network.GetUserService
|
||||
import net.schueller.peertube.network.GetVideoDataService
|
||||
import net.schueller.peertube.network.RetrofitInstance
|
||||
import net.schueller.peertube.network.Session
|
||||
@ -61,8 +59,6 @@ import okhttp3.ResponseBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import net.schueller.peertube.helper.MetaDataHelper.isChannel
|
||||
import net.schueller.peertube.network.GetUserService
|
||||
|
||||
|
||||
sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
@ -70,13 +66,13 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
var videoRating: Rating? = null
|
||||
var isLeaveAppExpected = false
|
||||
|
||||
class CategoryViewHolder(private val binding: ItemCategoryTitleBinding): MultiViewRecyclerViewHolder(binding) {
|
||||
class CategoryViewHolder(private val binding: ItemCategoryTitleBinding) : MultiViewRecyclerViewHolder(binding) {
|
||||
fun bind(category: Category) {
|
||||
binding.textViewTitle.text = category.label
|
||||
}
|
||||
}
|
||||
|
||||
class VideoCommentsViewHolder(private val binding: ItemVideoCommentsOverviewBinding): MultiViewRecyclerViewHolder(binding) {
|
||||
class VideoCommentsViewHolder(private val binding: ItemVideoCommentsOverviewBinding) : MultiViewRecyclerViewHolder(binding) {
|
||||
fun bind(commentThread: CommentThread) {
|
||||
|
||||
binding.videoCommentsTotalCount.text = commentThread.total.toString()
|
||||
@ -99,7 +95,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
}
|
||||
|
||||
|
||||
class VideoMetaViewHolder(private val binding: ItemVideoMetaBinding, private val videoMetaDataFragment: VideoMetaDataFragment?): MultiViewRecyclerViewHolder(binding) {
|
||||
class VideoMetaViewHolder(private val binding: ItemVideoMetaBinding, private val videoMetaDataFragment: VideoMetaDataFragment?) : MultiViewRecyclerViewHolder(binding) {
|
||||
fun bind(videoMetaViewItem: VideoMetaViewItem) {
|
||||
|
||||
val video = videoMetaViewItem.video
|
||||
@ -137,12 +133,10 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
rateVideo(false, video, context, binding)
|
||||
}
|
||||
|
||||
// Add to playlist
|
||||
binding.videoAddToPlaylistWrapper.setOnClickListener {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(string.video_feature_not_yet_implemented),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
videoMetaDataFragment.saveToPlaylist(video)
|
||||
Toast.makeText(context, "Saved to playlist", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
binding.videoBlockWrapper.setOnClickListener {
|
||||
@ -243,7 +237,6 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get subscription status
|
||||
var isSubscribed = false
|
||||
|
||||
@ -262,6 +255,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<JsonObject>, t: Throwable) {
|
||||
// Do nothing.
|
||||
}
|
||||
@ -286,6 +280,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
isSubscribed = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
|
||||
// Do nothing.
|
||||
}
|
||||
@ -308,6 +303,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
isSubscribed = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
|
||||
// Do nothing.
|
||||
}
|
||||
@ -333,7 +329,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelViewHolder(private val binding: ItemChannelTitleBinding): MultiViewRecyclerViewHolder(binding) {
|
||||
class ChannelViewHolder(private val binding: ItemChannelTitleBinding) : MultiViewRecyclerViewHolder(binding) {
|
||||
fun bind(channel: Channel) {
|
||||
|
||||
val context = binding.avatar.context
|
||||
@ -353,13 +349,13 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
|
||||
}
|
||||
}
|
||||
|
||||
class TagViewHolder(private val binding: ItemTagTitleBinding): MultiViewRecyclerViewHolder(binding) {
|
||||
class TagViewHolder(private val binding: ItemTagTitleBinding) : MultiViewRecyclerViewHolder(binding) {
|
||||
fun bind(tag: TagVideo) {
|
||||
binding.textViewTitle.text = tag.tag
|
||||
}
|
||||
}
|
||||
|
||||
class VideoViewHolder(private val binding: RowVideoListBinding): MultiViewRecyclerViewHolder(binding) {
|
||||
class VideoViewHolder(private val binding: RowVideoListBinding) : MultiViewRecyclerViewHolder(binding) {
|
||||
|
||||
fun bind(video: Video) {
|
||||
|
||||
|
@ -19,7 +19,9 @@ package net.schueller.peertube.database;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(entities = {Server.class}, version = 1)
|
||||
@Database(entities = {Server.class, Video.class}, version = 1)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
public abstract ServerDao serverDao();
|
||||
|
||||
public abstract VideoDao videoDao();
|
||||
}
|
21
app/src/main/java/net/schueller/peertube/database/Video.kt
Normal file
21
app/src/main/java/net/schueller/peertube/database/Video.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package net.schueller.peertube.database
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@Entity(tableName = "watch_later")
|
||||
data class Video(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Int = 0,
|
||||
|
||||
@ColumnInfo(name = "video_name")
|
||||
var videoName: String,
|
||||
|
||||
@ColumnInfo(name = "video_description")
|
||||
var videoDescription: String?
|
||||
|
||||
) : Parcelable
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.database
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
|
||||
@Dao
|
||||
interface VideoDao {
|
||||
|
||||
@Insert
|
||||
suspend fun insert(video: Video)
|
||||
|
||||
@Update
|
||||
suspend fun update(video: Video)
|
||||
|
||||
@Query("DELETE FROM watch_later")
|
||||
suspend fun deleteAll()
|
||||
|
||||
@Delete
|
||||
suspend fun delete(video: Video)
|
||||
|
||||
@get:Query("SELECT * from watch_later ORDER BY video_name DESC")
|
||||
val allVideos: LiveData<List<Video>>
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.database
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.LiveData
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class VideoRepository(application: Application) {
|
||||
|
||||
private val mVideoDao: VideoDao
|
||||
|
||||
val allVideos: LiveData<List<Video>>
|
||||
get() = mVideoDao.allVideos
|
||||
|
||||
init {
|
||||
val db = VideoRoomDatabase.getDatabase(application)
|
||||
mVideoDao = db.videoDao()
|
||||
}
|
||||
|
||||
suspend fun update(video: Video) = withContext(Dispatchers.IO) {
|
||||
mVideoDao.update(video)
|
||||
}
|
||||
|
||||
suspend fun insert(video: Video) = withContext(Dispatchers.IO) {
|
||||
mVideoDao.insert(video)
|
||||
}
|
||||
|
||||
suspend fun delete(video: Video) = withContext(Dispatchers.IO) {
|
||||
mVideoDao.delete(video)
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.database;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Database(entities = {Video.class}, version = 1, exportSchema = false)
|
||||
public abstract class VideoRoomDatabase extends RoomDatabase {
|
||||
|
||||
public abstract VideoDao videoDao();
|
||||
|
||||
private static volatile VideoRoomDatabase INSTANCE;
|
||||
|
||||
private static final int NUMBER_OF_THREADS = 4;
|
||||
|
||||
static final ExecutorService databaseWriteExecutor =
|
||||
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
|
||||
|
||||
public static VideoRoomDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (VideoRoomDatabase.class) {
|
||||
if (INSTANCE == null) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
VideoRoomDatabase.class, "playlist_database")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.database
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class VideoViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private val mRepository: VideoRepository = VideoRepository(application)
|
||||
val allVideos: LiveData<List<Video>> = mRepository.allVideos
|
||||
|
||||
fun insert(video: Video) {
|
||||
viewModelScope.launch {
|
||||
mRepository.insert(video)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(video: Video) {
|
||||
viewModelScope.launch {
|
||||
mRepository.update(video)
|
||||
}
|
||||
}
|
||||
|
||||
fun delete(video: Video) {
|
||||
viewModelScope.launch {
|
||||
mRepository.delete(video)
|
||||
}
|
||||
}
|
||||
}
|
@ -16,54 +16,36 @@
|
||||
*/
|
||||
package net.schueller.peertube.fragment
|
||||
|
||||
import android.Manifest
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getMetaString
|
||||
import net.schueller.peertube.helper.MetaDataHelper.getOwnerString
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.os.Bundle
|
||||
import net.schueller.peertube.R
|
||||
import net.schueller.peertube.service.VideoPlayerService
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import net.schueller.peertube.helper.APIUrlHelper
|
||||
import net.schueller.peertube.network.GetVideoDataService
|
||||
import net.schueller.peertube.network.RetrofitInstance
|
||||
import net.schueller.peertube.helper.ErrorHelper
|
||||
import androidx.core.app.ActivityCompat
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.squareup.picasso.Picasso
|
||||
import android.widget.TextView
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.mikepenz.iconics.Iconics
|
||||
import net.schueller.peertube.R
|
||||
import net.schueller.peertube.adapter.MultiViewRecycleViewAdapter
|
||||
import net.schueller.peertube.intents.Intents
|
||||
import net.schueller.peertube.database.VideoViewModel
|
||||
import net.schueller.peertube.helper.APIUrlHelper
|
||||
import net.schueller.peertube.helper.ErrorHelper
|
||||
import net.schueller.peertube.model.CommentThread
|
||||
import net.schueller.peertube.model.Rating
|
||||
import net.schueller.peertube.model.Video
|
||||
import net.schueller.peertube.model.VideoList
|
||||
import net.schueller.peertube.model.ui.VideoMetaViewItem
|
||||
import net.schueller.peertube.network.GetUserService
|
||||
import net.schueller.peertube.network.Session
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import net.schueller.peertube.network.GetVideoDataService
|
||||
import net.schueller.peertube.network.RetrofitInstance
|
||||
import net.schueller.peertube.service.VideoPlayerService
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import java.lang.Exception
|
||||
|
||||
class VideoMetaDataFragment : Fragment() {
|
||||
private var videoRating: Rating? = null
|
||||
@ -73,6 +55,8 @@ class VideoMetaDataFragment : Fragment() {
|
||||
|
||||
private lateinit var videoDescriptionFragment: VideoDescriptionFragment
|
||||
|
||||
private val mVideoViewModel: VideoViewModel by activityViewModels()
|
||||
|
||||
var isLeaveAppExpected = false
|
||||
private set
|
||||
|
||||
@ -176,7 +160,7 @@ class VideoMetaDataFragment : Fragment() {
|
||||
if (response.body() != null) {
|
||||
val commentThread = response.body()
|
||||
if (commentThread != null) {
|
||||
mMultiViewAdapter!!.setVideoComment(commentThread);
|
||||
mMultiViewAdapter!!.setVideoComment(commentThread)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -234,6 +218,12 @@ class VideoMetaDataFragment : Fragment() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun saveToPlaylist(video: Video) {
|
||||
val playlistVideo: net.schueller.peertube.database.Video = net.schueller.peertube.database.Video(videoName = video.name, videoDescription = video.description)
|
||||
mVideoViewModel.insert(playlistVideo)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "VMDF"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user