добавление данных тренировок и упражнений

This commit is contained in:
Надежда Емцова 2025-05-14 22:11:42 +03:00
parent 505f533f04
commit 3078443367
31 changed files with 928 additions and 323 deletions

View File

@ -0,0 +1,67 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "6ba5dfef7859cedba19af71b404c9e4f",
"entities": [
{
"tableName": "workouts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `numApproaches` INTEGER NOT NULL, `numExercises` INTEGER NOT NULL, `restBetweenExercises` INTEGER NOT NULL, `restBetweenApproaches` INTEGER NOT NULL, `exerciseDuration` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "numApproaches",
"columnName": "numApproaches",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "numExercises",
"columnName": "numExercises",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "restBetweenExercises",
"columnName": "restBetweenExercises",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "restBetweenApproaches",
"columnName": "restBetweenApproaches",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "exerciseDuration",
"columnName": "exerciseDuration",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6ba5dfef7859cedba19af71b404c9e4f')"
]
}
}

View File

@ -1,9 +0,0 @@
package com.example.timert
import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.timert.Workout
import com.example.timert.WorkoutDao
@Database(entities = [Workout::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun workoutDao(): WorkoutDao
}

View File

@ -1,27 +0,0 @@
package com.example.timert
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class WorkoutAdapter(private val workouts: List<Workout>) : RecyclerView.Adapter<WorkoutAdapter.WorkoutViewHolder>() {
class WorkoutViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textViewName: TextView = itemView.findViewById(R.id.textViewName)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.workout_item, parent, false)
return WorkoutViewHolder(itemView)
}
override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
val currentItem = workouts[position]
holder.textViewName.text = currentItem.name
}
override fun getItemCount() = workouts.size
}

View File

