0% found this document useful (0 votes)
28 views

Manual Tecnico

dddass

Uploaded by

Luis ツ
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views

Manual Tecnico

dddass

Uploaded by

Luis ツ
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 10

Manual Técnico de la Aplicación "!

A
caminar!"
Introducción
Este manual técnico proporciona una guía detallada sobre cómo se desarrolló la aplicación "!A
caminar!" utilizando Android Studio. La aplicación se centra en contar los pasos del usuario,
almacenar datos, utilizar la cámara para tomar fotos y vídeos, así como aprovechar los sensores del
móvil para el conteo de pasos en tiempo real. El desarrollo se realizó utilizando el lenguaje de
programación Kotlin.

Estructura del Proyecto


El proyecto "!A caminar!" está estructurado en varios archivos:

● activity_main.xml: Este archivo contiene el diseño de la interfaz de usuario de la pantalla principal de la


aplicación. Utiliza ConstraintLayout para organizar los elementos de manera flexible en la pantalla. Por
ejemplo, el TextView tv_stepsTaken muestra el número de pasos dados, mientras que los botones
flotantes (fab_save, fab_camera, fab_history, fab_reset) permiten realizar acciones como
guardar los pasos, tomar fotos, ver el historial y restablecer el contador.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<!-- Text View for the motivational message -->


<TextView
android:id="@+id/tv_motivation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="¡Comienza a caminar!"
android:textSize="30sp"
android:textColor="@color/black"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@+id/steps"
android:layout_marginTop="16dp" />

<!-- Text View for the "Steps" displayed -->


<TextView
android:id="@+id/steps"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="290dp"
android:text="Pasos"
android:textSize="45sp"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<!-- Text View for the step count -->


<TextView
android:id="@+id/tv_stepsTaken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="30dp"
android:text="0"
android:textSize="37sp"
android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/steps" />

<!-- Image View for the circle -->


<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="264dp"
android:background="@drawable/circle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<!-- Floating Action Button for saving steps -->


<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="@string/fab_save"
android:src="@drawable/ic_save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_stepsTaken" />

<!-- Floating Action Button for camera -->


<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_camera"
app:layout_constraintEnd_toStartOf="@id/fab_history"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/fab_camera"/>

<!-- Floating Action Button for history -->


<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_trophy"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/fab_history" />

<!-- Floating Action Button for reset -->


<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_reset"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/fab_reset" />

</androidx.constraintlayout.widget.ConstraintLayout>
● MainActivity.kt: En este archivo se encuentra la lógica de la actividad principal de la
aplicación. Se encarga de inicializar los componentes de la interfaz de usuario, como los
botones flotantes y el sensor de pasos. Además, implementa métodos para contar los pasos
en tiempo real, guardar los pasos dados, tomar fotos y restablecer el contador.

package com.example.gfg
import android.content.Context
import android.content.Intent
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity(), SensorEventListener {
private var sensorManager: SensorManager? = null
private var running = false
private var totalSteps = 0f
private var stepsSinceOpen = 0f

private lateinit var dbHelper: DatabaseHelper


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
dbHelper = DatabaseHelper(this)
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

findViewById<FloatingActionButton>(R.id.fab_save).setOnClickListener {
saveSteps()
}
findViewById<FloatingActionButton>(R.id.fab_history).setOnClickListener {
startActivity(Intent(this, HistoryActivity::class.java))
}
findViewById<FloatingActionButton>(R.id.fab_camera).setOnClickListener {
startActivity(Intent(this, CameraActivity::class.java))
}
findViewById<FloatingActionButton>(R.id.fab_reset).setOnClickListener {
resetSteps()
}
}

override fun onResume() {


super.onResume()
running = true
val stepSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)

if (stepSensor == null) {
Toast.makeText(this, "No Step Sensor!", Toast.LENGTH_SHORT).show()
} else {
sensorManager?.registerListener(this, stepSensor,
SensorManager.SENSOR_DELAY_UI)
}
}

override fun onPause() {


super.onPause()
running = false
sensorManager?.unregisterListener(this)
}

override fun onSensorChanged(event: SensorEvent) {


if (running) {
if (stepsSinceOpen == 0f) {
stepsSinceOpen = event.values[0]
}
val currentSteps = event.values[0] - stepsSinceOpen
findViewById<TextView>(R.id.tv_stepsTaken).text =
currentSteps.toInt().toString()
}
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}

