.
This commit is contained in:
36
app/src/main/AndroidManifest.xml
Normal file
36
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@drawable/ic_logo"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@drawable/ic_logo"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Cuida"
|
||||
tools:targetApi="31">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Launcher Intent Filter handled in LoginActivity usually, but for now we might start Main -->
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ui.auth.LoginActivity" 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=".ui.auth.RegisterActivity" />
|
||||
<activity android:name=".ui.auth.ForgotPasswordActivity" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
55
app/src/main/java/com/example/cuida/MainActivity.java
Normal file
55
app/src/main/java/com/example/cuida/MainActivity.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.example.cuida;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
import com.example.cuida.databinding.ActivityMainBinding;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.example.cuida.ui.auth.LoginActivity;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Check if user is logged in
|
||||
boolean isLoggedIn = getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||
.getBoolean("is_logged_in", false);
|
||||
|
||||
if (!isLoggedIn) {
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
BottomNavigationView navView = binding.navView;
|
||||
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.nav_host_fragment);
|
||||
|
||||
if (navHostFragment != null) {
|
||||
NavController navController = navHostFragment.getNavController();
|
||||
// Passing each menu ID as a set of Ids because each
|
||||
// menu should be considered as top level destinations.
|
||||
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
|
||||
R.id.navigation_home, R.id.navigation_appointments, R.id.navigation_medication,
|
||||
R.id.navigation_sns24, R.id.navigation_profile)
|
||||
.build();
|
||||
// NavigationUI.setupActionBarWithNavController(this, navController,
|
||||
// appBarConfiguration);
|
||||
NavigationUI.setupWithNavController(binding.navView, navController);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
app/src/main/java/com/example/cuida/data/AppDatabase.java
Normal file
65
app/src/main/java/com/example/cuida/data/AppDatabase.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.example.cuida.data;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.dao.AppointmentDao;
|
||||
import com.example.cuida.data.dao.MedicationDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Database(entities = { User.class, Appointment.class, Medication.class }, version = 3, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
public abstract UserDao userDao();
|
||||
|
||||
public abstract AppointmentDao appointmentDao();
|
||||
|
||||
public abstract MedicationDao medicationDao();
|
||||
|
||||
private static volatile AppDatabase INSTANCE;
|
||||
private static final int NUMBER_OF_THREADS = 4;
|
||||
public static final ExecutorService databaseWriteExecutor = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
|
||||
|
||||
public static AppDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (AppDatabase.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
AppDatabase.class, "cuida_database")
|
||||
.fallbackToDestructiveMigration()
|
||||
.addCallback(sRoomDatabaseCallback)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
|
||||
@Override
|
||||
public void onCreate(@NonNull SupportSQLiteDatabase db) {
|
||||
super.onCreate(db);
|
||||
databaseWriteExecutor.execute(() -> {
|
||||
// Populate the database in the background.
|
||||
|
||||
MedicationDao medDao = INSTANCE.medicationDao();
|
||||
medDao.insert(new Medication("Paracetamol", "08:00", "1 comp", "Tomar com água"));
|
||||
medDao.insert(new Medication("Ibuprofeno", "14:00", "1 comp", "Após refeição"));
|
||||
medDao.insert(new Medication("Vitamina C", "20:00", "1 comp", "Antes de dormir"));
|
||||
|
||||
AppointmentDao apptDao = INSTANCE.appointmentDao();
|
||||
apptDao.insert(new Appointment("Medicina Geral", "25/01/2026", "10:00", false));
|
||||
apptDao.insert(new Appointment("Cardiologia", "02/02/2026", "15:30", false));
|
||||
apptDao.insert(new Appointment("Oftalmologia", "10/01/2025", "09:00", true));
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.example.cuida.data.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface AppointmentDao {
|
||||
@Insert
|
||||
void insert(Appointment appointment);
|
||||
|
||||
@Query("SELECT * FROM appointments WHERE isPast = 0 ORDER BY date ASC, time ASC")
|
||||
LiveData<List<Appointment>> getFutureAppointments();
|
||||
|
||||
@Query("SELECT * FROM appointments WHERE isPast = 1 ORDER BY date DESC, time DESC")
|
||||
LiveData<List<Appointment>> getPastAppointments();
|
||||
|
||||
@Query("SELECT time FROM appointments WHERE date = :date")
|
||||
List<String> getBookedTimesForDate(String date);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.example.cuida.data.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface MedicationDao {
|
||||
@Insert
|
||||
void insert(Medication medication);
|
||||
|
||||
@androidx.room.Update
|
||||
void update(Medication medication);
|
||||
|
||||
@Query("SELECT * FROM medications ORDER BY time ASC")
|
||||
LiveData<List<Medication>> getAllMedications();
|
||||
|
||||
@Query("SELECT * FROM medications ORDER BY time ASC LIMIT 1")
|
||||
LiveData<Medication> getNextMedication();
|
||||
}
|
||||
26
app/src/main/java/com/example/cuida/data/dao/UserDao.java
Normal file
26
app/src/main/java/com/example/cuida/data/dao/UserDao.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.example.cuida.data.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import com.example.cuida.data.model.User;
|
||||
|
||||
@Dao
|
||||
public interface UserDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(User user);
|
||||
|
||||
@Update
|
||||
void update(User user);
|
||||
|
||||
@Query("SELECT * FROM users WHERE email = :email AND password = :password LIMIT 1")
|
||||
User login(String email, String password);
|
||||
|
||||
@Query("SELECT * FROM users WHERE email = :email LIMIT 1")
|
||||
User checkUser(String email);
|
||||
|
||||
@Query("delete from users")
|
||||
void deleteAll();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.example.cuida.data.model;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "appointments")
|
||||
public class Appointment {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int id;
|
||||
|
||||
public String type; // e.g. "Medicina Geral", "Cardiologia"
|
||||
public String date; // dd/MM/yyyy
|
||||
public String time; // HH:mm
|
||||
public boolean isPast;
|
||||
|
||||
public Appointment(String type, String date, String time, boolean isPast) {
|
||||
this.type = type;
|
||||
this.date = date;
|
||||
this.time = time;
|
||||
this.isPast = isPast;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.example.cuida.data.model;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "medications")
|
||||
public class Medication {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int id;
|
||||
|
||||
public String name;
|
||||
public String time; // HH:mm
|
||||
public String dosage; // e.g. "1 compprimido"
|
||||
public String notes;
|
||||
public boolean isTaken;
|
||||
|
||||
public Medication(String name, String time, String dosage, String notes) {
|
||||
this.name = name;
|
||||
this.time = time;
|
||||
this.dosage = dosage;
|
||||
this.notes = notes;
|
||||
this.isTaken = false;
|
||||
}
|
||||
}
|
||||
24
app/src/main/java/com/example/cuida/data/model/User.java
Normal file
24
app/src/main/java/com/example/cuida/data/model/User.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.example.cuida.data.model;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "users")
|
||||
public class User {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int uid;
|
||||
|
||||
public String name;
|
||||
public String email;
|
||||
public String password;
|
||||
public int age;
|
||||
public String utenteNumber;
|
||||
|
||||
public User(String name, String email, String password, int age, String utenteNumber) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.age = age;
|
||||
this.utenteNumber = utenteNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.example.cuida.ui.appointments;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.example.cuida.R;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AppointmentAdapter extends RecyclerView.Adapter<AppointmentAdapter.AppointmentViewHolder> {
|
||||
|
||||
private List<Appointment> appointmentList = new ArrayList<>();
|
||||
|
||||
public void setAppointments(List<Appointment> appointments) {
|
||||
this.appointmentList = appointments;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AppointmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_appointment, parent, false);
|
||||
return new AppointmentViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AppointmentViewHolder holder, int position) {
|
||||
Appointment appointment = appointmentList.get(position);
|
||||
holder.textType.setText(appointment.type);
|
||||
holder.textDate.setText(appointment.date);
|
||||
holder.textTime.setText(appointment.time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return appointmentList.size();
|
||||
}
|
||||
|
||||
public static class AppointmentViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView textType, textDate, textTime;
|
||||
|
||||
public AppointmentViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
textType = itemView.findViewById(R.id.text_type);
|
||||
textDate = itemView.findViewById(R.id.text_date);
|
||||
textTime = itemView.findViewById(R.id.text_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.example.cuida.ui.appointments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.example.cuida.R;
|
||||
import com.example.cuida.databinding.FragmentAppointmentsBinding;
|
||||
|
||||
public class AppointmentsFragment extends Fragment {
|
||||
|
||||
private FragmentAppointmentsBinding binding;
|
||||
private AppointmentsViewModel appointmentsViewModel;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
appointmentsViewModel = new ViewModelProvider(this).get(AppointmentsViewModel.class);
|
||||
|
||||
binding = FragmentAppointmentsBinding.inflate(inflater, container, false);
|
||||
|
||||
// Future Appointments
|
||||
AppointmentAdapter futureAdapter = new AppointmentAdapter();
|
||||
binding.recyclerAppointmentsFuture.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
binding.recyclerAppointmentsFuture.setAdapter(futureAdapter);
|
||||
|
||||
appointmentsViewModel.getFutureAppointments().observe(getViewLifecycleOwner(), appointments -> {
|
||||
futureAdapter.setAppointments(appointments);
|
||||
});
|
||||
|
||||
// Past Appointments
|
||||
AppointmentAdapter pastAdapter = new AppointmentAdapter();
|
||||
binding.recyclerAppointmentsPast.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
binding.recyclerAppointmentsPast.setAdapter(pastAdapter);
|
||||
|
||||
appointmentsViewModel.getPastAppointments().observe(getViewLifecycleOwner(), appointments -> {
|
||||
pastAdapter.setAppointments(appointments);
|
||||
});
|
||||
|
||||
binding.fabAddAppointment.setOnClickListener(v -> {
|
||||
androidx.navigation.Navigation.findNavController(v).navigate(R.id.action_appointments_to_schedule);
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.example.cuida.ui.appointments;
|
||||
|
||||
import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.AppointmentDao;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class AppointmentsViewModel extends AndroidViewModel {
|
||||
|
||||
private final AppointmentDao appointmentDao;
|
||||
private final LiveData<List<Appointment>> futureAppointments;
|
||||
private final LiveData<List<Appointment>> pastAppointments;
|
||||
private final ExecutorService executorService;
|
||||
|
||||
public AppointmentsViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
AppDatabase db = AppDatabase.getDatabase(application);
|
||||
appointmentDao = db.appointmentDao();
|
||||
futureAppointments = appointmentDao.getFutureAppointments();
|
||||
pastAppointments = appointmentDao.getPastAppointments();
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
public LiveData<List<Appointment>> getFutureAppointments() {
|
||||
return futureAppointments;
|
||||
}
|
||||
|
||||
public LiveData<List<Appointment>> getPastAppointments() {
|
||||
return pastAppointments;
|
||||
}
|
||||
|
||||
public void insert(Appointment appointment) {
|
||||
executorService.execute(() -> appointmentDao.insert(appointment));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.example.cuida.ui.auth;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.example.cuida.databinding.ActivityForgotPasswordBinding;
|
||||
|
||||
public class ForgotPasswordActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityForgotPasswordBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityForgotPasswordBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
binding.resetButton.setOnClickListener(v -> {
|
||||
String email = binding.emailEditText.getText().toString();
|
||||
if (email.isEmpty()) {
|
||||
Toast.makeText(this, "Por favor insira o seu email.", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
// Mock reset logic
|
||||
Toast.makeText(this, "Email de recuperação enviado para " + email, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
binding.backToLogin.setOnClickListener(v -> finish());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.example.cuida.ui.auth;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.example.cuida.MainActivity;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.databinding.ActivityLoginBinding;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityLoginBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityLoginBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
binding.loginButton.setOnClickListener(v -> login());
|
||||
binding.registerLink.setOnClickListener(v -> {
|
||||
startActivity(new Intent(this, RegisterActivity.class));
|
||||
finish();
|
||||
});
|
||||
|
||||
binding.forgotPasswordLink.setOnClickListener(v -> {
|
||||
startActivity(new Intent(this, ForgotPasswordActivity.class));
|
||||
});
|
||||
}
|
||||
|
||||
private void login() {
|
||||
String email = binding.emailEditText.getText().toString();
|
||||
String password = binding.passwordEditText.getText().toString();
|
||||
|
||||
if (email.isEmpty() || password.isEmpty()) {
|
||||
Toast.makeText(this, "Preencha todos os campos", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
AppDatabase db = AppDatabase.getDatabase(getApplicationContext());
|
||||
UserDao userDao = db.userDao();
|
||||
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
User user = userDao.login(email, password);
|
||||
runOnUiThread(() -> {
|
||||
if (user != null) {
|
||||
// Login Success
|
||||
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
|
||||
prefs.edit().putBoolean("is_logged_in", true).apply();
|
||||
prefs.edit().putString("user_name", user.name).apply();
|
||||
prefs.edit().putString("user_email", user.email).apply();
|
||||
|
||||
Toast.makeText(this, "Bem-vindo " + user.name, Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
finish();
|
||||
} else {
|
||||
Toast.makeText(this, "Credenciais inválidas", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.example.cuida.ui.auth;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.databinding.ActivityRegisterBinding;
|
||||
|
||||
public class RegisterActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityRegisterBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityRegisterBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
binding.registerButton.setOnClickListener(v -> register());
|
||||
binding.loginLink.setOnClickListener(v -> {
|
||||
startActivity(new Intent(this, LoginActivity.class));
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
private void register() {
|
||||
String name = binding.nameEditText.getText().toString();
|
||||
String ageStr = binding.ageEditText.getText().toString();
|
||||
String utenteStr = binding.utenteEditText.getText().toString();
|
||||
String email = binding.emailEditText.getText().toString();
|
||||
String password = binding.passwordEditText.getText().toString();
|
||||
|
||||
if (name.isEmpty() || ageStr.isEmpty() || email.isEmpty() || password.isEmpty() || utenteStr.isEmpty()) {
|
||||
Toast.makeText(this, "Preencha todos os campos", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
int age = Integer.parseInt(ageStr);
|
||||
|
||||
AppDatabase db = AppDatabase.getDatabase(getApplicationContext());
|
||||
UserDao userDao = db.userDao();
|
||||
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
User existing = userDao.checkUser(email);
|
||||
if (existing != null) {
|
||||
runOnUiThread(() -> Toast.makeText(this, "Email já registado", Toast.LENGTH_SHORT).show());
|
||||
} else {
|
||||
User newUser = new User(name, email, password, age, utenteStr);
|
||||
userDao.insert(newUser);
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(this, "Conta criada com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(this, LoginActivity.class));
|
||||
finish();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.example.cuida.ui.home;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import com.example.cuida.databinding.FragmentHomeBinding;
|
||||
import com.example.cuida.ui.medication.MedicationViewModel;
|
||||
import com.example.cuida.ui.appointments.AppointmentsViewModel;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
|
||||
private FragmentHomeBinding binding;
|
||||
private MedicationViewModel medicationViewModel;
|
||||
private AppointmentsViewModel appointmentsViewModel;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentHomeBinding.inflate(inflater, container, false);
|
||||
|
||||
// --- Greeting ---
|
||||
SharedPreferences prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
|
||||
String name = prefs.getString("user_name", "Utilizador");
|
||||
binding.textGreeting.setText("Olá, " + name + "!");
|
||||
|
||||
// --- Next Medication ---
|
||||
medicationViewModel = new ViewModelProvider(this).get(MedicationViewModel.class);
|
||||
medicationViewModel.getNextMedication().observe(getViewLifecycleOwner(), medication -> {
|
||||
if (medication != null) {
|
||||
binding.nextMedName.setText(medication.name + " (" + medication.dosage + ")");
|
||||
binding.nextMedTime.setText("Hoje, " + medication.time);
|
||||
} else {
|
||||
binding.nextMedName.setText("Sem medicação");
|
||||
binding.nextMedTime.setText("--:--");
|
||||
}
|
||||
});
|
||||
|
||||
// --- Book Appointment ---
|
||||
appointmentsViewModel = new ViewModelProvider(this).get(AppointmentsViewModel.class);
|
||||
binding.buttonBookAppointment.setOnClickListener(v -> showTimePicker());
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void showTimePicker() {
|
||||
Calendar mcurrentTime = Calendar.getInstance();
|
||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||
|
||||
TimePickerDialog mTimePicker;
|
||||
mTimePicker = new TimePickerDialog(getContext(), (timePicker, selectedHour, selectedMinute) -> {
|
||||
// Round to 15 minutes
|
||||
int roundedMinute = (selectedMinute / 15) * 15;
|
||||
String time = String.format(Locale.getDefault(), "%02d:%02d", selectedHour, roundedMinute);
|
||||
|
||||
// For MVP, assume date is tomorrow (or let user pick date, but brief said
|
||||
// "Hora" mostly)
|
||||
// Let's assume a default date for now or just "Amanhã" text logic
|
||||
String date = "Amanhã";
|
||||
|
||||
// Save to DB
|
||||
Appointment newAppt = new Appointment("Consulta Geral", date, time, false);
|
||||
appointmentsViewModel.insert(newAppt);
|
||||
|
||||
binding.buttonBookAppointment.setText("Consulta marcada: " + time);
|
||||
Toast.makeText(getContext(), "Consulta marcada para " + time, Toast.LENGTH_SHORT).show();
|
||||
|
||||
}, hour, minute, true);
|
||||
|
||||
mTimePicker.setTitle("Selecione a hora");
|
||||
mTimePicker.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.example.cuida.ui.medication;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.example.cuida.R;
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MedicationAdapter extends RecyclerView.Adapter<MedicationAdapter.MedicationViewHolder> {
|
||||
|
||||
private List<Medication> medicationList = new ArrayList<>();
|
||||
private final OnItemClickListener listener;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onCheckClick(Medication medication);
|
||||
}
|
||||
|
||||
public MedicationAdapter(OnItemClickListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setMedications(List<Medication> medications) {
|
||||
this.medicationList = medications;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MedicationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_medication, parent, false);
|
||||
return new MedicationViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull MedicationViewHolder holder, int position) {
|
||||
Medication medication = medicationList.get(position);
|
||||
holder.textName.setText(medication.name);
|
||||
holder.textDosage.setText(medication.dosage);
|
||||
holder.textTime.setText(medication.time);
|
||||
holder.textNotes.setText(medication.notes);
|
||||
|
||||
// Remove listener temporarily to avoid triggering it during bind
|
||||
holder.checkBoxTaken.setOnCheckedChangeListener(null);
|
||||
holder.checkBoxTaken.setChecked(medication.isTaken);
|
||||
|
||||
holder.checkBoxTaken.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
medication.isTaken = isChecked;
|
||||
listener.onCheckClick(medication);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return medicationList.size();
|
||||
}
|
||||
|
||||
public static class MedicationViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView textName, textDosage, textTime, textNotes;
|
||||
CheckBox checkBoxTaken;
|
||||
|
||||
public MedicationViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
textName = itemView.findViewById(R.id.text_med_name);
|
||||
textDosage = itemView.findViewById(R.id.text_med_dosage);
|
||||
textTime = itemView.findViewById(R.id.text_med_time);
|
||||
textNotes = itemView.findViewById(R.id.text_med_notes);
|
||||
checkBoxTaken = itemView.findViewById(R.id.checkbox_taken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.example.cuida.ui.medication;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import com.example.cuida.databinding.FragmentMedicationBinding;
|
||||
|
||||
public class MedicationFragment extends Fragment {
|
||||
|
||||
private FragmentMedicationBinding binding;
|
||||
private MedicationViewModel medicationViewModel;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
medicationViewModel = new ViewModelProvider(this).get(MedicationViewModel.class);
|
||||
|
||||
binding = FragmentMedicationBinding.inflate(inflater, container, false);
|
||||
|
||||
MedicationAdapter adapter = new MedicationAdapter(medication -> {
|
||||
medicationViewModel.update(medication);
|
||||
});
|
||||
binding.recyclerMedication.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
binding.recyclerMedication.setAdapter(adapter);
|
||||
|
||||
medicationViewModel.getAllMedications().observe(getViewLifecycleOwner(), medications -> {
|
||||
adapter.setMedications(medications);
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.example.cuida.ui.medication;
|
||||
|
||||
import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.MedicationDao;
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import java.util.List;
|
||||
|
||||
public class MedicationViewModel extends AndroidViewModel {
|
||||
|
||||
private final LiveData<List<Medication>> allMedications;
|
||||
private final LiveData<Medication> nextMedication;
|
||||
|
||||
public MedicationViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
AppDatabase db = AppDatabase.getDatabase(application);
|
||||
MedicationDao medicationDao = db.medicationDao();
|
||||
allMedications = medicationDao.getAllMedications();
|
||||
nextMedication = medicationDao.getNextMedication();
|
||||
}
|
||||
|
||||
public LiveData<List<Medication>> getAllMedications() {
|
||||
return allMedications;
|
||||
}
|
||||
|
||||
public LiveData<Medication> getNextMedication() {
|
||||
return nextMedication;
|
||||
}
|
||||
|
||||
public void update(Medication medication) {
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
AppDatabase.getDatabase(getApplication()).medicationDao().update(medication);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.example.cuida.ui.profile;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.R;
|
||||
import com.example.cuida.databinding.FragmentProfileBinding;
|
||||
import com.example.cuida.ui.auth.LoginActivity;
|
||||
|
||||
public class ProfileFragment extends Fragment {
|
||||
|
||||
private FragmentProfileBinding binding;
|
||||
private User currentUser;
|
||||
private UserDao userDao;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentProfileBinding.inflate(inflater, container, false);
|
||||
|
||||
userDao = AppDatabase.getDatabase(requireContext()).userDao();
|
||||
loadUserData();
|
||||
|
||||
binding.buttonEditProfile.setOnClickListener(v -> showEditDialog());
|
||||
|
||||
binding.buttonLogout.setOnClickListener(v -> {
|
||||
getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE).edit().clear().apply();
|
||||
Intent intent = new Intent(getContext(), LoginActivity.class);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void loadUserData() {
|
||||
SharedPreferences prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
|
||||
String email = prefs.getString("user_email", "");
|
||||
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
currentUser = userDao.checkUser(email);
|
||||
if (currentUser != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
binding.profileName.setText(currentUser.name);
|
||||
binding.profileEmail.setText(currentUser.email);
|
||||
binding.profileAge.setText(String.valueOf(currentUser.age));
|
||||
binding.profileUtente.setText(currentUser.utenteNumber != null ? currentUser.utenteNumber : "N/A");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showEditDialog() {
|
||||
if (currentUser == null)
|
||||
return;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
|
||||
// Inflate custom layout
|
||||
LayoutInflater inflater = requireActivity().getLayoutInflater();
|
||||
View dialogView = inflater.inflate(R.layout.dialog_edit_profile, null);
|
||||
builder.setView(dialogView);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
// Bind Views
|
||||
EditText editName = dialogView.findViewById(R.id.edit_name);
|
||||
EditText editAge = dialogView.findViewById(R.id.edit_age);
|
||||
EditText editUtente = dialogView.findViewById(R.id.edit_utente);
|
||||
EditText editEmail = dialogView.findViewById(R.id.edit_email);
|
||||
EditText editPassword = dialogView.findViewById(R.id.edit_password);
|
||||
View btnSave = dialogView.findViewById(R.id.button_save);
|
||||
View btnCancel = dialogView.findViewById(R.id.button_cancel);
|
||||
|
||||
// Pre-fill data
|
||||
editName.setText(currentUser.name);
|
||||
editAge.setText(String.valueOf(currentUser.age));
|
||||
editUtente.setText(currentUser.utenteNumber);
|
||||
editEmail.setText(currentUser.email);
|
||||
editPassword.setText(currentUser.password);
|
||||
|
||||
btnSave.setOnClickListener(v -> {
|
||||
String newName = editName.getText().toString();
|
||||
String ageStr = editAge.getText().toString();
|
||||
String newUtente = editUtente.getText().toString();
|
||||
String newEmail = editEmail.getText().toString();
|
||||
String newPassword = editPassword.getText().toString();
|
||||
|
||||
if (newName.isEmpty() || ageStr.isEmpty() || newUtente.isEmpty() || newEmail.isEmpty()
|
||||
|| newPassword.isEmpty()) {
|
||||
Toast.makeText(getContext(), "Preencha todos os campos", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
int newAge = Integer.parseInt(ageStr);
|
||||
boolean emailChanged = !newEmail.equals(currentUser.email);
|
||||
|
||||
currentUser.name = newName;
|
||||
currentUser.age = newAge;
|
||||
currentUser.utenteNumber = newUtente;
|
||||
currentUser.email = newEmail;
|
||||
currentUser.password = newPassword;
|
||||
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
userDao.insert(currentUser);
|
||||
});
|
||||
|
||||
// Update SharedPreferences if email changed (key for login persistence)
|
||||
if (emailChanged) {
|
||||
getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putString("user_email", newEmail)
|
||||
.apply();
|
||||
}
|
||||
|
||||
// UI update
|
||||
binding.profileName.setText(newName);
|
||||
binding.profileEmail.setText(newEmail);
|
||||
binding.profileAge.setText(String.valueOf(newAge));
|
||||
binding.profileUtente.setText(newUtente);
|
||||
|
||||
Toast.makeText(getContext(), "Dados atualizados com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
btnCancel.setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.example.cuida.ui.schedule;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.example.cuida.R;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class ScheduleAppointmentFragment extends Fragment {
|
||||
|
||||
private ScheduleViewModel scheduleViewModel;
|
||||
private DatePicker datePicker;
|
||||
private RecyclerView recyclerTimeSlots;
|
||||
private Button btnConfirm;
|
||||
private TimeSlotAdapter timeSlotAdapter;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_schedule_appointment, container, false);
|
||||
|
||||
scheduleViewModel = new ViewModelProvider(this).get(ScheduleViewModel.class);
|
||||
|
||||
datePicker = root.findViewById(R.id.datePicker);
|
||||
recyclerTimeSlots = root.findViewById(R.id.recycler_time_slots);
|
||||
btnConfirm = root.findViewById(R.id.btn_confirm_appointment);
|
||||
|
||||
setupDatePicker();
|
||||
setupRecyclerView();
|
||||
setupObservers();
|
||||
|
||||
btnConfirm.setOnClickListener(v -> scheduleViewModel.confirmAppointment());
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void setupDatePicker() {
|
||||
Calendar today = Calendar.getInstance();
|
||||
datePicker.init(today.get(Calendar.YEAR), today.get(Calendar.MONTH),
|
||||
today.get(Calendar.DAY_OF_MONTH), (view, year, monthOfYear, dayOfMonth) -> {
|
||||
scheduleViewModel.setDate(year, monthOfYear, dayOfMonth);
|
||||
});
|
||||
|
||||
// Set initial valid date in VM
|
||||
scheduleViewModel.setDate(today.get(Calendar.YEAR), today.get(Calendar.MONTH),
|
||||
today.get(Calendar.DAY_OF_MONTH));
|
||||
|
||||
// Prevent past dates
|
||||
datePicker.setMinDate(System.currentTimeMillis() - 1000);
|
||||
}
|
||||
|
||||
private void setupRecyclerView() {
|
||||
timeSlotAdapter = new TimeSlotAdapter();
|
||||
timeSlotAdapter.setOnTimeSlotSelectedListener(time -> scheduleViewModel.setTime(time));
|
||||
|
||||
recyclerTimeSlots.setLayoutManager(new GridLayoutManager(getContext(), 4));
|
||||
recyclerTimeSlots.setAdapter(timeSlotAdapter);
|
||||
}
|
||||
|
||||
private void setupObservers() {
|
||||
scheduleViewModel.getTimeSlots().observe(getViewLifecycleOwner(), slots -> {
|
||||
timeSlotAdapter.setTimeSlots(slots);
|
||||
});
|
||||
|
||||
scheduleViewModel.getSaveSuccess().observe(getViewLifecycleOwner(), success -> {
|
||||
if (success) {
|
||||
Toast.makeText(getContext(), "Consulta agendada com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
NavController navController = Navigation.findNavController(getView());
|
||||
navController.popBackStack();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.example.cuida.ui.schedule;
|
||||
|
||||
import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.AppointmentDao;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ScheduleViewModel extends AndroidViewModel {
|
||||
|
||||
private final AppointmentDao appointmentDao;
|
||||
private final ExecutorService executorService;
|
||||
|
||||
private final MutableLiveData<String> selectedDate = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> selectedTime = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<TimeSlot>> timeSlots = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> saveSuccess = new MutableLiveData<>();
|
||||
|
||||
public ScheduleViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
AppDatabase db = AppDatabase.getDatabase(application);
|
||||
appointmentDao = db.appointmentDao();
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
// Initial empty state or default date
|
||||
}
|
||||
|
||||
public void setDate(int year, int month, int dayOfMonth) {
|
||||
// Format to dd/MM/yyyy
|
||||
String date = String.format("%02d/%02d/%04d", dayOfMonth, month + 1, year);
|
||||
selectedDate.setValue(date);
|
||||
loadTimeSlots(date);
|
||||
}
|
||||
|
||||
public LiveData<String> getSelectedDate() {
|
||||
return selectedDate;
|
||||
}
|
||||
|
||||
public void setTime(String time) {
|
||||
selectedTime.setValue(time);
|
||||
|
||||
// Update selection state in the list
|
||||
List<TimeSlot> currentSlots = timeSlots.getValue();
|
||||
if (currentSlots != null) {
|
||||
for (TimeSlot slot : currentSlots) {
|
||||
slot.setSelected(slot.getTime().equals(time));
|
||||
}
|
||||
timeSlots.setValue(currentSlots);
|
||||
}
|
||||
}
|
||||
|
||||
public LiveData<String> getSelectedTime() {
|
||||
return selectedTime;
|
||||
}
|
||||
|
||||
public LiveData<List<TimeSlot>> getTimeSlots() {
|
||||
return timeSlots;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getSaveSuccess() {
|
||||
return saveSuccess;
|
||||
}
|
||||
|
||||
private void loadTimeSlots(String date) {
|
||||
executorService.execute(() -> {
|
||||
List<String> bookedTimes = appointmentDao.getBookedTimesForDate(date);
|
||||
List<TimeSlot> slots = generateTimeSlots(bookedTimes);
|
||||
timeSlots.postValue(slots);
|
||||
});
|
||||
}
|
||||
|
||||
private List<TimeSlot> generateTimeSlots(List<String> bookedTimes) {
|
||||
List<TimeSlot> slots = new ArrayList<>();
|
||||
int startHour = 8;
|
||||
int endHour = 20;
|
||||
|
||||
for (int hour = startHour; hour < endHour; hour++) {
|
||||
addSlot(slots, String.format("%02d:00", hour), bookedTimes);
|
||||
addSlot(slots, String.format("%02d:30", hour), bookedTimes);
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
private void addSlot(List<TimeSlot> slots, String time, List<String> bookedTimes) {
|
||||
boolean isBooked = bookedTimes.contains(time);
|
||||
// If current selected time is now booked (e.g. concurrent), deselect it?
|
||||
// For simplicity, just check booked state.
|
||||
boolean isSelected = time.equals(selectedTime.getValue());
|
||||
slots.add(new TimeSlot(time, isBooked, isSelected));
|
||||
}
|
||||
|
||||
public void confirmAppointment() {
|
||||
String date = selectedDate.getValue();
|
||||
String time = selectedTime.getValue();
|
||||
|
||||
if (date != null && time != null) {
|
||||
Appointment appointment = new Appointment("Consulta Geral", date, time, false);
|
||||
executorService.execute(() -> {
|
||||
appointmentDao.insert(appointment);
|
||||
saveSuccess.postValue(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.example.cuida.ui.schedule;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class TimeSlot {
|
||||
private String time;
|
||||
private boolean isBooked;
|
||||
private boolean isSelected;
|
||||
|
||||
public TimeSlot(String time, boolean isBooked, boolean isSelected) {
|
||||
this.time = time;
|
||||
this.isBooked = isBooked;
|
||||
this.isSelected = isSelected;
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public boolean isBooked() {
|
||||
return isBooked;
|
||||
}
|
||||
|
||||
public void setBooked(boolean booked) {
|
||||
isBooked = booked;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
isSelected = selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
TimeSlot timeSlot = (TimeSlot) o;
|
||||
return isBooked == timeSlot.isBooked &&
|
||||
isSelected == timeSlot.isSelected &&
|
||||
Objects.equals(time, timeSlot.time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(time, isBooked, isSelected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.example.cuida.ui.schedule;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.example.cuida.R;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TimeSlotAdapter extends RecyclerView.Adapter<TimeSlotAdapter.ViewHolder> {
|
||||
|
||||
private List<TimeSlot> timeSlots = new ArrayList<>();
|
||||
private OnTimeSlotSelectedListener listener;
|
||||
|
||||
public interface OnTimeSlotSelectedListener {
|
||||
void onTimeSlotSelected(String time);
|
||||
}
|
||||
|
||||
public void setOnTimeSlotSelectedListener(OnTimeSlotSelectedListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setTimeSlots(List<TimeSlot> slots) {
|
||||
this.timeSlots = slots;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_time_slot, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
TimeSlot slot = timeSlots.get(position);
|
||||
holder.btnTimeSlot.setText(slot.getTime());
|
||||
|
||||
if (slot.isBooked()) {
|
||||
holder.btnTimeSlot.setEnabled(false);
|
||||
holder.btnTimeSlot.setAlpha(0.5f);
|
||||
holder.btnTimeSlot.setChecked(false);
|
||||
holder.btnTimeSlot.setOnClickListener(null);
|
||||
} else {
|
||||
holder.btnTimeSlot.setEnabled(true);
|
||||
holder.btnTimeSlot.setAlpha(1.0f);
|
||||
holder.btnTimeSlot.setChecked(slot.isSelected());
|
||||
|
||||
holder.btnTimeSlot.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onTimeSlotSelected(slot.getTime());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return timeSlots.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
MaterialButton btnTimeSlot;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
btnTimeSlot = itemView.findViewById(R.id.btn_time_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.example.cuida.ui.sns24;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import com.example.cuida.databinding.FragmentSns24Binding;
|
||||
|
||||
public class Sns24Fragment extends Fragment {
|
||||
|
||||
private FragmentSns24Binding binding;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentSns24Binding.inflate(inflater, container, false);
|
||||
|
||||
binding.buttonCallSns.setOnClickListener(v -> {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
intent.setData(Uri.parse("tel:808242424"));
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
// In case no dialer app is found
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
binding.buttonTriage.setOnClickListener(v -> performTriage());
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void performTriage() {
|
||||
boolean fever = binding.checkFever.isChecked();
|
||||
boolean breath = binding.checkBreath.isChecked();
|
||||
boolean pain = binding.checkPain.isChecked();
|
||||
|
||||
if (breath || pain) {
|
||||
binding.textTriageResult.setText("URGENTE: Dirija-se imediatamente ao hospital ou ligue 112.");
|
||||
binding.textTriageResult.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
|
||||
} else if (fever) {
|
||||
binding.textTriageResult.setText("GRAVE: Ligue SNS 24 para aconselhamento antes de sair de casa.");
|
||||
binding.textTriageResult.setTextColor(getResources().getColor(android.R.color.holo_orange_dark));
|
||||
} else {
|
||||
binding.textTriageResult.setText("NÃO GRAVE: Fique em casa e monitorize os sintomas.");
|
||||
binding.textTriageResult.setTextColor(getResources().getColor(android.R.color.holo_green_dark));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
12
app/src/main/res/drawable/ic_launcher.xml
Normal file
12
app/src/main/res/drawable/ic_launcher.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#005B96"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M48,30h12v24h24v12h-24v24h-12v-24h-24v-12h24z"/>
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_launcher_round.xml
Normal file
12
app/src/main/res/drawable/ic_launcher_round.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#005B96"
|
||||
android:pathData="M54,54m-54,0a54,54 0 1,1 108,0a54,54 0 1,1 -108,0"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M48,30h12v24h24v12h-24v24h-12v-24h-24v-12h24z"/>
|
||||
</vector>
|
||||
BIN
app/src/main/res/drawable/ic_logo.png
Normal file
BIN
app/src/main/res/drawable/ic_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
63
app/src/main/res/layout/activity_forgot_password.xml
Normal file
63
app/src/main/res/layout/activity_forgot_password.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="24dp"
|
||||
android:background="@color/background_color">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/ic_logo" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/forgot_password"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Insira o seu email para recuperar a palavra-passe."
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/email_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/email_hint"
|
||||
android:inputType="textEmailAddress" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/reset_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:text="Recuperar Palavra-passe"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/back_to_login"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Voltar ao Login"
|
||||
android:textColor="@color/primary_color"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
</LinearLayout>
|
||||
119
app/src/main/res/layout/activity_login.xml
Normal file
119
app/src/main/res/layout/activity_login.xml
Normal file
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView 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="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="@color/background_color">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="139dp"
|
||||
android:layout_height="129dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:src="@drawable/ic_logo" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@color/surface_color">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_title"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/email_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/email_hint"
|
||||
android:inputType="textEmailAddress" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
android:inputType="textPassword" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/login_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:text="@string/login_button"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="28dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/forgot_password_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/forgot_password"
|
||||
android:textColor="@color/secondary_color"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:padding="8dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_account"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/register_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/register_title"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/secondary_color"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
33
app/src/main/res/layout/activity_main.xml
Normal file
33
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:defaultNavHost="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/nav_view"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navGraph="@navigation/mobile_navigation" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:background="?android:attr/windowBackground"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:menu="@menu/bottom_nav_menu" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
161
app/src/main/res/layout/activity_register.xml
Normal file
161
app/src/main/res/layout/activity_register.xml
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView 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="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="@color/background_color">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:src="@drawable/ic_logo"
|
||||
android:contentDescription="@string/app_name" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@color/surface_color">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/register_title"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/name_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/name_hint"
|
||||
android:inputType="textPersonName" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/age_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/age_hint"
|
||||
android:inputType="number" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="2"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/utente_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Nº Utente"
|
||||
android:inputType="number" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/email_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/email_hint"
|
||||
android:inputType="textEmailAddress" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
android:inputType="textPassword" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/register_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:text="@string/register_button"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:cornerRadius="28dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/already_account"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_title"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/secondary_color"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
108
app/src/main/res/layout/dialog_edit_profile.xml
Normal file
108
app/src/main/res/layout/dialog_edit_profile.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Editar Dados"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Nome"
|
||||
android:inputType="textPersonName" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_age"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Idade"
|
||||
android:inputType="number" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_utente"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Nº Utente"
|
||||
android:inputType="number" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Email"
|
||||
android:inputType="textEmailAddress" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Nova Palavra-Passe"
|
||||
android:inputType="textPassword" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_cancel"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Cancelar"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Salvar" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
58
app/src/main/res/layout/fragment_appointments.xml
Normal file
58
app/src/main/res/layout/fragment_appointments.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_appointments"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<!-- Placeholder for RecyclerView -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Futuras"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_appointments_future"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Passadas"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_appointments_past"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_appointment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="Agendar Consulta"
|
||||
android:src="@android:drawable/ic_input_add" />
|
||||
|
||||
</FrameLayout>
|
||||
72
app/src/main/res/layout/fragment_home.xml
Normal file
72
app/src/main/res/layout/fragment_home.xml
Normal file
@@ -0,0 +1,72 @@
|
||||
<?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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_greeting"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Olá, utilizador!"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_next_medication"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_greeting">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Próxima Medicação"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:textColor="@color/primary_color"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/next_med_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Paracetamol 500mg"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/next_med_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hoje, 14:00"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/darker_gray"
|
||||
android:layout_marginTop="4dp"/>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_book_appointment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="Marcar Consulta"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="24dp"
|
||||
app:icon="@android:drawable/ic_menu_my_calendar"
|
||||
app:iconGravity="textStart"
|
||||
app:layout_constraintTop_toBottomOf="@id/card_next_medication"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
22
app/src/main/res/layout/fragment_medication.xml
Normal file
22
app/src/main/res/layout/fragment_medication.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_medication"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_medication"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</LinearLayout>
|
||||
126
app/src/main/res/layout/fragment_profile.xml
Normal file
126
app/src/main/res/layout/fragment_profile.xml
Normal file
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:background="@color/background_color">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@drawable/ic_logo"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@color/surface_color"
|
||||
android:layout_marginBottom="32dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/profile_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nome do Utilizador"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/profile_email"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="email@exemplo.com"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#E0E0E0"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Idade: "
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/text_secondary"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/profile_age"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="--"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nº Utente: "
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/text_secondary"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/profile_utente"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="--"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_edit_profile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="Editar Dados"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cornerRadius="30dp"
|
||||
android:backgroundTint="@color/secondary_color"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_logout"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="Terminar Sessão"
|
||||
app:strokeColor="@color/error_color"
|
||||
android:textColor="@color/error_color"
|
||||
app:cornerRadius="30dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
55
app/src/main/res/layout/fragment_schedule_appointment.xml
Normal file
55
app/src/main/res/layout/fragment_schedule_appointment.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Agendar Consulta"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Selecionar Data"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<DatePicker
|
||||
android:id="@+id/datePicker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:calendarViewShown="false"
|
||||
android:datePickerMode="spinner"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Selecionar Horário"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_time_slots"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_confirm_appointment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Confirmar Agendamento"/>
|
||||
|
||||
</LinearLayout>
|
||||
95
app/src/main/res/layout/fragment_sns24.xml
Normal file
95
app/src/main/res/layout/fragment_sns24.xml
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_sns24"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/primary_color"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_call_sns"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:text="Ligar SNS 24 (808 24 24 24)"
|
||||
android:textSize="18sp"
|
||||
android:backgroundTint="@color/teal_700"
|
||||
app:icon="@android:drawable/ic_menu_call"
|
||||
app:iconGravity="textStart"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Triagem Inteligente"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sente algum destes sintomas?"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_fever"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Febre Alta (> 38ºC)"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_breath"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Dificuldade Respiratória"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_pain"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Dor no Peito"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_triage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Avaliar Sintomas"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_triage_result"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/error_color"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
46
app/src/main/res/layout/item_appointment.xml
Normal file
46
app/src/main/res/layout/item_appointment.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView 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="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tipo de Consulta"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:textColor="@color/primary_color"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="dd/MM/yyyy"
|
||||
android:layout_marginEnd="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="HH:mm"
|
||||
android:textStyle="italic"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
73
app/src/main/res/layout/item_medication.xml
Normal file
73
app/src/main/res/layout/item_medication.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView 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="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@android:drawable/ic_menu_agenda"
|
||||
app:tint="@color/secondary_color"
|
||||
android:layout_marginEnd="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_med_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nome Medicamento"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:textColor="@color/primary_color"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_med_dosage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Dosagem"
|
||||
android:layout_marginTop="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_med_notes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Observações"
|
||||
android:textStyle="italic"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_med_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="HH:mm"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginEnd="16dp"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_taken"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:buttonTint="@color/primary_color"/>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
9
app/src/main/res/layout/item_time_slot.xml
Normal file
9
app/src/main/res/layout/item_time_slot.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/btn_time_slot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="09:00"
|
||||
android:checkable="true"
|
||||
android:layout_margin="4dp"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"/>
|
||||
29
app/src/main/res/menu/bottom_nav_menu.xml
Normal file
29
app/src/main/res/menu/bottom_nav_menu.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_home"
|
||||
android:icon="@android:drawable/ic_menu_today"
|
||||
android:title="@string/title_home" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_appointments"
|
||||
android:icon="@android:drawable/ic_menu_my_calendar"
|
||||
android:title="@string/title_appointments" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_medication"
|
||||
android:icon="@android:drawable/ic_menu_agenda"
|
||||
android:title="@string/title_medication" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_sns24"
|
||||
android:icon="@android:drawable/ic_menu_call"
|
||||
android:title="@string/title_sns24" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_profile"
|
||||
android:icon="@android:drawable/ic_menu_myplaces"
|
||||
android:title="@string/title_profile" />
|
||||
|
||||
</menu>
|
||||
48
app/src/main/res/navigation/mobile_navigation.xml
Normal file
48
app/src/main/res/navigation/mobile_navigation.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation 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:id="@+id/mobile_navigation"
|
||||
app:startDestination="@+id/navigation_home">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_home"
|
||||
android:name="com.example.cuida.ui.home.HomeFragment"
|
||||
android:label="@string/title_home"
|
||||
tools:layout="@layout/fragment_home" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_appointments"
|
||||
android:name="com.example.cuida.ui.appointments.AppointmentsFragment"
|
||||
android:label="@string/title_appointments"
|
||||
tools:layout="@layout/fragment_appointments">
|
||||
<action
|
||||
android:id="@+id/action_appointments_to_schedule"
|
||||
app:destination="@id/navigation_schedule_appointment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_medication"
|
||||
android:name="com.example.cuida.ui.medication.MedicationFragment"
|
||||
android:label="@string/title_medication"
|
||||
tools:layout="@layout/fragment_medication" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_sns24"
|
||||
android:name="com.example.cuida.ui.sns24.Sns24Fragment"
|
||||
android:label="@string/title_sns24"
|
||||
tools:layout="@layout/fragment_sns24" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_profile"
|
||||
android:name="com.example.cuida.ui.profile.ProfileFragment"
|
||||
android:label="@string/title_profile"
|
||||
tools:layout="@layout/fragment_profile" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_schedule_appointment"
|
||||
android:name="com.example.cuida.ui.schedule.ScheduleAppointmentFragment"
|
||||
android:label="Agendar Consulta"
|
||||
tools:layout="@layout/fragment_schedule_appointment" />
|
||||
|
||||
</navigation>
|
||||
22
app/src/main/res/values/colors.xml
Normal file
22
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#90CAF9</color>
|
||||
<color name="purple_500">#2196F3</color>
|
||||
<color name="purple_700">#1976D2</color>
|
||||
<color name="teal_200">#80DEEA</color>
|
||||
<color name="teal_700">#0097A7</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
|
||||
<!-- App Brand Colors -->
|
||||
<color name="primary_color">#1976D2</color> <!-- Strong Blue -->
|
||||
<color name="primary_light_color">#BBDEFB</color>
|
||||
<color name="secondary_color">#000000</color> <!-- Black -->
|
||||
<color name="secondary_dark_color">#000000</color>
|
||||
|
||||
<color name="background_color">#F5F7FA</color>
|
||||
<color name="surface_color">#FFFFFF</color>
|
||||
<color name="text_primary">#000000</color>
|
||||
<color name="text_secondary">#424242</color>
|
||||
<color name="error_color">#B00020</color>
|
||||
</resources>
|
||||
21
app/src/main/res/values/strings.xml
Normal file
21
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<resources>
|
||||
<string name="app_name">Cuida</string>
|
||||
<string name="title_home">Início</string>
|
||||
<string name="title_appointments">Consultas</string>
|
||||
<string name="title_medication">Medicação</string>
|
||||
<string name="title_sns24">SNS 24</string>
|
||||
<string name="title_profile">Perfil</string>
|
||||
|
||||
<!-- Auth -->
|
||||
<string name="login_title">Iniciar Sessão</string>
|
||||
<string name="register_title">Criar Conta</string>
|
||||
<string name="forgot_password">Esqueci-me da Palavra-passe</string>
|
||||
<string name="email_hint">Email</string>
|
||||
<string name="password_hint">Palavra-passe</string>
|
||||
<string name="name_hint">Nome</string>
|
||||
<string name="age_hint">Idade</string>
|
||||
<string name="login_button">Entrar</string>
|
||||
<string name="register_button">Registar</string>
|
||||
<string name="no_account">Não tem conta?</string>
|
||||
<string name="already_account">Já tem conta?</string>
|
||||
</resources>
|
||||
16
app/src/main/res/values/themes.xml
Normal file
16
app/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.Cuida" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/primary_color</item>
|
||||
<item name="colorPrimaryVariant">@color/primary_color</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/secondary_color</item>
|
||||
<item name="colorSecondaryVariant">@color/secondary_color</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
5
app/src/main/res/xml/backup_rules.xml
Normal file
5
app/src/main/res/xml/backup_rules.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
<include domain="sharedpref" path="."/>
|
||||
<include domain="database" path="."/>
|
||||
</full-backup-content>
|
||||
11
app/src/main/res/xml/data_extraction_rules.xml
Normal file
11
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<include domain="sharedpref" path="."/>
|
||||
<include domain="database" path="."/>
|
||||
</cloud-backup>
|
||||
<device-transfer>
|
||||
<include domain="sharedpref" path="."/>
|
||||
<include domain="database" path="."/>
|
||||
</device-transfer>
|
||||
</data-extraction-rules>
|
||||
Reference in New Issue
Block a user