@ -6,13 +6,24 @@ import android.os.Bundle
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.ImageView import android.widget.ImageView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.ViewModelProvider
import com.example.timert.com.example.timert.data.entity.Workout
import com.example.timert.data.viewModel.WorkoutViewModel
class AddWorkout : AppCompatActivity() { class AddWorkout : AppCompatActivity() {
private var isSave = false private var isSave = false
private lateinit var editWorkoutView: EditText
private lateinit var numWorkoutView: EditText
private lateinit var numRestWorkoutView: EditText
private lateinit var numRestSetsView: EditText
private lateinit var numSetsView: EditText
private lateinit var timeWorkoutView: EditText
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -23,13 +34,64 @@ class AddWorkout : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets insets
} }
val workoutViewModel = ViewModelProvider(
this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
)[WorkoutViewModel::class.java]
editWorkoutView = findViewById(R.id.name_training)
numWorkoutView = findViewById(R.id.num_exercise)
numRestWorkoutView = findViewById(R.id.rest_workout_all)
numRestSetsView = findViewById(R.id.rest_sets_all)
numSetsView = findViewById(R.id.numbers_of_sets_all)
timeWorkoutView = findViewById(R.id.time_work_all)
val buttonSaveAll: Button = findViewById(R.id.btn_save_all) val buttonSaveAll: Button = findViewById(R.id.btn_save_all)
buttonSaveAll.setOnClickListener { buttonSaveAll.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent) val workoutName = editWorkoutView.text.toString()
val numWorkoutText = numWorkoutView.text.toString()
val restWorkoutText = numRestWorkoutView.text.toString()
val restSetsText = numRestSetsView.text.toString()
val numSetsText = numSetsView.text.toString()
val timeWorkText = timeWorkoutView.text.toString()
if (workoutName.isBlank() || numSetsText.isBlank() || restSetsText.isBlank()||numWorkoutText.isBlank() || restWorkoutText.isBlank() || timeWorkText.isBlank()) {
Toast.makeText(this, "Заполните все поля", Toast.LENGTH_SHORT).show()
} else {
val numExercise = numWorkoutText.toIntOrNull()
val restExercise = restWorkoutText.toIntOrNull()
val numSets = numSetsText.toIntOrNull()
val restSets = restSetsText.toIntOrNull()
val timeWorkExercise = timeWorkText.toIntOrNull()
if (numSets == null || restSets == null || numExercise == null || restExercise == null || timeWorkExercise == null) {
Toast.makeText(this, "Неверный формат чисел", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
val newWorkout = Workout(
name = workoutName,
numApproaches = numSets,
numExercises = numExercise,
restBetweenExercises = restExercise,
restBetweenApproaches = restSets,
exerciseDuration = timeWorkExercise,
)
workoutViewModel.insert(newWorkout)
Toast.makeText(this, "Упражнение сохранено", Toast.LENGTH_SHORT).show()
isSave = true isSave = true
} }
}
val button_on_main_all: Button = findViewById(R.id.btn_on_main_all) val button_on_main_all: Button = findViewById(R.id.btn_on_main_all)
button_on_main_all.setOnClickListener { button_on_main_all.setOnClickListener {
if (isSave == false) { if (isSave == false) {
@ -71,10 +133,16 @@ class AddWorkout : AppCompatActivity() {
val Plus: ImageView = findViewById(R.id.add_set) val Plus: ImageView = findViewById(R.id.add_set)
val Minus: ImageView = findViewById(R.id.del_set) val Minus: ImageView = findViewById(R.id.del_set)
val numExer: EditText = findViewById(R.id.num_exercise)
val PlusExer: ImageView = findViewById(R.id.add_set4)
val MinusExer: ImageView = findViewById(R.id.del_set4)
setupPlusMinus(timeInputRestSetAll, btnPlusTimeAll, btnMinusTimeAll, minValue = 5, maxValue = 600) setupPlusMinus(timeInputRestSetAll, btnPlusTimeAll, btnMinusTimeAll, minValue = 5, maxValue = 600)
setupPlusMinus(setsInputAll, btnPlusSetsAll, btnMinusSetsAll, minValue = 1, maxValue = 20) setupPlusMinus(setsInputAll, btnPlusSetsAll, btnMinusSetsAll, minValue = 1, maxValue = 20)
setupPlusMinus(timeInputRest, btnPlusTimeWor, btnMinusTimeWor, minValue = 5, maxValue = 600) setupPlusMinus(timeInputRest, btnPlusTimeWor, btnMinusTimeWor, minValue = 5, maxValue = 600)
setupPlusMinus(timeWork, Plus, Minus, minValue = 5, maxValue = 600) setupPlusMinus(timeWork, Plus, Minus, minValue = 5, maxValue = 600)
setupPlusMinus(numExer, PlusExer, MinusExer, minValue = 1, maxValue = 50)
} }

View File

@ -59,7 +59,8 @@ class AllTraining : AppCompatActivity() {
val newExercise = Exercise( val newExercise = Exercise(
name_exercise = exerciseName, name_exercise = exerciseName,
num_sets = numSets, num_sets = numSets,
rest_of_sets = restSets rest_of_sets = restSets,
trainingId = 0
) )
exerciseViewModel.insert(newExercise) exerciseViewModel.insert(newExercise)
Toast.makeText(this, "Упражнение сохранено", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Упражнение сохранено", Toast.LENGTH_SHORT).show()

View File

@ -7,6 +7,7 @@ import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
@ -15,18 +16,30 @@ import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.timert.data.adapter.ExerciseAdapter import com.example.timert.data.adapter.ExerciseAdapter
import com.example.timert.data.entity.Training
import com.example.timert.data.viewModel.ExerciseViewModel import com.example.timert.data.viewModel.ExerciseViewModel
import com.example.timert.data.viewModel.TrainingViewModel
import com.example.timert.data.viewModel.WorkoutViewModel
class CreatingTraining : AppCompatActivity() { class CreatingTraining : AppCompatActivity() {
private lateinit var viewModel: ExerciseViewModel private lateinit var viewModel: ExerciseViewModel
private lateinit var name_training: EditText
private lateinit var numSets: EditText
private lateinit var restSets: EditText
private var isSave = false private var isSave = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
setContentView(R.layout.activity_creating_training) setContentView(R.layout.activity_creating_training)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
@ -36,6 +49,10 @@ class CreatingTraining : AppCompatActivity() {
)[ExerciseViewModel::class.java] )[ExerciseViewModel::class.java]
name_training = findViewById(R.id.name_training)
numSets = findViewById(R.id.numbers_of_sets)
restSets = findViewById(R.id.rest_sets)
val adapter = ExerciseAdapter { id -> val adapter = ExerciseAdapter { id ->
viewModel.deleteExerciseById(id) viewModel.deleteExerciseById(id)
} }
@ -50,6 +67,13 @@ class CreatingTraining : AppCompatActivity() {
adapter.setExercises(it) adapter.setExercises(it)
} }
} }
val trainingViewModel = ViewModelProvider(
this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
)[TrainingViewModel::class.java]
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
@ -57,22 +81,46 @@ class CreatingTraining : AppCompatActivity() {
} }
val buttonSave: Button = findViewById(R.id.btn_save) val buttonSave: Button = findViewById(R.id.btn_save)
buttonSave.setOnClickListener { buttonSave.setOnClickListener {
val name = name_training.text.toString()
val numS = numSets.text.toString()
val resS = restSets.text.toString()
if (name.isBlank() || numS.isBlank() || resS.isBlank()) {
Toast.makeText(this, "Заполните все поля", Toast.LENGTH_SHORT).show()
} else {
val sets = numS.toIntOrNull()
val rest = resS.toIntOrNull()
if (sets == null || rest == null) {
Toast.makeText(this, "Неверный формат чисел", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
val newTraining = Training(
name = name,
numSets = sets,
restBetweenSets = rest)
trainingViewModel.insertTrainingAndLinkExercises(newTraining)
Toast.makeText(this, "Тренировка сохранена", Toast.LENGTH_SHORT).show()
isSave = true isSave = true
val intent = Intent(this, MainActivity::class.java) }
startActivity(intent)
} }
val timeInputRest: EditText = findViewById(R.id.rest_sets)
val btnPlusTime: ImageView = findViewById(R.id.add_res) val btnPlusTime: ImageView = findViewById(R.id.add_res)
val btnMinusTime: ImageView = findViewById(R.id.del_res) val btnMinusTime: ImageView = findViewById(R.id.del_res)
val setsInput: EditText = findViewById(R.id.numbers_of_sets)
val btnPlusSets: ImageView = findViewById(R.id.add_set) val btnPlusSets: ImageView = findViewById(R.id.add_set)
val btnMinusSets: ImageView = findViewById(R.id.del_set) val btnMinusSets: ImageView = findViewById(R.id.del_set)
setupPlusMinus(timeInputRest, btnPlusTime, btnMinusTime, minValue = 5, maxValue = 600) setupPlusMinus(restSets, btnPlusTime, btnMinusTime, minValue = 5, maxValue = 600)
setupPlusMinus(setsInput, btnPlusSets, btnMinusSets, minValue = 1, maxValue = 20) setupPlusMinus(numSets, btnPlusSets, btnMinusSets, minValue = 1, maxValue = 20)
val button_on_main: Button = findViewById(R.id.btn_on_main) val button_on_main: Button = findViewById(R.id.btn_on_main)
button_on_main.setOnClickListener { button_on_main.setOnClickListener {
if(isSave==false){ if(isSave==false){

View File

@ -26,5 +26,11 @@ class History : AppCompatActivity() {
recyclerViewHistory.layoutManager = LinearLayoutManager(this) recyclerViewHistory.layoutManager = LinearLayoutManager(this)
val button_on_main: Button = findViewById(R.id.btn_on_main)
button_on_main.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
} }
} }

View File

@ -2,18 +2,26 @@ package com.example.timert
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.widget.Button import android.widget.Button
import android.widget.Toast import android.widget.Toast
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.timert.com.example.timert.data.adapter.WorkoutAdapter
import com.example.timert.data.TrainingItem
import com.example.timert.data.adapter.TrainingAdapter
import com.example.timert.data.viewModel.TrainingViewModel
import com.example.timert.data.viewModel.WorkoutViewModel
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var adapter: TrainingAdapter
private lateinit var workoutViewModel: WorkoutViewModel
private lateinit var trainingViewModel: TrainingViewModel
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -24,6 +32,44 @@ class MainActivity : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets insets
} }
adapter = TrainingAdapter(
onDeleteWorkout = { id -> workoutViewModel.deleteWorkoutById(id) },
onDeleteTraining = { id -> trainingViewModel.deleteTrainingById(id) }
)
val recyclerView = findViewById<RecyclerView>(R.id.workout)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
workoutViewModel = ViewModelProvider(this)[WorkoutViewModel::class.java]
trainingViewModel = ViewModelProvider(this)[TrainingViewModel::class.java]
// объединяем данные вручную
val combinedList = mutableListOf<TrainingItem>()
workoutViewModel.allWorkouts.observe(this) { workouts ->
combinedList.clear()
combinedList.addAll(workouts.map { TrainingItem.WorkoutItem(it) })
trainingViewModel.allTrainingsWithExercises.value?.let { trainings ->
combinedList.addAll(trainings.map { TrainingItem.TrainingWithExercisesItem(it) })
}
adapter.submitList(combinedList.toList())
}
trainingViewModel.allTrainingsWithExercises.observe(this) { trainings ->
combinedList.clear()
workoutViewModel.allWorkouts.value?.let { workouts ->
combinedList.addAll(workouts.map { TrainingItem.WorkoutItem(it) })
}
combinedList.addAll(trainings.map {TrainingItem.TrainingWithExercisesItem(it) })
adapter.submitList(combinedList.toList())
}
// Кнопки главной формы: // Кнопки главной формы:
val settingsButton: Button = findViewById(R.id.settingsButton) val settingsButton: Button = findViewById(R.id.settingsButton)

View File

@ -2,7 +2,7 @@ package com.example.timert
import android.app.Application import android.app.Application
import androidx.room.Room import androidx.room.Room
import com.example.timert.AppDatabase import com.example.timert.com.example.timert.data.database.AppDatabase
class MyApplication : Application() { class MyApplication : Application() {
companion object { companion object {

View File

@ -0,0 +1,9 @@
package com.example.timert.data
import com.example.timert.com.example.timert.data.entity.Workout
import com.example.timert.data.entity.Training
sealed class TrainingItem {
data class WorkoutItem(val workout: Workout) : TrainingItem()
data class TrainingWithExercisesItem(val trainingWithExercise: trainingWithExercise) : TrainingItem()
}

View File

@ -1,18 +1,13 @@
package com.example.timert.data.adapter package com.example.timert.data.adapter
import android.content.Context
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.Button
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.timert.R import com.example.timert.R
import com.example.timert.data.entity.Exercise import com.example.timert.data.entity.Exercise
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
//class ExerciseAdapter internal constructor(context: Context):RecyclerView.Adapter<ExerciseAdapter.ExerciseViewHolder>(){ //class ExerciseAdapter internal constructor(context: Context):RecyclerView.Adapter<ExerciseAdapter.ExerciseViewHolder>(){

View File

@ -0,0 +1,80 @@
package com.example.timert.data.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageButton
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.timert.R
import com.example.timert.com.example.timert.data.entity.Workout
import com.example.timert.data.TrainingItem
import com.example.timert.data.entity.Training
import com.example.timert.data.trainingWithExercise
class TrainingAdapter( private val onDeleteWorkout: (Int) -> Unit,
private val onDeleteTraining: (Int) -> Unit
) : ListAdapter<TrainingItem, RecyclerView.ViewHolder>(DiffCallback()) {
companion object {
private const val TYPE_WORKOUT = 0
private const val TYPE_TRAINING_WITH_EXERCISES = 1
}
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is TrainingItem.WorkoutItem -> TYPE_WORKOUT
is TrainingItem.TrainingWithExercisesItem -> TYPE_TRAINING_WITH_EXERCISES
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.training_item_layout, parent, false) // один layout
return when (viewType) {
TYPE_WORKOUT -> WorkoutViewHolder(view, onDeleteWorkout)
TYPE_TRAINING_WITH_EXERCISES -> TrainingViewHolder(view, onDeleteTraining)
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = getItem(position)) {
is TrainingItem.WorkoutItem -> (holder as WorkoutViewHolder).bind(item.workout)
is TrainingItem.TrainingWithExercisesItem -> (holder as TrainingViewHolder).bind(item.trainingWithExercise)
}
}
class WorkoutViewHolder(itemView: View, private val onDelete: (Int) -> Unit) :
RecyclerView.ViewHolder(itemView) {
fun bind(workout: Workout) {
itemView.findViewById<TextView>(R.id.training_text).text = workout.name
itemView.findViewById<ImageButton>(R.id.deleteButtonTraining).setOnClickListener {
onDelete(workout.id)
}
}
}
class TrainingViewHolder(itemView: View, private val onDelete: (Int) -> Unit) :
RecyclerView.ViewHolder(itemView) {
fun bind(trainingWithExercise: trainingWithExercise) {
itemView.findViewById<TextView>(R.id.training_text).text = trainingWithExercise.training.name
itemView.findViewById<ImageButton>(R.id.deleteButtonTraining).setOnClickListener {
onDelete(trainingWithExercise.training.id)
}
}
}
class DiffCallback : DiffUtil.ItemCallback<TrainingItem>() {
override fun areItemsTheSame(oldItem: TrainingItem, newItem: TrainingItem): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: TrainingItem, newItem: TrainingItem): Boolean {
return oldItem == newItem
}
}
}

View File

@ -0,0 +1,48 @@
package com.example.timert.com.example.timert.data.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.timert.R
import com.example.timert.com.example.timert.data.entity.Workout
class WorkoutAdapter internal constructor(private val onDeleteClick: (Int) -> Unit
) : RecyclerView.Adapter<WorkoutAdapter.WorkoutViewHolder>() {
private var workouts: List<Workout> = emptyList()
inner class WorkoutViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textViewName: TextView = itemView.findViewById(R.id.training_text)
val deleteButton: ImageButton = itemView.findViewById(R.id.deleteButtonTraining)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.training_item_layout, parent, false)
return WorkoutViewHolder(itemView)
}
override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
val currentItem = workouts[position]
holder.textViewName.text =
"${currentItem.name}"
holder.deleteButton.setOnClickListener {
onDeleteClick(currentItem.id)
}
}
override fun getItemCount() = workouts.size
fun setWorkouts(workouts: List<Workout>) {
this.workouts = workouts
notifyDataSetChanged()
}
}

View File

@ -6,11 +6,14 @@ import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import androidx.room.Transaction
import com.example.timert.data.entity.Exercise import com.example.timert.data.entity.Exercise
@Dao @Dao
interface ExerciseDao { interface ExerciseDao {
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(exercise: Exercise) suspend fun insert(exercise: Exercise)
@ -18,9 +21,9 @@ interface ExerciseDao {
fun getExercise(): LiveData<List<Exercise>> fun getExercise(): LiveData<List<Exercise>>
//@Delete
// suspend fun delete(exercise: Exercise)
@Query("DELETE FROM exercise_table WHERE id = :id") @Query("DELETE FROM exercise_table WHERE id = :id")
suspend fun deleteById(id: Int) suspend fun deleteById(id: Int)
@Query("UPDATE exercise_table SET trainingId = :newTrainingId WHERE trainingId = 0")
suspend fun updateExercisesWithTrainingId(newTrainingId: Int)
} }

View File

@ -0,0 +1,41 @@
package com.example.timert.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.example.timert.data.entity.Training
import com.example.timert.data.trainingWithExercise
@Dao
interface TrainingDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTraining(training: Training) : Long
@Query("SELECT * FROM Training WHERE id = :trainingId")
fun getTrainingWithExercise(trainingId: Int): LiveData<trainingWithExercise>
@Delete
fun deleteTraining(training: Training)
@Query("SELECT * FROM training")
fun getAllTrainings(): LiveData<List<Training>>
@Query("DELETE FROM training WHERE id = :id")
suspend fun deleteById(id: Int)
@Query("SELECT * FROM training WHERE id = :trainingId")
fun getTrainingWithExercises(trainingId: Int): LiveData<trainingWithExercise>
@Transaction
@Query("SELECT * FROM training")
fun getAllTrainingsWithExercises(): LiveData<List<trainingWithExercise>>
@Transaction
@Query("SELECT * FROM training")
fun getTrainingsWithExercises(): LiveData<List<trainingWithExercise>>
}

View File

@ -1,22 +1,29 @@
package com.example.timert package com.example.timert.com.example.timert.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import androidx.room.Update import androidx.room.Update
import com.example.timert.com.example.timert.data.entity.Workout
import com.example.timert.data.entity.Exercise
@Dao @Dao
interface WorkoutDao { interface WorkoutDao {
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertWorkout(workout: Workout): Long suspend fun insertWorkout(workout: Workout): Long
@Query("SELECT * FROM workouts") @Query("SELECT * FROM workouts")
suspend fun getAllWorkouts(): List<Workout> fun getAllWorkouts(): LiveData<List<Workout>>
@Query("SELECT * FROM workouts WHERE id = :workoutId") @Query("SELECT * FROM workouts WHERE id = :workoutId")
suspend fun getWorkoutById(workoutId: Int): Workout? suspend fun getWorkoutById(workoutId: Int): Workout?
@Update @Update
suspend fun updateWorkout(workout: Workout) suspend fun updateWorkout(workout: Workout)
@Query("DELETE FROM workouts WHERE id = :id")
suspend fun deleteById(id: Int)
} }

View File

@ -0,0 +1,43 @@
package com.example.timert.com.example.timert.data.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.timert.com.example.timert.data.dao.WorkoutDao
import com.example.timert.com.example.timert.data.entity.Workout
import com.example.timert.data.dao.ExerciseDao
import com.example.timert.data.dao.TrainingDao
import com.example.timert.data.entity.Exercise
import com.example.timert.data.entity.Training
import kotlinx.coroutines.CoroutineScope
@Database(entities = [Workout::class, Exercise::class, Training::class], version = 3, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun workoutDao(): WorkoutDao
abstract fun trainingDao(): TrainingDao
abstract fun exerciseDao(): ExerciseDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"workout_database"
)
//.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
return instance
}
}
}
}

