Compare commits

...

5 Commits

14 changed files with 145 additions and 50 deletions

View File

@ -43,7 +43,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
implementation 'com.arthenica:ffmpeg-kit-full:5.1.LTS' implementation 'com.arthenica:ffmpeg-kit-full-gpl:5.1.LTS'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4' androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'

View File

@ -13,6 +13,8 @@ import android.provider.MediaStore
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.widget.ImageButton
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
@ -22,22 +24,21 @@ import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.arthenica.ffmpegkit.FFmpegKit
import com.arthenica.ffmpegkit.FFmpegKitConfig
import com.example.myapplication.R
import com.example.myapplication.databinding.ActivityMainBinding
import ca.unb.lantau.ui.completed.CompletedAdapter import ca.unb.lantau.ui.completed.CompletedAdapter
import ca.unb.lantau.ui.completed.CompletedItem import ca.unb.lantau.ui.completed.CompletedItem
import ca.unb.lantau.ui.compressing.CompressingAdapter import ca.unb.lantau.ui.compressing.CompressingAdapter
import ca.unb.lantau.ui.compressing.CompressingItem import ca.unb.lantau.ui.compressing.CompressingItem
import ca.unb.lantau.ui.settings.SettingsViewModel import ca.unb.lantau.ui.settings.SettingsViewModel
import com.arthenica.ffmpegkit.*
import com.example.myapplication.R
import com.example.myapplication.databinding.ActivityMainBinding
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import java.io.File import java.io.File
import java.util.* import java.util.*
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
private val settingsViewModel: SettingsViewModel by viewModels() private val settingsViewModel: SettingsViewModel by viewModels()
@ -144,9 +145,9 @@ class MainActivity : AppCompatActivity() {
Log.i("ethan", settingsViewModel.getSize().toString()) Log.i("ethan", settingsViewModel.getSize().toString())
Log.i("ethan", fileSize.toString()) Log.i("ethan", fileSize.toString())
val bitrate = (settingsViewModel.getSize() * 1000000) / (duration!! / 1000) val bitrate = (settingsViewModel.getSize() * 1_000_000) / (duration!! / 1_000)
val item = CompressingItem(fileName!!, 0.0, fileDate) val item = CompressingItem(fileName!!, 0.0, fileDate, "Not started", ImageButton(this),null)
val outputFile = File(this.getExternalFilesDir(null), "converted_$fileName") val outputFile = File(this.getExternalFilesDir(null), "converted_$fileName")
@ -154,27 +155,64 @@ class MainActivity : AppCompatActivity() {
val handler = Handler(Looper.getMainLooper()) val handler = Handler(Looper.getMainLooper())
val command = "-i $inUri -b:v $bitrate ${outputFile.absolutePath} -y" val tempFile = File(this.cacheDir, "temp_$fileName")
Log.i("ethan", command) val tempVideoFile = File(this.cacheDir, "tempVideo_$fileName")
val session = FFmpegKit.executeAsync(command) {
compressingItems.remove(item)
completedAdapter.refreshList(this)
val firstPass = "-i $inUri -codec:v libx264 -passlogfile ${tempFile.absolutePath} -preset veryfast -b:v $bitrate -maxrate $bitrate -minrate $bitrate -codec:a aac -pass 1 ${tempVideoFile.absolutePath} -y"
val secondPass = "-i ${tempVideoFile.absolutePath} -codec:v libx264 -passlogfile ${tempFile.absolutePath} -preset veryfast -b:v $bitrate -maxrate $bitrate -minrate $bitrate -codec:a aac -pass 2 ${outputFile.absolutePath} -y"
Log.i("Lantau", firstPass)
Log.i("Lantau", secondPass)
val firstPassSession = FFmpegKit.executeAsync(firstPass) { session ->
if (session.returnCode.isValueSuccess) {
val secondPassSession = FFmpegKit.executeAsync(secondPass) { session2 ->
if (session2.returnCode.isValueSuccess) {
handler.post {
handler.post { handler.post {
Toast.makeText( Toast.makeText(
this, applicationContext,
"Finished converting $fileName", "Finished converting $fileName",
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
compressingItems.remove(item)
compressingAdapter.notifyDataSetChanged()
completedAdapter.refreshList(applicationContext)
tempFile.delete()
tempVideoFile.delete()
}
}
} else {
handler.post {
Toast.makeText(
applicationContext,
"Failed to convert $fileName during second pass",
Toast.LENGTH_SHORT
).show()
compressingItems.remove(item)
compressingAdapter.notifyDataSetChanged() compressingAdapter.notifyDataSetChanged()
} }
} }
}
item.status = "Second pass running"
Log.i("Tag", Arrays.deepToString(session.arguments)) item.session = secondPassSession
Log.i("Tag", session.output) Log.i("Lantau", Arrays.deepToString(secondPassSession.arguments))
} else {
handler.post {
Toast.makeText(
applicationContext,
"Failed to convert $fileName during first pass",
Toast.LENGTH_SHORT
).show()
compressingItems.remove(item)
compressingAdapter.notifyDataSetChanged()
}
}
}
item.status = "First pass running"
item.session = firstPassSession
Log.i("Lantau", Arrays.deepToString(firstPassSession.arguments))
compressingAdapter.notifyDataSetChanged() compressingAdapter.notifyDataSetChanged()
} else { } else {
Toast.makeText( Toast.makeText(
@ -190,7 +228,7 @@ class MainActivity : AppCompatActivity() {
val compressingItems: MutableList<CompressingItem> = mutableListOf() val compressingItems: MutableList<CompressingItem> = mutableListOf()
val compressingAdapter = CompressingAdapter(compressingItems) val compressingAdapter = CompressingAdapter(compressingItems)
val completedItems: MutableList<CompletedItem> = mutableListOf() private val completedItems: MutableList<CompletedItem> = mutableListOf()
val completedAdapter = CompletedAdapter(completedItems) val completedAdapter = CompletedAdapter(completedItems)
} }
} }

View File

@ -3,6 +3,7 @@ package ca.unb.lantau.ui.compressing
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -14,11 +15,15 @@ class CompressingAdapter(private val mCompressingItems: MutableList<CompressingI
val filename: TextView = itemView.findViewById(R.id.compressing_filename) val filename: TextView = itemView.findViewById(R.id.compressing_filename)
val date: TextView = itemView.findViewById(R.id.compressing_date) val date: TextView = itemView.findViewById(R.id.compressing_date)
val progress: ProgressBar = itemView.findViewById(R.id.compressing_progress) val progress: ProgressBar = itemView.findViewById(R.id.compressing_progress)
val status: TextView = itemView.findViewById(R.id.compressing_status)
val cancelButton: ImageButton = itemView.findViewById(R.id.compressing_cancel)
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val compressingItemView = val compressingItemView =
LayoutInflater.from(parent.context).inflate(R.layout.item_compressing, parent, false) LayoutInflater.from(parent.context).inflate(R.layout.item_compressing, parent, false)
// Use gesture controls to swipe to delete
// Reference here: https://www.tutorialspoint.com/how-to-detect-swipe-direction-between-left-right-and-up-down-in-android
return ViewHolder(compressingItemView) return ViewHolder(compressingItemView)
} }
@ -27,7 +32,12 @@ class CompressingAdapter(private val mCompressingItems: MutableList<CompressingI
holder.filename.text = compressingItem.filename holder.filename.text = compressingItem.filename
holder.date.text = compressingItem.date.toString() holder.date.text = compressingItem.date.toString()
holder.progress.progress = compressingItem.progress.toInt() holder.progress.progress = compressingItem.progress.toInt()
holder.progress.visibility = View.INVISIBLE
holder.status.text = compressingItem.status
holder.status.visibility = View.INVISIBLE
holder.cancelButton.setOnClickListener {
compressingItem.session!!.cancel()
}
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {

View File

@ -1,5 +1,7 @@
package ca.unb.lantau.ui.compressing package ca.unb.lantau.ui.compressing
import android.widget.ImageButton
import com.arthenica.ffmpegkit.FFmpegSession
import java.util.* import java.util.*
data class CompressingItem(val filename: String, val progress: Double, val date: Date) data class CompressingItem(val filename: String, val progress: Double, val date: Date, var status: String, val cancelButton: ImageButton, var session: FFmpegSession?)

View File

@ -40,7 +40,10 @@ class SettingsFragment : Fragment() {
//updates size when size selection changes //updates size when size selection changes
binding.settingRadioGroup.setOnCheckedChangeListener{ group,checkedID -> binding.settingRadioGroup.setOnCheckedChangeListener{ group,checkedID ->
if(checkedID == binding.settingDefaultSizeVideo.id){ if (checkedID == binding.settingSmallVideoSize.id) {
settingsViewModel.size.value = 8.0
}
else if(checkedID == binding.settingDefaultSizeVideo.id){
settingsViewModel.size.value = 25.0 settingsViewModel.size.value = 25.0
}else if(checkedID == binding.settingBigSizeVideo.id){ }else if(checkedID == binding.settingBigSizeVideo.id){
settingsViewModel.size.value = 50.0 settingsViewModel.size.value = 50.0

View File

@ -13,7 +13,7 @@ class SettingsViewModel : ViewModel() {
//size of the file, grab this for use //size of the file, grab this for use
private val _size = MutableLiveData<Double>().apply { private val _size = MutableLiveData<Double>().apply {
value = 25.0 value = 8.0
} }
val size: MutableLiveData<Double> = _size val size: MutableLiveData<Double> = _size

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
</vector>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout 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" 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"
@ -7,7 +8,15 @@
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RadioGroup <RadioGroup
android:id="@+id/setting_radio_group" android:id="@+id/setting_radio_group"
@ -21,10 +30,16 @@
android:text="@string/settings_video_size" /> android:text="@string/settings_video_size" />
<RadioButton <RadioButton
android:id="@+id/setting_default_size_video" android:id="@+id/setting_small_video_size"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="true" android:checked="true"
android:text="@string/settings_small_size" />
<RadioButton
android:id="@+id/setting_default_size_video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/settings_default_size" /> android:text="@string/settings_default_size" />
<RadioButton <RadioButton

View File

@ -1,20 +1,30 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="10dp" android:paddingTop="10dp"
android:paddingBottom="10dp"> android:paddingBottom="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="5"
android:orientation="vertical">
<TextView <TextView
android:id="@+id/compressing_filename" android:id="@+id/compressing_filename"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<TextView <TextView
android:id="@+id/compressing_date" android:id="@+id/compressing_date"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/compressing_status"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<ProgressBar <ProgressBar
@ -22,5 +32,14 @@
style="@android:style/Widget.Holo.ProgressBar.Horizontal" style="@android:style/Widget.Holo.ProgressBar.Horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout>
<ImageButton
android:id="@+id/compressing_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="@drawable/ic_cancel"
android:contentDescription="@string/cancel" />
</LinearLayout> </LinearLayout>

View File

@ -5,6 +5,7 @@
<string name="title_settings">Settings</string> <string name="title_settings">Settings</string>
<string name="settings_video_size">Video Size</string> <string name="settings_video_size">Video Size</string>
<string name="settings_image_size">Image Size</string> <string name="settings_image_size">Image Size</string>
<string name="settings_small_size">8mb</string>
<string name="settings_default_size">25mb</string> <string name="settings_default_size">25mb</string>
<string name="settings_big_size">50mb</string> <string name="settings_big_size">50mb</string>
<string name="settings_huge_size">500mb</string> <string name="settings_huge_size">500mb</string>
@ -14,4 +15,6 @@
<string name="youtube">Youtube</string> <string name="youtube">Youtube</string>
<string name="share_button">Share</string> <string name="share_button">Share</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="cancel">Cancel</string>
</resources> </resources>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.