appli finalized
This commit is contained in:
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -4,7 +4,6 @@
|
|||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
@@ -13,6 +12,7 @@
|
|||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="resolveExternalAnnotations" value="false" />
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||||
|
|||||||
@@ -82,4 +82,8 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
tasks.register("testClasses")
|
||||||
}
|
}
|
||||||
BIN
app/release/app-release.apk
Normal file
BIN
app/release/app-release.apk
Normal file
Binary file not shown.
BIN
app/release/baselineProfiles/0/app-release.dm
Normal file
BIN
app/release/baselineProfiles/0/app-release.dm
Normal file
Binary file not shown.
BIN
app/release/baselineProfiles/1/app-release.dm
Normal file
BIN
app/release/baselineProfiles/1/app-release.dm
Normal file
Binary file not shown.
37
app/release/output-metadata.json
Normal file
37
app/release/output-metadata.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"artifactType": {
|
||||||
|
"type": "APK",
|
||||||
|
"kind": "Directory"
|
||||||
|
},
|
||||||
|
"applicationId": "com.dreamteam.timelapse",
|
||||||
|
"variantName": "release",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "SINGLE",
|
||||||
|
"filters": [],
|
||||||
|
"attributes": [],
|
||||||
|
"versionCode": 1,
|
||||||
|
"versionName": "1.0",
|
||||||
|
"outputFile": "app-release.apk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elementType": "File",
|
||||||
|
"baselineProfiles": [
|
||||||
|
{
|
||||||
|
"minApi": 28,
|
||||||
|
"maxApi": 30,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/1/app-release.dm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minApi": 31,
|
||||||
|
"maxApi": 2147483647,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/0/app-release.dm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minSdkVersionForDexing": 28
|
||||||
|
}
|
||||||
@@ -93,13 +93,27 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
||||||
builder.setView(layout)
|
builder.setView(layout)
|
||||||
builder.setPositiveButton("Save",
|
builder.setPositiveButton("Sauvegarder",
|
||||||
DialogInterface.OnClickListener { dialog, which ->
|
DialogInterface.OnClickListener { dialog, which ->
|
||||||
val onSuccess : () -> Unit = {dialog.dismiss() ; Snackbar.make(viewfortoast, "Nouveau projet créé", Snackbar.LENGTH_LONG).setAnchorView(Rtmp.id.fab).show() ; }
|
val onSuccess : () -> Unit = {
|
||||||
|
dialog.dismiss() ;
|
||||||
|
Snackbar.make(viewfortoast, "Nouveau projet créé", Snackbar.LENGTH_LONG).setAnchorView(Rtmp.id.fab).show() ;
|
||||||
|
}
|
||||||
val onError : (s:String) -> Unit = { s-> Snackbar.make(viewfortoast, "Erreur lors de la création du projet. ${s}", Snackbar.LENGTH_LONG).setAnchorView(Rtmp.id.fab).show() }
|
val onError : (s:String) -> Unit = { s-> Snackbar.make(viewfortoast, "Erreur lors de la création du projet. ${s}", Snackbar.LENGTH_LONG).setAnchorView(Rtmp.id.fab).show() }
|
||||||
|
|
||||||
projectRepository.createProject(project_name.text.toString(), project_desc.text.toString(), onSuccess, onError)
|
val name = project_name.text.toString()
|
||||||
|
val desc = project_desc.text.toString()
|
||||||
|
if (name.isBlank() || desc.isBlank() || name == "" || desc == "") {
|
||||||
|
Snackbar.make(viewfortoast, "Les champs ne doivent pas être vides", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}else {
|
||||||
|
projectRepository.createProject(
|
||||||
|
project_name.text.toString(),
|
||||||
|
project_desc.text.toString(),
|
||||||
|
onSuccess,
|
||||||
|
onError
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
builder.setNegativeButton("Cancel",
|
builder.setNegativeButton("Cancel",
|
||||||
DialogInterface.OnClickListener { dialog, which -> dialog.dismiss() })
|
DialogInterface.OnClickListener { dialog, which -> dialog.dismiss() })
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
package com.dreamteam.timelapse
|
package com.dreamteam.timelapse
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.EditText
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.dreamteam.timelapse.data.ApiService
|
import com.dreamteam.timelapse.data.ApiService
|
||||||
|
import com.dreamteam.timelapse.data.CaptureQuery
|
||||||
|
import com.dreamteam.timelapse.data.Confirmation
|
||||||
import com.dreamteam.timelapse.data.Measurement
|
import com.dreamteam.timelapse.data.Measurement
|
||||||
import com.dreamteam.timelapse.data.Project
|
import com.dreamteam.timelapse.data.Project
|
||||||
import com.dreamteam.timelapse.data.ProjectRepository
|
import com.dreamteam.timelapse.data.ProjectRepository
|
||||||
@@ -21,6 +27,11 @@ import com.github.mikephil.charting.data.LineData
|
|||||||
import com.github.mikephil.charting.data.LineDataSet
|
import com.github.mikephil.charting.data.LineDataSet
|
||||||
import com.github.mikephil.charting.formatter.ValueFormatter
|
import com.github.mikephil.charting.formatter.ValueFormatter
|
||||||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
|
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@@ -30,6 +41,9 @@ import java.util.Locale
|
|||||||
|
|
||||||
class ProjectActivity : AppCompatActivity() {
|
class ProjectActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var stopingProcedureDialog: AlertDialog
|
||||||
|
private lateinit var videoRenderDialog: AlertDialog
|
||||||
|
private lateinit var startingProcedureDialog: AlertDialog
|
||||||
private lateinit var binding: ProjectBinding
|
private lateinit var binding: ProjectBinding
|
||||||
private lateinit var projectRepository: ProjectRepository
|
private lateinit var projectRepository: ProjectRepository
|
||||||
private lateinit var videoRepository: VideoRepository
|
private lateinit var videoRepository: VideoRepository
|
||||||
@@ -37,6 +51,11 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
private var measures: List<Measurement> = emptyList() // Déclare une liste de projets vide
|
private var measures: List<Measurement> = emptyList() // Déclare une liste de projets vide
|
||||||
private var project: Project? = null
|
private var project: Project? = null
|
||||||
private var imageUrls = emptyList<String>()
|
private var imageUrls = emptyList<String>()
|
||||||
|
enum class ButtonState {
|
||||||
|
START, LOADING, FINISHED, ENDING
|
||||||
|
}
|
||||||
|
|
||||||
|
private var buttonState = ButtonState.START
|
||||||
|
|
||||||
class GridSpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {
|
class GridSpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {
|
||||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||||
@@ -48,6 +67,16 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
outRect.top = spacing
|
outRect.top = spacing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun refreshMultiuseButton(){
|
||||||
|
val floatingButton = findViewById<FloatingActionButton>(R.id.multiusefloating)
|
||||||
|
var icon = when (buttonState) {
|
||||||
|
ButtonState.START -> android.R.drawable.ic_media_play
|
||||||
|
ButtonState.LOADING -> R.drawable.baseline_stop_24
|
||||||
|
ButtonState.FINISHED, ButtonState.ENDING -> android.R.drawable.ic_menu_save
|
||||||
|
}
|
||||||
|
floatingButton.setImageResource(icon)
|
||||||
|
}
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
.baseUrl("https://timelapse.kerboul.me/api/")
|
.baseUrl("https://timelapse.kerboul.me/api/")
|
||||||
@@ -65,36 +94,77 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
initProjectInfo()
|
initProjectInfo()
|
||||||
|
binding.imagesList.layoutManager = GridLayoutManager(this.baseContext, 2, GridLayoutManager.HORIZONTAL, false)
|
||||||
|
binding.imagesList.addItemDecoration(GridSpacingItemDecoration(16)) // 16px spacing
|
||||||
|
binding.videosList.layoutManager = GridLayoutManager(this.baseContext, 2, GridLayoutManager.HORIZONTAL, false)
|
||||||
|
binding.videosList.addItemDecoration(GridSpacingItemDecoration(16)) // 16px spacing
|
||||||
fetchMeasuresAndRebuildGraph()
|
fetchMeasuresAndRebuildGraph()
|
||||||
|
fetchVideos()
|
||||||
val swipeRefreshLayout = binding.swipeRefreshLayout
|
val swipeRefreshLayout = binding.swipeRefreshLayout
|
||||||
swipeRefreshLayout.setOnRefreshListener {
|
swipeRefreshLayout.setOnRefreshListener {
|
||||||
fetchMeasuresAndRebuildGraph()
|
fetchMeasuresAndRebuildGraph()
|
||||||
|
fetchVideos()
|
||||||
Log.d("ProjetsFrag", "Actualisation des projets")
|
Log.d("ProjetsFrag", "Actualisation des projets")
|
||||||
}
|
}
|
||||||
fetchVideos()
|
|
||||||
|
|
||||||
|
val floatingButton = findViewById<FloatingActionButton>(R.id.multiusefloating)
|
||||||
|
this.buttonState = when(project?.getStatusText()) {
|
||||||
|
"Brouillon" -> ButtonState.START
|
||||||
|
"En Cours" -> ButtonState.LOADING
|
||||||
|
"Terminé" -> ButtonState.FINISHED
|
||||||
|
"En cours d'arret" -> ButtonState.ENDING
|
||||||
|
else -> ButtonState.START
|
||||||
|
}
|
||||||
|
var icon = when (buttonState) {
|
||||||
|
ButtonState.START -> android.R.drawable.ic_media_play
|
||||||
|
ButtonState.LOADING -> R.drawable.baseline_stop_24
|
||||||
|
ButtonState.FINISHED -> android.R.drawable.ic_menu_save
|
||||||
|
ButtonState.ENDING -> android.R.drawable.ic_menu_save
|
||||||
|
}
|
||||||
|
floatingButton.setImageResource(icon)
|
||||||
|
|
||||||
|
floatingButton.setOnClickListener {
|
||||||
|
// when (buttonState) {
|
||||||
|
// ButtonState.LOADING -> {
|
||||||
|
// buttonState = ButtonState.FINISHED
|
||||||
|
// }
|
||||||
|
// else -> {}
|
||||||
|
// }
|
||||||
|
// refreshMultiuseButton()
|
||||||
|
when (buttonState) {
|
||||||
|
ButtonState.START -> clickStartProcess()
|
||||||
|
ButtonState.LOADING -> clickStopProcess()
|
||||||
|
ButtonState.FINISHED, ButtonState.ENDING -> clickSave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var but = findViewById<View>(R.id.multiusefloating)
|
||||||
|
but.post {
|
||||||
|
project?.let {
|
||||||
|
createVideoRenderDialog(but, it.id, measures)
|
||||||
|
createStopProcedureDialog(but, it.id)
|
||||||
|
createStartingProcedureDialog(but, it.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Bouton flottant
|
// Bouton flottant
|
||||||
// binding.fab.setOnClickListener { view ->
|
// binding.fab.setOnClickListener { view ->
|
||||||
// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
|
//
|
||||||
// //.setAction("Action", null) //sert à rien
|
|
||||||
// .setAnchorView(R.id.fab).show() //au dessus du bouton mail
|
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchVideos(){
|
fun fetchVideos(){
|
||||||
this.project?.let{
|
this.project?.let{
|
||||||
videoRepository.fetchVideosOfProject(it.id, onSuccess = { videos ->
|
videoRepository.fetchRenderedVideosOfProject(it.id, onSuccess = { videos ->
|
||||||
val adapter = VideoAdapter(false, videos.toMutableList(), null) //ImageAdapter(imageUrls)
|
val adapter = VideoAdapter(false, videos.toMutableList(), null) //ImageAdapter(imageUrls)
|
||||||
binding.videosList.layoutManager = GridLayoutManager(this.baseContext, 2, GridLayoutManager.HORIZONTAL, false)
|
|
||||||
binding.videosList.addItemDecoration(GridSpacingItemDecoration(16)) // 16px spacing
|
|
||||||
binding.videosList.adapter = adapter
|
binding.videosList.adapter = adapter
|
||||||
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
}, onError = {errorMessage ->
|
}, onError = {errorMessage ->
|
||||||
Log.e("ProjectActivity", errorMessage)
|
Log.e("ProjectActivity", "Fetch Video " + errorMessage)
|
||||||
fetchVideos()
|
fetchVideos()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -109,8 +179,7 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
initGraph(this.measures)
|
initGraph(this.measures)
|
||||||
|
|
||||||
val adapter = ImageAdapter(this.measures.map { m-> "https://timelapse.kerboul.me/api/images/${m.project_id}/${m.order_id}"}) //ImageAdapter(imageUrls)
|
val adapter = ImageAdapter(this.measures.map { m-> "https://timelapse.kerboul.me/api/images/${m.project_id}/${m.order_id}"}) //ImageAdapter(imageUrls)
|
||||||
binding.imagesList.layoutManager = GridLayoutManager(this.baseContext, 2, GridLayoutManager.HORIZONTAL, false)
|
Log.d("ProjectActivity", "Je vais mettre l'adapter")
|
||||||
binding.imagesList.addItemDecoration(GridSpacingItemDecoration(16)) // 16px spacing
|
|
||||||
binding.imagesList.adapter = adapter
|
binding.imagesList.adapter = adapter
|
||||||
|
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
@@ -124,7 +193,6 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initGraph(lm: List<Measurement>) {
|
fun initGraph(lm: List<Measurement>) {
|
||||||
val temperatureHumidityChart = this.binding.temperatureHumidityChart
|
val temperatureHumidityChart = this.binding.temperatureHumidityChart
|
||||||
|
|
||||||
@@ -160,8 +228,15 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
val xAxis = temperatureHumidityChart.xAxis
|
val xAxis = temperatureHumidityChart.xAxis
|
||||||
xAxis.valueFormatter = object : ValueFormatter() {
|
xAxis.valueFormatter = object : ValueFormatter() {
|
||||||
override fun getFormattedValue(value: Float): String {
|
override fun getFormattedValue(value: Float): String {
|
||||||
// Map the index back to the corresponding timestamp
|
val index = value.toInt()
|
||||||
val timestamp = lm.sortedBy { it.order_id }[value.toInt()].timestamp
|
val sortedList = lm.sortedBy { it.order_id }
|
||||||
|
|
||||||
|
if (index < 0 || index >= sortedList.size) {
|
||||||
|
// Index out of bounds, return empty string or something neutral
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val timestamp = sortedList[index].timestamp
|
||||||
val date = Date(timestamp.time)
|
val date = Date(timestamp.time)
|
||||||
val sdf = SimpleDateFormat("dd/MM/yyyy:HH:mm:ss", Locale.getDefault())
|
val sdf = SimpleDateFormat("dd/MM/yyyy:HH:mm:ss", Locale.getDefault())
|
||||||
return sdf.format(date)
|
return sdf.format(date)
|
||||||
@@ -222,9 +297,6 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
// Refresh the chart
|
// Refresh the chart
|
||||||
temperatureHumidityChart.invalidate()
|
temperatureHumidityChart.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun initProjectInfo(){
|
fun initProjectInfo(){
|
||||||
val nameview = findViewById<TextView>(R.id.project_name)
|
val nameview = findViewById<TextView>(R.id.project_name)
|
||||||
val descriptionview = findViewById<TextView>(R.id.project_description)
|
val descriptionview = findViewById<TextView>(R.id.project_description)
|
||||||
@@ -236,4 +308,200 @@ class ProjectActivity : AppCompatActivity() {
|
|||||||
beginview.text = project!!.start_date.toString()
|
beginview.text = project!!.start_date.toString()
|
||||||
statusview.text = project!!.getStatusText()
|
statusview.text = project!!.getStatusText()
|
||||||
}
|
}
|
||||||
|
private fun clickStartProcess() {
|
||||||
|
Log.i("ProjectActivity", "Start collect...")
|
||||||
|
|
||||||
|
// Simule une durée avant la finalisation du processus
|
||||||
|
// Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
// val floatingButton = findViewById<FloatingActionButton>(R.id.multiusefloating)
|
||||||
|
// floatingButton.setImageResource(android.R.drawable.ic_menu_save) // Icône d'enregistrement
|
||||||
|
// buttonState = ButtonState.FINISHED
|
||||||
|
// }, 5000) // 5 secondes de chargement
|
||||||
|
startingProcedureDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickStopProcess() {
|
||||||
|
Log.i("ProjectActivity", "Stop collect...")
|
||||||
|
stopingProcedureDialog.show()
|
||||||
|
// Implémente l'arrêt du processus (annulation si nécessaire)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickSave() {
|
||||||
|
Log.i("ProjectActivity", "Create video...")
|
||||||
|
videoRenderDialog.show()
|
||||||
|
//videoRepository.createVideo(project.id, measures, )
|
||||||
|
// Toast.makeText(context, "Downloading...", Toast.LENGTH_SHORT).show()
|
||||||
|
//
|
||||||
|
// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
|
||||||
|
// .setAction("Action", null) //sert à rien
|
||||||
|
// .setAnchorView(R.id.fab).show() //au dessus du bouton mail
|
||||||
|
// Implémente la création d'une vidéo
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createVideoRenderDialog(viewfortoast: View, projectId: Int, measurements: List<Measurement>) {
|
||||||
|
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
val layout: View = inflater.inflate(R.layout.video_render_dialog_layout, findViewById(R.id.layout_root))
|
||||||
|
|
||||||
|
val videoName = layout.findViewById<EditText>(R.id.video_name_dialog)
|
||||||
|
//val videoResolution = layout.findViewById<EditText>(R.id.video_resolution_dialog)
|
||||||
|
val videoDuration = layout.findViewById<EditText>(R.id.video_duration_dialog)
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(this)
|
||||||
|
builder.setView(layout)
|
||||||
|
.setPositiveButton("Render Video") { dialog, _ ->
|
||||||
|
val name = videoName.text.toString()
|
||||||
|
//val resolution = videoResolution.text.toString()
|
||||||
|
val durationText = videoDuration.text.toString()
|
||||||
|
|
||||||
|
if (name.isBlank() || durationText.isBlank()) {
|
||||||
|
Snackbar.make(viewfortoast, "All fields must be filled", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
return@setPositiveButton
|
||||||
|
}
|
||||||
|
|
||||||
|
val duration = durationText.toIntOrNull()
|
||||||
|
if (duration == null || duration <= 0) {
|
||||||
|
Snackbar.make(viewfortoast, "Invalid duration", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
return@setPositiveButton
|
||||||
|
}
|
||||||
|
|
||||||
|
val onSuccess: (Confirmation?) -> Unit = {
|
||||||
|
dialog.dismiss()
|
||||||
|
Snackbar.make(viewfortoast, "Video render started", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
val onError: (String) -> Unit = { error ->
|
||||||
|
Snackbar.make(viewfortoast, "Error: $error", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
videoRepository.createVideo(projectId, measures, name, "1920x1080", duration, onSuccess, onError)
|
||||||
|
}
|
||||||
|
.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
|
||||||
|
|
||||||
|
this.videoRenderDialog = builder.create()
|
||||||
|
}
|
||||||
|
fun createStartingProcedureDialog(viewfortoast: View, projectId: Int) {
|
||||||
|
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
val layout: View = inflater.inflate(R.layout.capture_start_dialog_layout, findViewById(R.id.layout_root))
|
||||||
|
|
||||||
|
val intervalView = layout.findViewById<EditText>(R.id.interval)
|
||||||
|
//val videoResolution = layout.findViewById<EditText>(R.id.video_resolution_dialog)
|
||||||
|
val nbImView = layout.findViewById<EditText>(R.id.nb_images)
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(this)
|
||||||
|
builder.setView(layout)
|
||||||
|
.setPositiveButton("Run capture procedure") { dialog, _ ->
|
||||||
|
val intervalStr = intervalView.text.toString()
|
||||||
|
//val resolution = videoResolution.text.toString()
|
||||||
|
val nb_imagesStr = nbImView.text.toString()
|
||||||
|
|
||||||
|
if (intervalStr.isBlank() || nb_imagesStr.isBlank()) {
|
||||||
|
Snackbar.make(viewfortoast, "Les champs doivent être remplis", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
return@setPositiveButton
|
||||||
|
}
|
||||||
|
|
||||||
|
val interval = intervalStr.toIntOrNull()
|
||||||
|
val nb_images = nb_imagesStr.toIntOrNull()
|
||||||
|
if (interval == null || interval <= 0 || nb_images == null || nb_images <= 0) {
|
||||||
|
Snackbar.make(viewfortoast, "Les chiffres fournis doivent être superieurs à 1", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
return@setPositiveButton
|
||||||
|
}
|
||||||
|
|
||||||
|
val onSuccess: () -> Unit = {
|
||||||
|
dialog.dismiss()
|
||||||
|
Snackbar.make(viewfortoast, "Processus de capture lancé", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
buttonState = ButtonState.LOADING
|
||||||
|
refreshMultiuseButton()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
val onError: (String) -> Unit = { error ->
|
||||||
|
Snackbar.make(viewfortoast, "Error : $error", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
apiService.procedureStart(CaptureQuery(interval, nb_images, projectId)).enqueue(object :
|
||||||
|
Callback<Void> {
|
||||||
|
override fun onResponse(call: Call<Void>, response: Response<Void>) {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
refreshProjectInfo(onSuccess, onError)
|
||||||
|
} else {
|
||||||
|
onError("Erreur serveur : ${response.code()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<Void>, t: Throwable) {
|
||||||
|
onError("Erreur réseau : ${t.message}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
|
||||||
|
|
||||||
|
this.startingProcedureDialog = builder.create()
|
||||||
|
}
|
||||||
|
fun createStopProcedureDialog(viewfortoast: View, projectId: Int) {
|
||||||
|
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||||
|
val layout: View = inflater.inflate(R.layout.capture_stop_dialog_layout, findViewById(R.id.layout_root))
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(this)
|
||||||
|
builder.setView(layout)
|
||||||
|
.setPositiveButton("Stop") { dialog, _ ->
|
||||||
|
val onSuccess: () -> Unit = {
|
||||||
|
dialog.dismiss()
|
||||||
|
Snackbar.make(viewfortoast, "Processus arreté", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
buttonState = ButtonState.FINISHED
|
||||||
|
refreshMultiuseButton()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
val onError: (String) -> Unit = { error ->
|
||||||
|
Snackbar.make(viewfortoast, "Error : $error", Snackbar.LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
apiService.procedureStop().enqueue(object :
|
||||||
|
Callback<Void> {
|
||||||
|
override fun onResponse(call: Call<Void>, response: Response<Void>) {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
refreshProjectInfo(onSuccess, onError)
|
||||||
|
} else {
|
||||||
|
onError("Erreur serveur : ${response.code()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<Void>, t: Throwable) {
|
||||||
|
onError("Erreur réseau : ${t.message}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
|
||||||
|
|
||||||
|
this.stopingProcedureDialog = builder.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshProjectInfo(cbGood: ()->Unit, cbBad: (String)->Unit){
|
||||||
|
this.project?.let {
|
||||||
|
projectRepository.fetchProject(it.id, onSuccess = {
|
||||||
|
Log.i("ProjectActivity", "Pull projet ok")
|
||||||
|
this.project = it;
|
||||||
|
this.initProjectInfo()
|
||||||
|
cbGood()
|
||||||
|
}, onError = {
|
||||||
|
Log.i("ProjectActivity", "Erreur de pull projet : $it")
|
||||||
|
cbBad("Erreur de pull projet : $it")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
super.onBackPressed()
|
||||||
|
startActivity(Intent(this, MainActivity::class.java))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,24 +74,28 @@ class ProjectAdapter(private val projects: MutableList<Project>, private val lis
|
|||||||
}
|
}
|
||||||
fun removeItem(position: Int, context: Context, v : View) {
|
fun removeItem(position: Int, context: Context, v : View) {
|
||||||
val builder = AlertDialog.Builder(context)
|
val builder = AlertDialog.Builder(context)
|
||||||
val dialog = builder.setTitle("Confirm Deletion")
|
val dialog = builder.setTitle("Confirmer la supression")
|
||||||
.setMessage("Voulez vous supprimer ce projet ?")
|
.setMessage("Voulez vous supprimer ce projet ?")
|
||||||
.setPositiveButton("Supprimer") { dialog, _ ->
|
.setPositiveButton("Supprimer") { dialog, _ ->
|
||||||
projectRepository.deleteProject(projects[position].id, onSuccess = {
|
if(projects[position].status != 3 && projects[position].status != 2){
|
||||||
val name = projects[position].name
|
projectRepository.deleteProject(projects[position].id, onSuccess = {
|
||||||
projects.removeAt(position)
|
val name = projects[position].name
|
||||||
notifyItemRemoved(position)
|
projects.removeAt(position)
|
||||||
Snackbar.make(v.rootView, "$name supprimé avec succès !", Snackbar.LENGTH_SHORT).show()
|
notifyItemRemoved(position)
|
||||||
}, onError = {s ->
|
Snackbar.make(v.rootView, "$name supprimé avec succès !", Snackbar.LENGTH_SHORT).show()
|
||||||
dialog.dismiss()
|
}, onError = {s ->
|
||||||
|
dialog.dismiss()
|
||||||
|
notifyItemChanged(position)
|
||||||
|
Snackbar.make(v.rootView, "Error while trying to delete ${projects[position].name} : $s", Snackbar.LENGTH_SHORT).show()
|
||||||
|
})
|
||||||
|
}else{
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
Snackbar.make(v.rootView, "Error while trying to delete ${projects[position].name} : $s", Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(v.rootView, "On ne peut pas supprimer un projet dans un état intermédiaire", Snackbar.LENGTH_SHORT).show()
|
||||||
})
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.setNegativeButton("Annuler") { dialog, _ ->
|
.setNegativeButton("Annuler") { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
notifyItemChanged(position) // Reset swipe animation
|
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
dialog.setOnDismissListener {
|
dialog.setOnDismissListener {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ interface ApiService {
|
|||||||
fun getMeasurements(@Path("id") projectId: Int): Call<List<Measurement>>
|
fun getMeasurements(@Path("id") projectId: Int): Call<List<Measurement>>
|
||||||
@GET("videos")
|
@GET("videos")
|
||||||
fun getVideos(): Call<List<VideoDTO>>
|
fun getVideos(): Call<List<VideoDTO>>
|
||||||
|
@POST("videos")
|
||||||
|
fun createVideo(@Body video: VideoDTO): Call<Confirmation>
|
||||||
@DELETE("videos/{id}")
|
@DELETE("videos/{id}")
|
||||||
fun deleteVideo(@Path("id") videoId : Int): Call<Void>
|
fun deleteVideo(@Path("id") videoId : Int): Call<Void>
|
||||||
@POST("projects/")
|
@POST("projects/")
|
||||||
@@ -25,4 +27,8 @@ interface ApiService {
|
|||||||
fun getVideosOfProject(@Path("id") projectId:Int): Call<List<VideoDTO>>
|
fun getVideosOfProject(@Path("id") projectId:Int): Call<List<VideoDTO>>
|
||||||
@DELETE("projects/{id}")
|
@DELETE("projects/{id}")
|
||||||
fun deleteProject(@Path("id") projectId:Int) : Call<Void>
|
fun deleteProject(@Path("id") projectId:Int) : Call<Void>
|
||||||
|
@POST("procedure/start")
|
||||||
|
fun procedureStart(@Body captureQuery: CaptureQuery): Call<Void>
|
||||||
|
@POST("procedure/stop")
|
||||||
|
fun procedureStop(): Call<Void>
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.dreamteam.timelapse.data
|
||||||
|
|
||||||
|
data class CaptureQuery (
|
||||||
|
val interval: Int,
|
||||||
|
val nb_images: Int,
|
||||||
|
val project_id: Int
|
||||||
|
)
|
||||||
|
{}
|
||||||
@@ -24,7 +24,7 @@ data class Project(
|
|||||||
|
|
||||||
fun getStatusText(): String{
|
fun getStatusText(): String{
|
||||||
Log.i("Project", "Status $status being trasnlated")
|
Log.i("Project", "Status $status being trasnlated")
|
||||||
val statusArr = arrayOf("Brouillon", "En Cours", "Terminé", "Annulé")
|
val statusArr = arrayOf("Brouillon", "En Cours", "Terminé", "En cours d'arret")
|
||||||
return statusArr[status]
|
return statusArr[status]
|
||||||
}
|
}
|
||||||
fun getStatusColor(): Int{
|
fun getStatusColor(): Int{
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ class ProjectRepository(private val apiService: ApiService) {
|
|||||||
onSuccess(it)
|
onSuccess(it)
|
||||||
} ?: onError("Aucune mesure trouvé")
|
} ?: onError("Aucune mesure trouvé")
|
||||||
} else {
|
} else {
|
||||||
onError("Erreur : ${response.code()}")
|
onSuccess(emptyList())
|
||||||
|
//onError("Erreur reception measures: ${response.code()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ class ProjectRepository(private val apiService: ApiService) {
|
|||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
onSuccess()
|
onSuccess()
|
||||||
} else {
|
} else {
|
||||||
onError("Erreur : ${response.code()}")
|
onError("Erreur creation projet : ${response.code()}, ${response.body()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.dreamteam.timelapse.data
|
package com.dreamteam.timelapse.data
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
@@ -16,7 +17,15 @@ data class VideoDTO (
|
|||||||
fun toVideo(): Video {
|
fun toVideo(): Video {
|
||||||
fun parseIntArray(jsonString: String): List<Int> {
|
fun parseIntArray(jsonString: String): List<Int> {
|
||||||
val type = object : TypeToken<List<Int>>() {}.type
|
val type = object : TypeToken<List<Int>>() {}.type
|
||||||
return Gson().fromJson<List<Int>>(jsonString, type)
|
try {
|
||||||
|
Log.d("VideoDTO", Gson().fromJson<List<Int>>(jsonString, type).toString())
|
||||||
|
return Gson().fromJson<List<Int>>(jsonString, type)
|
||||||
|
}catch (e: Exception){
|
||||||
|
Log.d("VideoDTO", jsonString)
|
||||||
|
return Gson().fromJson<List<Int>>("[]", type)
|
||||||
|
|
||||||
|
//throw Exception("Tentative de transformer une videoDTO en video alors que le format est pas bon")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Video(id, project_id, parseIntArray(measurement_ids), video_file, resolution, duration, status, name)
|
return Video(id, project_id, parseIntArray(measurement_ids), video_file, resolution, duration, status, name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.dreamteam.timelapse.data
|
package com.dreamteam.timelapse.data
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
@@ -39,15 +40,20 @@ class VideoRepository(private val apiService: ApiService) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fun fetchVideosOfProject(id:Int, onSuccess: (List<Video>) -> Unit, onError: (String) -> Unit){
|
fun fetchRenderedVideosOfProject(id:Int, onSuccess: (List<Video>) -> Unit, onError: (String) -> Unit){
|
||||||
apiService.getVideosOfProject(id).enqueue(object : Callback<List<VideoDTO>> {
|
apiService.getVideosOfProject(id).enqueue(object : Callback<List<VideoDTO>> {
|
||||||
override fun onResponse(call: Call<List<VideoDTO>>, response: Response<List<VideoDTO>>) {
|
override fun onResponse(call: Call<List<VideoDTO>>, response: Response<List<VideoDTO>>) {
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
val videoDtos = response.body() ?: emptyList()
|
val videoDtos = response.body() ?: emptyList()
|
||||||
|
videoDtos.forEach {
|
||||||
|
Log.d("VideoRepository", it.toString())
|
||||||
|
it.toVideo()
|
||||||
|
}
|
||||||
val videos = videoDtos.map { it.toVideo() } // Convert ugly data to clean Video objects
|
val videos = videoDtos.map { it.toVideo() } // Convert ugly data to clean Video objects
|
||||||
onSuccess(videos)
|
onSuccess(videos.filter { v -> v.video_file != null })
|
||||||
} else {
|
} else {
|
||||||
onError("Erreur serveur : ${response.code()}")
|
onSuccess(emptyList())
|
||||||
|
//onError("Erreur serveur : ${response.code()} ; id : $id ; ${response.body()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,4 +94,24 @@ class VideoRepository(private val apiService: ApiService) {
|
|||||||
onError("Erreur réseau : ${t.message}")
|
onError("Erreur réseau : ${t.message}")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}}
|
}
|
||||||
|
fun createVideo(project_id:Int, measurements: List<Measurement>,
|
||||||
|
name:String, resolution: String, duration:Int,
|
||||||
|
onSuccess: (Confirmation?) -> Unit, onError: (String) -> Unit){
|
||||||
|
Log.d("VideoRepository", measurements.map {m -> m.order_id}.toString())
|
||||||
|
var v = VideoDTO(0, project_id, measurements.map {m -> m.order_id}.toString(), null, resolution, duration, 0, name)
|
||||||
|
apiService.createVideo(v).enqueue(object : Callback<Confirmation> {
|
||||||
|
override fun onResponse(call: Call<Confirmation>, response: Response<Confirmation>) {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
onSuccess(response.body())
|
||||||
|
} else {
|
||||||
|
onError("Erreur : ${response.code()} ; ${response.body()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<Confirmation>, t: Throwable) {
|
||||||
|
onError("Échec de l'appel API : ${t.message}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
5
app/src/main/res/drawable/baseline_stop_24.xml
Normal file
5
app/src/main/res/drawable/baseline_stop_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M6,6h12v12H6z"/>
|
||||||
|
|
||||||
|
</vector>
|
||||||
29
app/src/main/res/layout/capture_start_dialog_layout.xml
Normal file
29
app/src/main/res/layout/capture_start_dialog_layout.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/layout_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/interval"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Frequence (min)"
|
||||||
|
android:inputType="number"/>
|
||||||
|
|
||||||
|
<!--<EditText
|
||||||
|
android:id="@+id/video_resolution_dialog"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Resolution (e.g., 1080p)" />-->
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/nb_images"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Nombre d'images"
|
||||||
|
android:inputType="number" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
16
app/src/main/res/layout/capture_stop_dialog_layout.xml
Normal file
16
app/src/main/res/layout/capture_stop_dialog_layout.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/layout_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="25sp"
|
||||||
|
android:text="Voulez vous annuler la prise de vue ? (la demande sera prise en compte par la camera lors de son prochain redemarrage)" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -165,4 +165,15 @@
|
|||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
</com.dreamteam.timelapse.CustomSwipeRefreshLayout>
|
</com.dreamteam.timelapse.CustomSwipeRefreshLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/multiusefloating"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="25dp"
|
||||||
|
android:layout_marginBottom="25dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:srcCompat="@android:drawable/ic_media_play" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
28
app/src/main/res/layout/video_render_dialog_layout.xml
Normal file
28
app/src/main/res/layout/video_render_dialog_layout.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/layout_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/video_name_dialog"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Video Name" />
|
||||||
|
|
||||||
|
<!--<EditText
|
||||||
|
android:id="@+id/video_resolution_dialog"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Resolution (e.g., 1080p)" />-->
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/video_duration_dialog"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Duration (seconds)"
|
||||||
|
android:inputType="number" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user