View File

@ -1,61 +0,0 @@
package com.example.timert.data.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.timert.data.dao.ExerciseDao
import com.example.timert.data.entity.Exercise
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Database(entities = [Exercise::class], version = 1, exportSchema = false)
abstract class ExerciseDatabase:RoomDatabase(){
abstract fun exerciseDao():ExerciseDao
// private class ExerciseDatabaseCallback (private val scope: CoroutineScope) : RoomDatabase.Callback(){
//override fun onOpen(db: SupportSQLiteDatabase) {
// super.onOpen(db)
// INSTANCE?.let { database ->
// scope.launch {
// populateDatabase(database.exerciseDao())
// }
// }
// }
//suspend fun populateDatabase(exerciseDao: ExerciseDao) {
// Delete all content here.
//exerciseDao.deleteAll()
// Add sample words.
//var exercise = Exercise(0, "training", 10, 45 )
// exerciseDao.insert(exercise)
// TODO: Add your own words!
// }
//}
companion object {
@Volatile
private var INSTANCE: ExerciseDatabase? = null
fun getDatabase(context: Context,
scope: CoroutineScope
): ExerciseDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ExerciseDatabase::class.java,
"exercise_database"
)
//.addCallback(ExerciseDatabaseCallback(scope))
.build()
INSTANCE = instance
return instance
}
}
}
}

