From 204058c8394fd3d6ceab19d1340d6d851ea4378e Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 11 Mar 2025 16:22:29 +0100 Subject: [PATCH] fix #10 telechargement videos --- .../com/dreamteam/timelapse/VideoAdapter.kt | 127 +++++++++++++++++- app/src/main/res/menu/video_popup_menu.xml | 9 ++ 2 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 app/src/main/res/menu/video_popup_menu.xml diff --git a/app/src/main/java/com/dreamteam/timelapse/VideoAdapter.kt b/app/src/main/java/com/dreamteam/timelapse/VideoAdapter.kt index 1f8358a..a57e05b 100644 --- a/app/src/main/java/com/dreamteam/timelapse/VideoAdapter.kt +++ b/app/src/main/java/com/dreamteam/timelapse/VideoAdapter.kt @@ -1,8 +1,15 @@ package com.dreamteam.timelapse import android.annotation.SuppressLint +import android.app.ProgressDialog +import android.content.ContentValues +import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.os.Environment +import android.os.Handler +import android.os.Looper +import android.provider.MediaStore import android.util.Log import android.util.TypedValue import android.view.LayoutInflater @@ -10,6 +17,8 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.recyclerview.widget.RecyclerView @@ -24,6 +33,16 @@ import retrofit2.converter.gson.GsonConverterFactory import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.request.RequestOptions import com.google.android.material.imageview.ShapeableImageView +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okhttp3.internal.http2.Http2Reader +import okio.IOException +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream class VideoAdapter( public val withProjectNames : Boolean, @@ -70,14 +89,7 @@ class VideoAdapter( // Load video thumbnail val url = "https://timelapse.kerboul.me/api/videos/file/${video.id}" -// val shapeAppearanceModel = holder.videoThumbnail.shapeAppearanceModel -// .toBuilder() -// .setAllCornerSizes( -// TypedValue.applyDimension( -// TypedValue.COMPLEX_UNIT_DIP, 25f, holder.itemView.resources.displayMetrics)) // 16dp fixed -// .build() - //holder.videoThumbnail.shapeAppearanceModel = shapeAppearanceModel Glide.with(context) .load(url) // Load the video URL @@ -92,6 +104,107 @@ class VideoAdapter( intent.setFlags(FLAG_ACTIVITY_NEW_TASK) context.startActivity(intent) } + holder.itemView.setOnLongClickListener { + showPopupMenu(it, url) + true + } + } + + private fun showPopupMenu(view: View, videoUrl: String) { + val popupMenu = PopupMenu(view.context, view) + popupMenu.menuInflater.inflate(R.menu.video_popup_menu, popupMenu.menu) + + popupMenu.setOnMenuItemClickListener { item -> + when (item.itemId) { + R.id.menu_download -> { + downloadVideo(view.context, videoUrl) + true + } + else -> false + } + } + popupMenu.show() + } + + fun downloadVideo(context: Context, videoUrl: String) { + val request = Request.Builder().url(videoUrl).build() + val client = OkHttpClient() + + val progressDialog = ProgressDialog(context).apply { + setTitle("Téléchargement en cours") + setMessage("Patientez...") + setCancelable(false) + setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) + show() + } + + client.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.e("DownloadError", "Failed: ${e.message}") + progressDialog.dismiss() + Handler(Looper.getMainLooper()).post { + Toast.makeText(context, "Une erreur s'est produite lors du téléchargement", Toast.LENGTH_SHORT).show() + } } + + override fun onResponse(call: Call, response: Response) { + if (!response.isSuccessful) { + Log.e("DownloadError", "Error: ${response.code}") + progressDialog.dismiss() + + Handler(Looper.getMainLooper()).post { + Toast.makeText(context, "Une erreur s'est produite lors du téléchargement (Erreur ${response.code})", Toast.LENGTH_SHORT).show() + } + return + } + + val fileName = "video_${System.currentTimeMillis()}.mp4" + val file = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), fileName) + + val body = response.body ?: return + val totalSize = body.contentLength() + var downloadedSize = 0L + + body.byteStream().use { input -> + FileOutputStream(file).use { output -> + val buffer = ByteArray(1024) + var bytesRead: Int + + while (input.read(buffer).also { bytesRead = it } != -1) { + output.write(buffer, 0, bytesRead) + downloadedSize += bytesRead + progressDialog.progress = ((downloadedSize * 100) / totalSize).toInt() + } + } + } + + progressDialog.dismiss() + Handler(Looper.getMainLooper()).post { + moveFileToDownloads(file) + Toast.makeText(context, "Téléchargé : $fileName", Toast.LENGTH_SHORT).show() + } + } + }) + } + + fun moveFileToDownloads(sourceFile: File) { + val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + val destFile = File(downloadsDir, sourceFile.name) + + try { + // Create streams for copying data + FileInputStream(sourceFile).use { input -> + FileOutputStream(destFile).use { output -> + input.copyTo(output) + } + } + // Optionally delete the original file + if (sourceFile.exists()) { + sourceFile.delete() + } + Log.d("FileMove", "File moved to: ${destFile.absolutePath}") + } catch (e: Exception) { + Log.e("FileMoveError", "Error moving file: ${e.message}") + } } override fun getItemCount(): Int { diff --git a/app/src/main/res/menu/video_popup_menu.xml b/app/src/main/res/menu/video_popup_menu.xml new file mode 100644 index 0000000..661a930 --- /dev/null +++ b/app/src/main/res/menu/video_popup_menu.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file