From c7893ddd389873d85fa798bde13e2f7c9d7ebf8b Mon Sep 17 00:00:00 2001 From: digiwizkid Date: Sat, 8 Jan 2022 13:18:41 +0530 Subject: [PATCH] Add to playlist feature initial commit --- .../adapter/MultiViewRecyclerViewHolder.kt | 196 +++++++++--------- .../peertube/database/AppDatabase.java | 4 +- .../net/schueller/peertube/database/Video.kt | 21 ++ .../schueller/peertube/database/VideoDao.kt | 39 ++++ .../peertube/database/VideoRepository.kt | 47 +++++ .../peertube/database/VideoRoomDatabase.java | 54 +++++ .../peertube/database/VideoViewModel.kt | 47 +++++ .../fragment/VideoMetaDataFragment.kt | 88 ++++---- 8 files changed, 346 insertions(+), 150 deletions(-) create mode 100644 app/src/main/java/net/schueller/peertube/database/Video.kt create mode 100644 app/src/main/java/net/schueller/peertube/database/VideoDao.kt create mode 100644 app/src/main/java/net/schueller/peertube/database/VideoRepository.kt create mode 100644 app/src/main/java/net/schueller/peertube/database/VideoRoomDatabase.java create mode 100644 app/src/main/java/net/schueller/peertube/database/VideoViewModel.kt diff --git a/app/src/main/java/net/schueller/peertube/adapter/MultiViewRecyclerViewHolder.kt b/app/src/main/java/net/schueller/peertube/adapter/MultiViewRecyclerViewHolder.kt index 80d1699..af85876 100644 --- a/app/src/main/java/net/schueller/peertube/adapter/MultiViewRecyclerViewHolder.kt +++ b/app/src/main/java/net/schueller/peertube/adapter/MultiViewRecyclerViewHolder.kt @@ -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() @@ -90,8 +86,8 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi val baseUrl = APIUrlHelper.getUrl(binding.videoHighlightedAvatar.context) val avatarPath = avatar.path Picasso.get() - .load(baseUrl + avatarPath) - .into(binding.videoHighlightedAvatar) + .load(baseUrl + avatarPath) + .into(binding.videoHighlightedAvatar) } binding.videoHighlightedComment.text = highlightedComment.text } @@ -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 @@ -109,16 +105,16 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi val context = binding.avatar.context val apiBaseURL = APIUrlHelper.getUrlWithVersion(context) val videoDataService = RetrofitInstance.getRetrofitInstance( - apiBaseURL, - APIUrlHelper.useInsecureConnection(context) + apiBaseURL, + APIUrlHelper.useInsecureConnection(context) ).create( - GetVideoDataService::class.java + GetVideoDataService::class.java ) val userService = RetrofitInstance.getRetrofitInstance( - apiBaseURL, - APIUrlHelper.useInsecureConnection(context) + apiBaseURL, + APIUrlHelper.useInsecureConnection(context) ).create( - GetUserService::class.java + GetUserService::class.java ) // Title @@ -137,27 +133,25 @@ 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 { Toast.makeText( - context, - context.getString(string.video_feature_not_yet_implemented), - Toast.LENGTH_SHORT + context, + context.getString(string.video_feature_not_yet_implemented), + Toast.LENGTH_SHORT ).show() } binding.videoFlagWrapper.setOnClickListener { Toast.makeText( - context, - context.getString(string.video_feature_not_yet_implemented), - Toast.LENGTH_SHORT + context, + context.getString(string.video_feature_not_yet_implemented), + Toast.LENGTH_SHORT ).show() } @@ -198,10 +192,10 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi // created at / views binding.videoMeta.text = getMetaString( - video.createdAt, - video.views, - context, - true + video.createdAt, + video.views, + context, + true ) // owner / creator @@ -220,8 +214,8 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi val baseUrl = APIUrlHelper.getUrl(context) val avatarPath = avatar.path Picasso.get() - .load(baseUrl + avatarPath) - .into(binding.avatar) + .load(baseUrl + avatarPath) + .into(binding.avatar) } // videoOwnerSubscribers @@ -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, t: Throwable) { // Do nothing. } @@ -278,52 +272,54 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi val call = userService.subscribe(body) call.enqueue(object : Callback { override fun onResponse( - call: Call, - response: Response + call: Call, + response: Response ) { if (response.isSuccessful) { binding.videoOwnerSubscribeButton.setText(string.unsubscribe) isSubscribed = true } } + override fun onFailure(call: Call, t: Throwable) { // Do nothing. } }) } else { AlertDialog.Builder(context) - .setTitle(context.getString(string.video_sub_del_alert_title)) - .setMessage(context.getString(string.video_sub_del_alert_msg)) - .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> - // Yes - val payload = video.channel.name + "@" + video.channel.host - val call = userService.unsubscribe(payload) - call.enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - binding.videoOwnerSubscribeButton.setText(string.subscribe) - isSubscribed = false + .setTitle(context.getString(string.video_sub_del_alert_title)) + .setMessage(context.getString(string.video_sub_del_alert_msg)) + .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> + // Yes + val payload = video.channel.name + "@" + video.channel.host + val call = userService.unsubscribe(payload) + call.enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + binding.videoOwnerSubscribeButton.setText(string.subscribe) + isSubscribed = false + } } - } - override fun onFailure(call: Call, t: Throwable) { - // Do nothing. - } - }) - } - .setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int -> - // No - } - .setIcon(android.R.drawable.ic_dialog_alert) - .show() + + override fun onFailure(call: Call, t: Throwable) { + // Do nothing. + } + }) + } + .setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int -> + // No + } + .setIcon(android.R.drawable.ic_dialog_alert) + .show() } } else { Toast.makeText( - context, - context.getString(string.video_login_required_for_service), - Toast.LENGTH_SHORT + context, + context.getString(string.video_login_required_for_service), + Toast.LENGTH_SHORT ).show() } } @@ -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 @@ -344,22 +340,22 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi if (avatar != null) { val avatarPath = avatar.path Picasso.get() - .load(baseUrl + avatarPath) - .placeholder(R.drawable.test_image) - .into(binding.avatar) + .load(baseUrl + avatarPath) + .placeholder(R.drawable.test_image) + .into(binding.avatar) } binding.textViewTitle.text = channel.displayName } } - 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) { @@ -368,18 +364,18 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi // Temp Loading Image Picasso.get() - .load(baseUrl + video.previewPath) - .placeholder(R.drawable.test_image) - .error(R.drawable.test_image) - .into(binding.thumb) + .load(baseUrl + video.previewPath) + .placeholder(R.drawable.test_image) + .error(R.drawable.test_image) + .into(binding.thumb) // Avatar val avatar = getCreatorAvatar(video, context) if (avatar != null) { val avatarPath = avatar.path Picasso.get() - .load(baseUrl + avatarPath) - .into(binding.avatar) + .load(baseUrl + avatarPath) + .into(binding.avatar) } // set Name binding.slRowName.text = video.name @@ -395,9 +391,9 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi // set age and view count binding.videoMeta.text = getMetaString( - video.createdAt, - video.views, - context + video.createdAt, + video.views, + context ) // set owner @@ -431,8 +427,8 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi binding.moreButton.setOnClickListener { v: View? -> val popup = PopupMenu( - context, - v!! + context, + v!! ) popup.setOnMenuItemClickListener { menuItem: MenuItem -> when (menuItem.itemId) { @@ -492,17 +488,17 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi val apiBaseURL = APIUrlHelper.getUrlWithVersion(context) val videoDataService = RetrofitInstance.getRetrofitInstance( - apiBaseURL, APIUrlHelper.useInsecureConnection( + apiBaseURL, APIUrlHelper.useInsecureConnection( context - ) + ) ).create( - GetVideoDataService::class.java + GetVideoDataService::class.java ) val call = videoDataService.rateVideo(video.id, body) call.enqueue(object : Callback { override fun onResponse( - call: Call, - response: Response + call: Call, + response: Response ) { // if 20x, update likes/dislikes if (response.isSuccessful) { @@ -539,17 +535,17 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi override fun onFailure(call: Call, t: Throwable) { Toast.makeText( - context, - context.getString(string.video_rating_failed), - Toast.LENGTH_SHORT + context, + context.getString(string.video_rating_failed), + Toast.LENGTH_SHORT ).show() } }) } else { Toast.makeText( - context, - context.getString(string.video_login_required_for_service), - Toast.LENGTH_SHORT + context, + context.getString(string.video_login_required_for_service), + Toast.LENGTH_SHORT ).show() } } diff --git a/app/src/main/java/net/schueller/peertube/database/AppDatabase.java b/app/src/main/java/net/schueller/peertube/database/AppDatabase.java index 79833de..6f9807b 100644 --- a/app/src/main/java/net/schueller/peertube/database/AppDatabase.java +++ b/app/src/main/java/net/schueller/peertube/database/AppDatabase.java @@ -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(); } \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/database/Video.kt b/app/src/main/java/net/schueller/peertube/database/Video.kt new file mode 100644 index 0000000..1ac17f9 --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/database/Video.kt @@ -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 \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/database/VideoDao.kt b/app/src/main/java/net/schueller/peertube/database/VideoDao.kt new file mode 100644 index 0000000..276904d --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/database/VideoDao.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * 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 . + */ +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> +} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/database/VideoRepository.kt b/app/src/main/java/net/schueller/peertube/database/VideoRepository.kt new file mode 100644 index 0000000..8fc219f --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/database/VideoRepository.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * 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 . + */ +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> + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/database/VideoRoomDatabase.java b/app/src/main/java/net/schueller/peertube/database/VideoRoomDatabase.java new file mode 100644 index 0000000..53f6647 --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/database/VideoRoomDatabase.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * 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 . + */ +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; + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/database/VideoViewModel.kt b/app/src/main/java/net/schueller/peertube/database/VideoViewModel.kt new file mode 100644 index 0000000..d4fbe86 --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/database/VideoViewModel.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * 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 . + */ +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> = 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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.kt b/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.kt index cac3793..f594bb1 100644 --- a/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.kt +++ b/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.kt @@ -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,12 +55,14 @@ class VideoMetaDataFragment : Fragment() { private lateinit var videoDescriptionFragment: VideoDescriptionFragment + private val mVideoViewModel: VideoViewModel by activityViewModels() + var isLeaveAppExpected = false private set override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment @@ -94,11 +78,11 @@ class VideoMetaDataFragment : Fragment() { // show full description fragment videoDescriptionFragment = VideoDescriptionFragment.newInstance(video, this) childFragmentManager.beginTransaction() - .add(R.id.video_meta_data_fragment, videoDescriptionFragment, VideoDescriptionFragment.TAG).commit() + .add(R.id.video_meta_data_fragment, videoDescriptionFragment, VideoDescriptionFragment.TAG).commit() } fun hideDescriptionFragment() { - val fragment: Fragment? = childFragmentManager.findFragmentByTag(VideoDescriptionFragment.TAG) + val fragment: Fragment? = childFragmentManager.findFragmentByTag(VideoDescriptionFragment.TAG) if (fragment != null) { childFragmentManager.beginTransaction().remove(fragment).commit() } @@ -113,10 +97,10 @@ class VideoMetaDataFragment : Fragment() { val activity: Activity? = activity val apiBaseURL = APIUrlHelper.getUrlWithVersion(context) val videoDataService = RetrofitInstance.getRetrofitInstance( - apiBaseURL, - APIUrlHelper.useInsecureConnection(context) + apiBaseURL, + APIUrlHelper.useInsecureConnection(context) ).create( - GetVideoDataService::class.java + GetVideoDataService::class.java ) // related videos @@ -149,8 +133,8 @@ class VideoMetaDataFragment : Fragment() { videoOptions.setOnClickListener { val videoOptionsFragment = VideoOptionsFragment.newInstance(mService, video.files) videoOptionsFragment.show( - getActivity()!!.supportFragmentManager, - VideoOptionsFragment.TAG + getActivity()!!.supportFragmentManager, + VideoOptionsFragment.TAG ) } } @@ -166,9 +150,9 @@ class VideoMetaDataFragment : Fragment() { // We set this to default to null so that on initial start there are videos listed. val apiBaseURL = APIUrlHelper.getUrlWithVersion(context) val service = - RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(context)).create( - GetVideoDataService::class.java - ) + RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(context)).create( + GetVideoDataService::class.java + ) val call: Call = service.getCommentThreads(videoId, start, count, sort) call.enqueue(object : Callback { @@ -176,7 +160,7 @@ class VideoMetaDataFragment : Fragment() { if (response.body() != null) { val commentThread = response.body() if (commentThread != null) { - mMultiViewAdapter!!.setVideoComment(commentThread); + mMultiViewAdapter!!.setVideoComment(commentThread) } } } @@ -197,8 +181,8 @@ class VideoMetaDataFragment : Fragment() { val filter: String? = null val sharedPref = context?.getSharedPreferences( - context.packageName + "_preferences", - Context.MODE_PRIVATE + context.packageName + "_preferences", + Context.MODE_PRIVATE ) var nsfw = "false" @@ -211,9 +195,9 @@ class VideoMetaDataFragment : Fragment() { // We set this to default to null so that on initial start there are videos listed. val apiBaseURL = APIUrlHelper.getUrlWithVersion(context) val service = - RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(context)).create( - GetVideoDataService::class.java - ) + RetrofitInstance.getRetrofitInstance(apiBaseURL, APIUrlHelper.useInsecureConnection(context)).create( + GetVideoDataService::class.java + ) val call: Call = service.getVideosData(start, count, sort, nsfw, filter, languages) /*Log the URL called*/Log.d("URL Called", call.request().url.toString() + "") @@ -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" }