View File

@ -1,11 +1,15 @@
package com.example.timert.data.entity package com.example.timert.data.entity
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "exercise_table") @Entity(tableName = "exercise_table",
indices = [Index("trainingId")])
data class Exercise(@PrimaryKey(autoGenerate = true) val id: Int = 0, data class Exercise(@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name_exercise: String, val name_exercise: String,
val num_sets: Int, val num_sets: Int,
val rest_of_sets: Int) val rest_of_sets: Int,
val trainingId: Int = 0)

View File

@ -0,0 +1,12 @@
package com.example.timert.data.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "training")
data class Training(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name: String,
val numSets: Int,
val restBetweenSets: Int
)

View File

@ -1,17 +1,16 @@
package com.example.timert package com.example.timert.com.example.timert.data.entity
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "workouts") @Entity(tableName = "workouts")
data class Workout( data class Workout(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true) val id: Int = 0,
val id: Int = 0,
val name: String, val name: String,
val numApproaches: Int, val numApproaches: Int,
val numExercises: Int, val numExercises: Int,
val restBetweenExercises: Int, val restBetweenExercises: Int,
val restBetweenApproaches: Int, val restBetweenApproaches: Int,
val exerciseDuration: Int, val exerciseDuration: Int,
val startTime: Long? = null, //val startTime: Long? = null,
val endTime: Long? = null // val endTime: Long? = null
) )