private fun saveSteps() {


val currentSteps =
findViewById<TextView>(R.id.tv_stepsTaken).text.toString().toInt()
val timestamp = System.currentTimeMillis()
dbHelper.addSteps(currentSteps, timestamp)
Toast.makeText(this, "Steps saved!", Toast.LENGTH_SHORT).show()
}

private fun resetSteps() {


stepsSinceOpen = 0f
findViewById<TextView>(R.id.tv_stepsTaken).text = "0"
Toast.makeText(this, "Steps reset!", Toast.LENGTH_SHORT).show()
}
}

● activity_camera.xml y CameraActivity.kt: Estos archivos están relacionados con la


funcionalidad de tomar fotos. activity_camera.xml define la interfaz de usuario de la
actividad de la cámara, mientras que CameraActivity.kt contiene la lógica para abrir la
cámara, capturar imágenes y guardarlas en la galería del dispositivo.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CameraActivity">

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="!Toma foto de tu actividad diaria!"
android:textSize="24sp"
android:textColor="@android:color/black"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"/>

<ImageView
android:id="@+id/imageView"
android:layout_width="350dp"
android:layout_height="350dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="@android:color/darker_gray"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@id/fab_camera"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.496"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintVertical_bias="0.35" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Take Photo"
android:src="@drawable/ic_camera"
app:layout_constraintBottom_toTopOf="@id/fab_back"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/fab_load"
android:layout_marginTop="16dp"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Load Image"
android:src="@drawable/ic_image"
app:layout_constraintBottom_toTopOf="@id/fab_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/fab_camera"
android:layout_marginTop="16dp"/>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="Back"
android:src="@drawable/ic_back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="16dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

package com.example.gfg

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date

class CameraActivity : AppCompatActivity() {


private lateinit var imageView: ImageView
private lateinit var currentPhotoPath: String

private val REQUEST_IMAGE_CAPTURE = 1


private val REQUEST_IMAGE_PICK = 2
private val REQUEST_PERMISSION_CODE = 100

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)

imageView = findViewById(R.id.imageView)

findViewById<FloatingActionButton>(R.id.fab_load).setOnClickListener {
openGallery()
}
findViewById<FloatingActionButton>(R.id.fab_camera).setOnClickListener {
openCamera()
}

findViewById<FloatingActionButton>(R.id.fab_back).setOnClickListener {
finish() // Regresa a la MainActivity
}

checkPermissions()
}

private fun checkPermissions() {


if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) !=
PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE),
REQUEST_PERMISSION_CODE)
}
}

private fun openGallery() {


val intent = Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent, REQUEST_IMAGE_PICK)
}

private fun openCamera() {


val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(packageManager) != null) {
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
null
}
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.example.gfg.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
}

@Throws(IOException::class)
private fun createImageFile(): File {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_",
".jpg",
storageDir
).apply {
currentPhotoPath = absolutePath
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {


super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
val file = File(currentPhotoPath)
if (file.exists()) {
imageView.setImageURI(Uri.fromFile(file))
addImageToGallery()
}
} else if (requestCode == REQUEST_IMAGE_PICK && resultCode == Activity.RESULT_OK)
{
val selectedImage: Uri? = data?.data
imageView.setImageURI(selectedImage)
}
}

private fun addImageToGallery() {


Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
val file = File(currentPhotoPath)
mediaScanIntent.data = Uri.fromFile(file)
sendBroadcast(mediaScanIntent)
}
}
}

● activity_history.xml y HistoryActivity.kt: Aquí se encuentra la funcionalidad de mostrar el


historial de pasos guardados. activity_history.xml define la interfaz de usuario de la
actividad de historial, mientras que HistoryActivity.kt se encarga de obtener los datos
de la base de datos y mostrarlos en un ListView.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HistoryActivity">

<!-- Título "PASOS GUARDADOS" -->


<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PASOS GUARDADOS 🏆"
android:textSize="24sp"
android:textColor="@android:color/black"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:padding="16dp" />

<ListView
android:id="@+id/listView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintBottom_toTopOf="@+id/btn_back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:padding="16dp" />

<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

package com.example.gfg
import android.widget.Button
import android.database.Cursor
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity

class HistoryActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_history)

val listView = findViewById<ListView>(R.id.listView)


val dbHelper = DatabaseHelper(this)
val cursor: Cursor = dbHelper.getAllSteps()
val stepList = ArrayList<String>()

if (cursor.moveToFirst()) {
do {
val steps = cursor.getInt(cursor.getColumnIndexOrThrow("steps"))
val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow("timestamp"))
val date = java.text.SimpleDateFormat("dd/MM/yyyy
HH:mm:ss").format(java.util.Date(timestamp))
stepList.add("Pasos: $steps, Fecha: $date")
} while (cursor.moveToNext())
}

