diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f2c6a58..b84e54d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,7 +1,8 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) - id("kotlin-kapt") + id("org.jetbrains.kotlin.kapt") + id("androidx.room") } android { @@ -34,6 +35,13 @@ android { kotlinOptions { jvmTarget = "11" } + + buildFeatures { + //noinspection WrongGradleMethod + room { + schemaDirectory("$projectDir/schemas") + } + } } dependencies { @@ -46,13 +54,13 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) - implementation("androidx.room:room-runtime:2.7.1") - implementation("androidx.room:room-ktx:2.7.1") - kapt ("androidx.room:room-compiler:2.7.1") - implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") - implementation ("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0") + // Room dependencies + implementation("androidx.room:room-runtime:2.7.1") // Замените на вашу версию + implementation("androidx.room:room-ktx:2.7.1") // Замените на вашу версию + kapt("androidx.room:room-compiler:2.7.1") // Замените на вашу версию - - -} \ No newline at end of file + // Lifecycle dependencies + implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") // Замените на вашу версию + implementation ("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0") // Замените на вашу версию +} diff --git a/app/schemas/com.example.timert.AppDatabase/1.json b/app/schemas/com.example.timert.AppDatabase/1.json new file mode 100644 index 0000000..15d2a28 --- /dev/null +++ b/app/schemas/com.example.timert.AppDatabase/1.json @@ -0,0 +1,77 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "87cf8dcd07bc0b2c0a8d52dbb0eca913", + "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, `startTime` INTEGER, `endTime` INTEGER)", + "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 + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "INTEGER" + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "INTEGER" + } + ], + "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, '87cf8dcd07bc0b2c0a8d52dbb0eca913')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 65a73a0..b4f691b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> <application + android:name=".MyApplication" android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" diff --git a/app/src/main/java/AppDatabase.kt b/app/src/main/java/AppDatabase.kt new file mode 100644 index 0000000..9269316 --- /dev/null +++ b/app/src/main/java/AppDatabase.kt @@ -0,0 +1,9 @@ +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 +} \ No newline at end of file diff --git a/app/src/main/java/Workout.kt b/app/src/main/java/Workout.kt new file mode 100644 index 0000000..3dd0900 --- /dev/null +++ b/app/src/main/java/Workout.kt @@ -0,0 +1,17 @@ +package com.example.timert +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "workouts") +data class Workout( + @PrimaryKey(autoGenerate = true) + val id: Int = 0, + val name: String, + val numApproaches: Int, + val numExercises: Int, + val restBetweenExercises: Int, + val restBetweenApproaches: Int, + val exerciseDuration: Int, + val startTime: Long? = null, + val endTime: Long? = null +) \ No newline at end of file diff --git a/app/src/main/java/WorkoutAdapter.kt b/app/src/main/java/WorkoutAdapter.kt new file mode 100644 index 0000000..63a62da --- /dev/null +++ b/app/src/main/java/WorkoutAdapter.kt @@ -0,0 +1,27 @@ +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 +} \ No newline at end of file diff --git a/app/src/main/java/WorkoutDao.kt b/app/src/main/java/WorkoutDao.kt new file mode 100644 index 0000000..26a43f6 --- /dev/null +++ b/app/src/main/java/WorkoutDao.kt @@ -0,0 +1,22 @@ +package com.example.timert + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update + +@Dao +interface WorkoutDao { + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insertWorkout(workout: Workout): Long + + @Query("SELECT * FROM workouts") + suspend fun getAllWorkouts(): List<Workout> + + @Query("SELECT * FROM workouts WHERE id = :workoutId") + suspend fun getWorkoutById(workoutId: Int): Workout? + + @Update + suspend fun updateWorkout(workout: Workout) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/timert/History.kt b/app/src/main/java/com/example/timert/History.kt index 2bfbb68..6642667 100644 --- a/app/src/main/java/com/example/timert/History.kt +++ b/app/src/main/java/com/example/timert/History.kt @@ -7,27 +7,24 @@ import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat -import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.example.timert.data.adapter.ExerciseAdapter -import com.example.timert.data.viewModel.ExerciseViewModel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers class History : AppCompatActivity() { + private lateinit var recyclerViewHistory: RecyclerView + private val coroutineScope = CoroutineScope(Dispatchers.IO) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() + setContentView(R.layout.activity_history) + + recyclerViewHistory = findViewById(R.id.recyclerViewHistory) + recyclerViewHistory.layoutManager = LinearLayoutManager(this) + - 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 - } - val button_on_main: Button = findViewById(R.id.btn_on_main) - button_on_main.setOnClickListener { - val intent = Intent(this, MainActivity::class.java) - startActivity(intent) - } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/timert/MainActivity.kt b/app/src/main/java/com/example/timert/MainActivity.kt index 2f485c1..b607269 100644 --- a/app/src/main/java/com/example/timert/MainActivity.kt +++ b/app/src/main/java/com/example/timert/MainActivity.kt @@ -2,7 +2,7 @@ package com.example.timert import android.content.Intent import android.os.Bundle -import android.view.View +import android.util.Log import android.widget.Button import android.widget.Toast import androidx.activity.enableEdgeToEdge @@ -10,7 +10,11 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat + class MainActivity : AppCompatActivity() { + + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -50,9 +54,8 @@ class MainActivity : AppCompatActivity() { //TODO: Intent для открытия Activity создания шаблона (форма 7) val intent = Intent(this, History::class.java) startActivity(intent) - - } + // ---- ROOM TEST ---- } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/timert/MyApplication.kt b/app/src/main/java/com/example/timert/MyApplication.kt new file mode 100644 index 0000000..1606441 --- /dev/null +++ b/app/src/main/java/com/example/timert/MyApplication.kt @@ -0,0 +1,20 @@ +package com.example.timert + +import android.app.Application +import androidx.room.Room +import com.example.timert.AppDatabase + +class MyApplication : Application() { + companion object { + lateinit var database: AppDatabase + } + + override fun onCreate() { + super.onCreate() + database = Room.databaseBuilder( + applicationContext, + AppDatabase::class.java, + "workout_database" + ).build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/timert/timer.kt b/app/src/main/java/com/example/timert/timer.kt index 26277ba..bd6e7dd 100644 --- a/app/src/main/java/com/example/timert/timer.kt +++ b/app/src/main/java/com/example/timert/timer.kt @@ -2,10 +2,9 @@ package com.example.timert import android.app.AlertDialog import android.content.Intent -import android.media.Image +import android.media.MediaPlayer import android.os.Bundle import android.os.CountDownTimer -import android.widget.Button import android.widget.ImageButton import android.widget.TextView import androidx.activity.enableEdgeToEdge @@ -28,6 +27,14 @@ class timer : AppCompatActivity() { private var exerciseDuration = 45 // например, 45 секунд упражнение private var currentTimer: CountDownTimer? = null private var timeLeftInMillis: Long = 0 + + // Объявляем переменные для MediaPlayer + private var startWorkoutSound: MediaPlayer? = null + private var workSound: MediaPlayer? = null + private var startRestSound: MediaPlayer? = null + private var restSound: MediaPlayer? = null + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -47,6 +54,12 @@ class timer : AppCompatActivity() { restBetweenApproaches = intent.getIntExtra("restBetweenApproaches", restBetweenApproaches) exerciseDuration = intent.getIntExtra("exerciseDuration", exerciseDuration) + // Инициализируем MediaPlayer + startWorkoutSound = MediaPlayer.create(this, R.raw.sound1) + workSound = MediaPlayer.create(this, R.raw.sound1) + startRestSound = MediaPlayer.create(this, R.raw.sound2) + restSound = MediaPlayer.create(this, R.raw.sound3) + startTraining() val button: ImageButton = findViewById(R.id.stop) @@ -106,15 +119,18 @@ class timer : AppCompatActivity() { statusText.text = "Тренировка завершена!" rootLayout.setBackgroundResource(R.drawable.blue_gradient) timerText.text = "00:00" + // Здесь должен быть звук завершения тренировки, если нужно return } - + statusSet.text = "Подход № $currentApproach" var currentExercise = 1 fun nextExercise() { if (currentExercise > numExercises) { statusText.text = "Отдых между подходами" rootLayout.setBackgroundResource(R.drawable.green_gradient) + // Звук перед началом отдыха между подходами + startRestSound?.start() startRest(restBetweenApproaches) { currentApproach++ nextApproach() @@ -122,23 +138,28 @@ class timer : AppCompatActivity() { return } rootLayout.setBackgroundResource(R.drawable.gradient_pink) - statusText.text="Работа" - + statusText.text = "Работа" statusExercise.text = "$currentExercise / $numExercises" - statusSet.text="$currentApproach" + statusSet.text = "$currentApproach" + + // Звук перед началом упражнения + workSound?.start() + startTimer(exerciseDuration) { statusText.text = "Отдых" rootLayout.setBackgroundResource(R.drawable.green_gradient) + // Звук перед началом отдыха между упражнениями + restSound?.start() startRest(restBetweenExercises) { currentExercise++ nextExercise() } } } - + // Звук перед началом подхода + startWorkoutSound?.start() nextExercise() } - nextApproach() } @@ -162,7 +183,6 @@ class timer : AppCompatActivity() { override fun onTick(millisUntilFinished: Long) { timerText.text = "${millisUntilFinished / 1000}" statusText.text = "Отдых" - } override fun onFinish() { @@ -170,5 +190,18 @@ class timer : AppCompatActivity() { } }.start() } + override fun onDestroy() { + super.onDestroy() + currentTimer?.cancel() + // Освобождаем ресурсы MediaPlayer + startWorkoutSound?.release() + workSound?.release() + startRestSound?.release() + restSound?.release() + startWorkoutSound = null + workSound = null + startRestSound = null + restSound = null + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml index d18ee74..99c53a9 100644 --- a/app/src/main/res/layout/activity_history.xml +++ b/app/src/main/res/layout/activity_history.xml @@ -8,6 +8,15 @@ android:background="@drawable/gradient_purpure" tools:context=".History"> + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recyclerViewHistory" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + <TextView android:id="@+id/textView4" android:layout_width="match_parent" diff --git a/app/src/main/res/layout/workout_item.xml b/app/src/main/res/layout/workout_item.xml new file mode 100644 index 0000000..d06f4d7 --- /dev/null +++ b/app/src/main/res/layout/workout_item.xml @@ -0,0 +1,17 @@ +<?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> \ No newline at end of file diff --git a/app/src/main/res/raw/sound1.mp3 b/app/src/main/res/raw/sound1.mp3 new file mode 100644 index 0000000..825b1da Binary files /dev/null and b/app/src/main/res/raw/sound1.mp3 differ diff --git a/app/src/main/res/raw/sound2.mp3 b/app/src/main/res/raw/sound2.mp3 new file mode 100644 index 0000000..b6562a7 Binary files /dev/null and b/app/src/main/res/raw/sound2.mp3 differ diff --git a/app/src/main/res/raw/sound3.mp3 b/app/src/main/res/raw/sound3.mp3 new file mode 100644 index 0000000..8362c2b Binary files /dev/null and b/app/src/main/res/raw/sound3.mp3 differ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2693823..6361eed 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.9.2" +agp = "8.10.0" kotlin = "2.0.21" coreKtx = "1.16.0" junit = "4.13.2" diff --git a/settings.gradle.kts b/settings.gradle.kts index 7bb073d..5b0b124 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,12 @@ pluginManagement { mavenCentral() gradlePluginPortal() } + plugins { + id("com.android.application") version "8.3.2" apply false // Замените на вашу версию + id("org.jetbrains.kotlin.android") version "1.9.0" apply false // Замените на вашу версию Kotlin + id("org.jetbrains.kotlin.kapt") version "1.9.0" apply false // замените на вашу версию Kotlin + id("androidx.room") version "2.7.1" apply false // Добавьте эту строку, заменив на вашу версию Room + } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) @@ -20,5 +26,4 @@ dependencyResolutionManagement { } rootProject.name = "TimerT" -include(":app") - \ No newline at end of file +include(":app") \ No newline at end of file