View File

@ -0,0 +1,23 @@
package com.example.timert.data.repository
import androidx.lifecycle.LiveData
import com.example.timert.data.dao.TrainingDao
import com.example.timert.data.entity.Training
import com.example.timert.data.trainingWithExercise
class TrainingRepository(private val trainingDao: TrainingDao) {
val allTrainings: LiveData<List<Training>> = trainingDao.getAllTrainings()
val allTrainingsWithExercises: LiveData<List<trainingWithExercise>> = trainingDao.getTrainingsWithExercises()
suspend fun insert(training: Training): Long {
return trainingDao.insertTraining(training)
}
suspend fun delete(training: Training) = trainingDao.deleteTraining(training)
suspend fun deleteTrainingById(id: Int) {
trainingDao.deleteById(id)
}
}

View File

@ -0,0 +1,17 @@
package com.example.timert.data.repository
import androidx.lifecycle.LiveData
import com.example.timert.com.example.timert.data.dao.WorkoutDao
import com.example.timert.com.example.timert.data.entity.Workout
class WorkoutRepository (private val workoutDao: WorkoutDao){
val allWorkout: LiveData<List<Workout>> = workoutDao.getAllWorkouts()
suspend fun insert(workout: Workout) {
workoutDao.insertWorkout(workout)
}
suspend fun deleteWorkoutById(id: Int) {
workoutDao.deleteById(id)
}
}