val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, stepList)


listView.adapter = adapter

// Button to return to main activity


findViewById<Button>(R.id.btn_back).setOnClickListener {
finish()
}
}
}

● file_paths.xml: Este archivo define la ruta de almacenamiento para las imágenes capturadas
por la cámara.

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="my_images"
path="Pictures/" />
</paths>

● DatabaseHelper.kt: Este archivo contiene la implementación de la base de datos SQLite


utilizada para almacenar el historial de pasos dados por el usuario. Define la estructura de la
tabla steps y proporciona métodos para agregar y obtener datos de la base de datos.

package com.example.gfg

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null,


DATABASE_VERSION) {

companion object {
private const val DATABASE_NAME = "steps.db"
private const val DATABASE_VERSION = 1
private const val TABLE_STEPS = "steps"
private const val COLUMN_ID = "id"
private const val COLUMN_STEPS = "steps"
private const val COLUMN_TIMESTAMP = "timestamp"
}

override fun onCreate(db: SQLiteDatabase) {


val CREATE_STEPS_TABLE = ("CREATE TABLE " + TABLE_STEPS + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_STEPS + " INTEGER,"
+ COLUMN_TIMESTAMP + " INTEGER" + ")")
db.execSQL(CREATE_STEPS_TABLE)
}

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {


db.execSQL("DROP TABLE IF EXISTS $TABLE_STEPS")
onCreate(db)
}

fun addSteps(steps: Int, timestamp: Long) {


val db = this.writableDatabase
val values = ContentValues()
values.put(COLUMN_STEPS, steps)
values.put(COLUMN_TIMESTAMP, timestamp)
db.insert(TABLE_STEPS, null, values)
db.close()
}

fun getAllSteps(): Cursor {


val db = this.readableDatabase
return db.rawQuery("SELECT * FROM $TABLE_STEPS ORDER BY $COLUMN_ID ASC", null)
}
}

● AndroidManifest.xml: En este archivo se especifican los permisos necesarios para la


aplicación, como el acceso a la cámara y el almacenamiento externo. También se define el
proveedor de contenido (FileProvider) para permitir el acceso seguro a los archivos de
imágenes.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-feature android:name="android.hardware.camera" android:required="false"/>


<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.GFG"
tools:targetApi="31">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".CameraActivity" android:exported="true"></activity>
<activity android:name=".HistoryActivity" android:exported="true"></activity>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.gfg.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>

Desarrollo Paso a Paso


1. Diseño de la Interfaz de Usuario: El archivo activity_main.xml define la interfaz de
usuario de la pantalla principal con elementos como el contador de pasos, botones flotantes
para acciones y un ImageView para visualizar el círculo de progreso.
2. Lógica de la Aplicación: En MainActivity.kt, se inicializan los componentes de la
interfaz de usuario y se implementa la funcionalidad para contar pasos en tiempo real
utilizando los sensores del dispositivo. También se gestionan las acciones de guardar pasos,
tomar fotos, ver historial y restablecer el contador.
3. Funcionalidad de la Cámara: Los archivos activity_camera.xml y
CameraActivity.kt se encargan de la funcionalidad de tomar fotos. El diseño de la
interfaz de usuario incluye un botón para capturar imágenes, y la lógica de la actividad
permite abrir la cámara, capturar fotos y guardarlas en la galería.
4. Historial de Pasos: La pantalla de historial (activity_history.xml y
HistoryActivity.kt) muestra los pasos guardados en un ListView obtenidos de la base
de datos SQLite a través de DatabaseHelper.kt.

Evaluación de la Aplicación
La aplicación "!A caminar!" cumple con los requisitos establecidos en la fase de desarrollo:

● Utiliza almacenamiento de datos a través de una base de datos SQLite


(DatabaseHelper.kt) para el historial de pasos.
● Integra la cámara para tomar fotos y guardarlas en la galería del dispositivo
(activity_camera.xml y CameraActivity.kt).
● Añade una imagen de logo al proyecto y genera un APK ejecutable en el teléfono móvil.
● El diseño de la interfaz de usuario es creativo y funcional para el usuario.

Conclusiones
La combinación de diseño de interfaz intuitivo, funcionalidades clave como el contador de pasos y la
integración de la cámara hacen que "!A caminar!" sea una aplicación útil para motivar a los usuarios
a mantener un estilo de vida activo y saludable.

You might also like