View File

@ -0,0 +1,16 @@
package com.example.timert.data
import androidx.lifecycle.LiveData
import androidx.room.Embedded
import androidx.room.Relation
import com.example.timert.data.entity.Exercise
import com.example.timert.data.entity.Training
data class trainingWithExercise (
@Embedded val training: Training,
@Relation(
parentColumn = "id",
entityColumn = "trainingId"
)
val exercises: List<Exercise>
)

View File

@ -4,7 +4,7 @@ import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.timert.data.database.ExerciseDatabase import com.example.timert.com.example.timert.data.database.AppDatabase
import com.example.timert.data.entity.Exercise import com.example.timert.data.entity.Exercise
import com.example.timert.data.repository.ExerciseRepository import com.example.timert.data.repository.ExerciseRepository
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -14,7 +14,7 @@ class ExerciseViewModel(application: Application):AndroidViewModel(application){
val allExercise: LiveData<List<Exercise>> val allExercise: LiveData<List<Exercise>>
init{ init{
val exercisesDao = ExerciseDatabase.getDatabase(application, viewModelScope).exerciseDao() val exercisesDao = AppDatabase.getDatabase(application).exerciseDao()
repository = ExerciseRepository(exercisesDao) repository = ExerciseRepository(exercisesDao)
allExercise = repository.allExercise allExercise = repository.allExercise
} }

View File

@ -0,0 +1,50 @@
package com.example.timert.data.viewModel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import com.example.timert.com.example.timert.data.database.AppDatabase
import com.example.timert.data.entity.Training
import com.example.timert.data.repository.TrainingRepository
import com.example.timert.data.trainingWithExercise
import kotlinx.coroutines.launch
class TrainingViewModel (application: Application): AndroidViewModel(application){
val allWorkouts: LiveData<List<Training>>
private val trainingDao = AppDatabase.getDatabase(application).trainingDao()
private val repository = TrainingRepository(trainingDao)
val allTrainings: LiveData<List<Training>> = repository.allTrainings
val allTrainingsWithExercises: LiveData<List<trainingWithExercise>> = repository.allTrainingsWithExercises
init{
val trainingDao = AppDatabase.getDatabase(application).trainingDao()
allWorkouts = repository.allTrainings
}
fun insert(training: Training) = viewModelScope.launch {
repository.insert(training)
}
fun deleteTrainingById(id: Int) = viewModelScope.launch {
repository.deleteTrainingById(id)
}
fun delete(training: Training) = viewModelScope.launch {
repository.delete(training)
}
fun insertTrainingAndLinkExercises(training: Training) {
viewModelScope.launch {
val newId = repository.insert(training) // возвращает id
// теперь обновляем trainingId в упражнениях
AppDatabase.getDatabase(getApplication()).exerciseDao()
.updateExercisesWithTrainingId(newId.toInt())
}
}
}

View File

@ -0,0 +1,28 @@
package com.example.timert.data.viewModel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import com.example.timert.com.example.timert.data.database.AppDatabase
import com.example.timert.com.example.timert.data.entity.Workout
import com.example.timert.data.repository.WorkoutRepository
import kotlinx.coroutines.launch
class WorkoutViewModel(application: Application):AndroidViewModel(application){
private val repository: WorkoutRepository
val allWorkouts: LiveData<List<Workout>>
init{
val workoutDao = AppDatabase.getDatabase(application).workoutDao()
repository = WorkoutRepository(workoutDao)
allWorkouts = repository.allWorkout
}
fun insert(workout: Workout) = viewModelScope.launch {
repository.insert(workout)
}
fun deleteWorkoutById(id: Int) = viewModelScope.launch {
repository.deleteWorkoutById(id)
}
}

View File

@ -31,20 +31,32 @@
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:ems="10" android:ems="10"
android:inputType="text" android:inputType="text"
android:text="Тренировка 1" android:text="Моя тренировка"
android:textAlignment="center" android:textAlignment="center"
android:textSize="20sp" /> android:textSize="20sp" />
</LinearLayout> </LinearLayout>
<ScrollView
android:id="@+id/scrollView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/frameLayout2"
app:layout_constraintTop_toBottomOf="@+id/linearLayout"
tools:layout_editor_absoluteX="9dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout <LinearLayout
android:id="@+id/setting_training" android:id="@+id/setting_training"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="400dp" android:layout_height="match_parent"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:orientation="vertical" android:orientation="vertical">
app:layout_constraintTop_toBottomOf="@+id/linearLayout"
tools:layout_editor_absoluteX="16dp">
<TextView <TextView
android:id="@+id/textView6" android:id="@+id/textView6"
@ -88,6 +100,48 @@
app:srcCompat="@drawable/ic_add_24px" /> app:srcCompat="@drawable/ic_add_24px" />
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/textView14"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Количество упражнений"
android:textAlignment="center"
android:textSize="24sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/del_set4"
android:layout_width="wrap_content"
android:layout_height="37dp"
android:layout_gravity="center"
android:layout_weight="1"
app:srcCompat="@drawable/ic_remove_24px" />
<EditText
android:id="@+id/num_exercise"
android:layout_width="3dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:ems="10"
android:gravity="center"
android:inputType="number"
android:text="1"
android:textSize="26sp" />
<ImageView
android:id="@+id/add_set4"
android:layout_width="wrap_content"
android:layout_height="37dp"
android:layout_gravity="center"
android:layout_weight="1"
app:srcCompat="@drawable/ic_add_24px" />
</LinearLayout>
<TextView <TextView
android:id="@+id/textView8_all2" android:id="@+id/textView8_all2"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -98,7 +152,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <ImageView
@ -217,12 +271,15 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout>
</ScrollView>
<FrameLayout <FrameLayout
android:id="@+id/frameLayout2"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@+id/setting_training" app:layout_constraintBottom_toTopOf="@+id/linearLayout4"
tools:layout_editor_absoluteX="0dp"> tools:layout_editor_absoluteX="0dp">
<Button <Button
@ -239,9 +296,10 @@
</FrameLayout> </FrameLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="60dp"
android:layout_marginBottom="35dp" android:layout_marginBottom="8dp"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@ -18,7 +18,7 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" /> app:layout_constraintVertical_bias="1.0" />
<Button <Button
android:id="@+id/settingsButton" android:id="@+id/settingsButton"
@ -99,4 +99,16 @@
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/workout"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/newTemplateCardView"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp">
<LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/green_rectangle"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingBottom="8dp">
<TextView
android:id="@+id/training_text"
android:layout_width="353dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="Тренировка"
android:textColor="#000000"
android:textSize="18sp" />
<ImageButton
android:id="@+id/deleteButtonTraining"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@android:drawable/ic_menu_delete" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="Workout Name"
android:textSize="18sp" />
</androidx.cardview.widget.CardView>