Commit 7d9fc201 authored by Syazmin's avatar Syazmin

calendar and form done

parent e17edfcb
......@@ -25,11 +25,16 @@ android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
// Enable modern Java APIs on older Android versions
coreLibraryDesugaringEnabled true
}
}
dependencies {
// Enable modern Java APIs on older Android versions
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
// Using correct, stable versions for all libraries
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.12.0'
......@@ -51,4 +56,7 @@ dependencies {
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// Custom Calendar View
implementation 'com.kizitonwose.calendar:view:2.5.1'
}
......@@ -2,6 +2,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Permissions for camera and gallery -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
......
......@@ -13,15 +13,16 @@ public class AppointmentViewModel extends ViewModel {
private final MutableLiveData<String> representativeName = new MutableLiveData<>();
private final MutableLiveData<String> contactEmail = new MutableLiveData<>();
private final MutableLiveData<String> contactNumber = new MutableLiveData<>();
private final MutableLiveData<Boolean> isOwnerAttending = new MutableLiveData<>(true);
private final MutableLiveData<Boolean> isRepresentativeAttending = new MutableLiveData<>(false);
// Getters
public LiveData<String> getUnitNo() { return unitNo; }
public LiveData<Long> getSelectedDate() { return selectedDate; }
public LiveData<String> getSelectedTime() { return selectedTime; }
public LiveData<String> getRepresentativeName() { return representativeName; }
public LiveData<String> getContactEmail() { return contactEmail; } // Added missing getter
public LiveData<String> getContactEmail() { return contactEmail; }
public LiveData<String> getContactNumber() { return contactNumber; }
public LiveData<Boolean> isRepresentativeAttending() { return isRepresentativeAttending; }
// Setters
public void setSelectedDate(long date) { selectedDate.setValue(date); }
......@@ -29,12 +30,19 @@ public class AppointmentViewModel extends ViewModel {
public void setRepresentativeName(String name) { representativeName.setValue(name); }
public void setContactEmail(String email) { contactEmail.setValue(email); }
public void setContactNumber(String number) { contactNumber.setValue(number); }
public void setRepresentativeAttending(boolean isAttending) { isRepresentativeAttending.setValue(isAttending); }
public void resetAppointment() {
selectedDate.setValue(null);
selectedTime.setValue(null);
public void clearRepresentativeData() {
representativeName.setValue(null);
contactEmail.setValue(null);
contactNumber.setValue(null);
// We don't reset the isRepresentativeAttending flag itself, as it's controlled by the switch
}
public void resetAppointment() {
selectedDate.setValue(null);
selectedTime.setValue(null);
isRepresentativeAttending.setValue(false);
clearRepresentativeData();
}
}
package com.example.qmsmakeappointment;
import android.app.AlertDialog;
import android.os.Bundle;
import android.widget.ImageButton;
import android.widget.Toast;
......@@ -31,9 +32,9 @@ public class MainActivity extends AppCompatActivity {
db = AppointmentDatabase.getDatabase(this);
closeButton = findViewById(R.id.close_button);
// Load the initial fragment
// Load the Terms & Conditions fragment as the initial fragment
if (savedInstanceState == null) {
loadFragment(new Step1DateFragment(), false);
loadFragment(new TermsConditionsFragment(), false);
}
// Handle the top-left close button (Simulates the Cancel Alert)
......@@ -54,14 +55,29 @@ public class MainActivity extends AppCompatActivity {
}
private void handleClose() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// If on a subsequent step, just pop back (back button function)
getSupportFragmentManager().popBackStack();
} else {
// If on the first step, show the "Cancel Alert"
Toast.makeText(this, "ALERT: Cancel make appointment? (Yes/No)", Toast.LENGTH_SHORT).show();
// In a real app, this would show a dialog.
// Always show cancel appointment dialog when close button is clicked
showCancelAppointmentDialog();
}
/**
* Show dialog to confirm cancelling the appointment
*/
private void showCancelAppointmentDialog() {
new AlertDialog.Builder(this)
.setTitle("Alert")
.setMessage("Cancel make appointment?")
.setPositiveButton("Yes", (dialog, which) -> {
// User confirmed - reset and go back to Terms & Conditions
viewModel.resetAppointment();
getSupportFragmentManager().popBackStack(null, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
loadFragment(new TermsConditionsFragment(), false);
})
.setNegativeButton("No", (dialog, which) -> {
// User cancelled - just dismiss the dialog
dialog.dismiss();
})
.setCancelable(false)
.show();
}
public void saveAppointment() {
......@@ -91,10 +107,10 @@ public class MainActivity extends AppCompatActivity {
// Show Access Alert
Toast.makeText(MainActivity.this, "Success: You have successfully made a appointment.", Toast.LENGTH_LONG).show();
// Clear back stack and restart to Step 1
// Clear back stack and restart to Terms & Conditions
getSupportFragmentManager().popBackStack(null, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
viewModel.resetAppointment();
loadFragment(new Step1DateFragment(), false);
loadFragment(new TermsConditionsFragment(), false);
});
});
}
......
package com.example.qmsmakeappointment;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CalendarView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.qmsmakeappointment.Step2TimeFragment;
import com.kizitonwose.calendar.core.CalendarDay;
import com.kizitonwose.calendar.core.DayPosition;
import com.kizitonwose.calendar.view.CalendarView;
import com.kizitonwose.calendar.view.MonthDayBinder;
import com.kizitonwose.calendar.view.ViewContainer;
import java.util.Calendar;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
public class Step1DateFragment extends Fragment {
private AppointmentViewModel viewModel;
private CalendarView calendarView;
private Button nextButton;
private long selectedDateTimestamp = 0;
private TextView monthYearText;
private LocalDate selectedDate;
// Mock data for available/limited days
private final Map<LocalDate, String> dayStatus = new HashMap<>();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Populate mock data
dayStatus.put(LocalDate.now().plusDays(2), "Available");
dayStatus.put(LocalDate.now().plusDays(3), "Available");
dayStatus.put(LocalDate.now().plusDays(7), "Limited");
dayStatus.put(LocalDate.now().plusDays(8), "Available");
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_step_1_date, container, false);
}
......@@ -34,54 +60,119 @@ public class Step1DateFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Get the shared ViewModel
viewModel = new ViewModelProvider(requireActivity()).get(AppointmentViewModel.class);
calendarView = view.findViewById(R.id.calendar_view);
nextButton = view.findViewById(R.id.button_step1);
monthYearText = view.findViewById(R.id.calendar_month_year_text);
ImageView prevButton = view.findViewById(R.id.calendar_prev_button);
ImageView nextButtonCal = view.findViewById(R.id.calendar_next_button);
Button backButton = view.findViewById(R.id.back_button_step1);
// Set the initial date if one exists in the ViewModel
Long storedDate = viewModel.getSelectedDate().getValue();
if (storedDate != null && storedDate != 0) {
calendarView.setDate(storedDate);
selectedDateTimestamp = storedDate;
nextButton.setEnabled(true);
} else {
// Set the current date as initially selected
selectedDateTimestamp = calendarView.getDate();
LinearLayout daysOfWeekLayout = view.findViewById(R.id.calendar_days_legend);
// Setup days of the week header
String[] daysOfWeek = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
for (String day : daysOfWeek) {
TextView textView = new TextView(requireContext());
textView.setText(day);
textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
textView.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
daysOfWeekLayout.addView(textView);
}
// Calendar setup
YearMonth currentMonth = YearMonth.now();
YearMonth startMonth = currentMonth.minusMonths(100);
YearMonth endMonth = currentMonth.plusMonths(100);
// Handle date selection
calendarView.setOnDateChangeListener((view1, year, month, dayOfMonth) -> {
// Get the timestamps
Calendar selectedCalendar = Calendar.getInstance();
selectedCalendar.set(year, month, dayOfMonth, 0, 0, 0);
selectedDateTimestamp = selectedCalendar.getTimeInMillis();
setupDayBinder();
setupMonthBinder();
// Enable the next button since a date is selected
nextButton.setEnabled(true);
});
calendarView.setup(startMonth, endMonth, DayOfWeek.SUNDAY);
calendarView.scrollToMonth(currentMonth);
// Handle Next Button
nextButton.setOnClickListener(v -> {
if (selectedDateTimestamp != 0) {
// Save the selected date to the ViewModel
viewModel.setSelectedDate(selectedDateTimestamp);
// Button listeners
prevButton.setOnClickListener(v -> calendarView.scrollToMonth(calendarView.findFirstVisibleMonth().getYearMonth().minusMonths(1)));
nextButtonCal.setOnClickListener(v -> calendarView.scrollToMonth(calendarView.findFirstVisibleMonth().getYearMonth().plusMonths(1)));
// Navigate to Step 2 (Time Selection) - you will need to create this fragment
nextButton.setOnClickListener(v -> {
if (selectedDate != null) {
viewModel.setSelectedDate(selectedDate.toEpochDay());
((MainActivity) requireActivity()).loadFragment(new Step2TimeFragment(), true);
} else {
Toast.makeText(getContext(), "Please select a date.", Toast.LENGTH_SHORT).show();
}
});
backButton.setOnClickListener(v -> getParentFragmentManager().popBackStack());
}
// Handle Back Button (which simulates moving back to the Terms step, if it existed)
backButton.setOnClickListener(v -> {
// Since Step 1 is the first screen in the flow, clicking "Back" often cancels or
// goes to a previous screen outside the flow (like 04.0 Alert).
Toast.makeText(getContext(), "Simulating back to Terms & Conditions screen.", Toast.LENGTH_SHORT).show();
private void setupDayBinder() {
calendarView.setDayBinder(new MonthDayBinder<DayViewContainer>() {
@NonNull
@Override
public DayViewContainer create(@NonNull View view) {
return new DayViewContainer(view);
}
@Override
public void bind(@NonNull DayViewContainer container, CalendarDay day) {
container.day = day;
TextView textView = container.textView;
textView.setText(String.valueOf(day.getDate().getDayOfMonth()));
if (day.getPosition() == DayPosition.MonthDate) {
textView.setVisibility(View.VISIBLE);
if (day.getDate().equals(selectedDate)) {
textView.setBackgroundResource(R.drawable.circle_blue);
textView.setTextColor(Color.WHITE);
} else {
textView.setTextColor(Color.BLACK);
String status = dayStatus.get(day.getDate());
if (status != null) {
if (status.equals("Available")) {
textView.setBackgroundResource(R.drawable.circle_green);
} else if (status.equals("Limited")) {
textView.setBackgroundResource(R.drawable.circle_orange);
}
} else {
textView.setBackgroundResource(R.drawable.circle_gray);
}
}
} else {
textView.setVisibility(View.INVISIBLE);
}
}
});
}
private void setupMonthBinder() {
calendarView.setMonthScrollListener(calendarMonth -> {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM yyyy");
monthYearText.setText(calendarMonth.getYearMonth().format(formatter));
return null;
});
}
class DayViewContainer extends ViewContainer {
TextView textView;
CalendarDay day;
public DayViewContainer(@NonNull View view) {
super(view);
textView = view.findViewById(R.id.calendar_day_text);
view.setOnClickListener(v -> {
if (day.getPosition() == DayPosition.MonthDate) {
if (selectedDate != day.getDate()) {
LocalDate oldDate = selectedDate;
selectedDate = day.getDate();
calendarView.notifyDateChanged(day.getDate());
if (oldDate != null) {
calendarView.notifyDateChanged(oldDate);
}
nextButton.setEnabled(true);
}
}
});
}
}
}
package com.example.qmsmakeappointment; // Change to your actual package
package com.example.qmsmakeappointment;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.qmsmakeappointment.AppointmentViewModel;
import com.google.android.material.button.MaterialButton;
public class Step2TimeFragment extends Fragment implements View.OnClickListener {
import java.util.ArrayList;
import java.util.List;
import com.example.qmsmakeappointment.Step4ConfirmFragment;
public class Step2TimeFragment extends Fragment {
private AppointmentViewModel viewModel;
private Button nextButton;
private MaterialButton selectedTimeButton = null;
private List<MaterialButton> timeSlotButtons = new ArrayList<>();
private String selectedTime = null;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_step_2_time, container, false);
}
......@@ -33,58 +41,66 @@ public class Step2TimeFragment extends Fragment implements View.OnClickListener
nextButton = view.findViewById(R.id.next_button_step2);
Button backButton = view.findViewById(R.id.back_button_step2);
// Map all time slot buttons and set their click listener
int[] timeSlotIds = {
R.id.time_slot_0900, R.id.time_slot_1000,
R.id.time_slot_1200, R.id.time_slot_1400,
R.id.time_slot_1600, R.id.time_slot_1700
};
for (int id : timeSlotIds) {
view.findViewById(id).setOnClickListener(this);
// Find all time slot buttons and add them to a list
timeSlotButtons.add(view.findViewById(R.id.time_slot_0900));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1000));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1100));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1200));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1400));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1500));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1600));
timeSlotButtons.add(view.findViewById(R.id.time_slot_1700));
// Set click listener for each button
for (MaterialButton button : timeSlotButtons) {
button.setOnClickListener(v -> handleTimeSelection((MaterialButton) v));
}
// Check if a time was already selected (e.g., user navigated back)
if (viewModel.getSelectedTime().getValue() != null) {
// Restore selection if a time was already selected
selectedTime = viewModel.getSelectedTime().getValue();
if (selectedTime != null) {
updateButtonStyles();
nextButton.setEnabled(true);
// In a real app, you would iterate through buttons to re-select the correct one.
}
// Handle Next Button
nextButton.setOnClickListener(v -> {
if (selectedTimeButton != null) {
// Time is already saved in the click handler, navigate to summary
((MainActivity) requireActivity()).loadFragment(new Step3SummaryFragment(), true);
if (selectedTime != null) {
viewModel.setSelectedTime(selectedTime);
((MainActivity) requireActivity()).loadFragment(new Step4ConfirmFragment(), true);
}
});
// Handle Back Button
backButton.setOnClickListener(v -> {
// Pop the current fragment to go back to Step 1 (Date Selection)
requireActivity().getSupportFragmentManager().popBackStack();
});
}
@Override
public void onClick(View v) {
MaterialButton clickedButton = (MaterialButton) v;
String time = clickedButton.getText().toString();
// 1. Reset previous selection's appearance
if (selectedTimeButton != null) {
selectedTimeButton.setStrokeColorResource(R.color.colorPrimary); // Assuming colorPrimary is defined
selectedTimeButton.setTextColor(getResources().getColor(R.color.colorPrimary));
backButton.setOnClickListener(v -> getParentFragmentManager().popBackStack());
}
// 2. Set new selection's appearance
clickedButton.setStrokeColorResource(R.color.white); // Simulating selection background
clickedButton.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); // Primary color background
clickedButton.setTextColor(getResources().getColor(android.R.color.white));
private void handleTimeSelection(MaterialButton clickedButton) {
// Get the time from the clicked button
selectedTime = clickedButton.getText().toString();
selectedTimeButton = clickedButton;
// Update the visual state of all buttons
updateButtonStyles();
// 3. Update ViewModel and enable next step
viewModel.setSelectedTime(time);
// Enable the Next button
nextButton.setEnabled(true);
}
private void updateButtonStyles() {
int colorPrimary = ContextCompat.getColor(requireContext(), R.color.colorPrimary);
int colorGrey = ContextCompat.getColor(requireContext(), R.color.Grey);
int colorWhite = ContextCompat.getColor(requireContext(), android.R.color.white);
for (MaterialButton button : timeSlotButtons) {
if (button.getText().toString().equals(selectedTime)) {
// Selected state
button.setBackgroundTintList(ColorStateList.valueOf(colorPrimary));
button.setTextColor(colorWhite);
button.setStrokeColor(ColorStateList.valueOf(colorPrimary));
} else {
// Unselected state
button.setBackgroundTintList(ColorStateList.valueOf(colorWhite));
button.setTextColor(colorGrey);
button.setStrokeColor(ColorStateList.valueOf(colorGrey));
}
}
}
}
package com.example.qmsmakeappointment;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.checkbox.MaterialCheckBox;
import com.google.android.material.textfield.TextInputEditText;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Step4ConfirmFragment extends Fragment {
private static final int REQUEST_IMAGE_CAPTURE = 1;
private static final int REQUEST_IMAGE_PICK = 2;
private AppointmentViewModel viewModel;
private TextView summaryDateTime;
private Button editButton, confirmButton;
// Representative Attending Components
private MaterialCheckBox representativeCheckbox;
private LinearLayout photoSection, contactSection;
private Button addPhotoButton;
private CardView photoPreviewCard;
private ImageView photoPreview;
private ImageButton deletePhotoButton;
// Contact Form Input Fields
private TextInputEditText nameInput, contactInput, emailInput;
private Uri selectedImageUri;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_step_4_confirm, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// It's safer to check for context before proceeding
if (getContext() == null) {
return;
}
viewModel = new ViewModelProvider(requireActivity()).get(AppointmentViewModel.class);
// Bind UI components
summaryDateTime = view.findViewById(R.id.summary_date_time);
editButton = view.findViewById(R.id.edit_button_step4);
confirmButton = view.findViewById(R.id.confirm_button_step4);
// Representative Attending Components
representativeCheckbox = view.findViewById(R.id.representative_checkbox);
photoSection = view.findViewById(R.id.photo_section);
contactSection = view.findViewById(R.id.contact_section);
addPhotoButton = view.findViewById(R.id.add_photo_button);
photoPreviewCard = view.findViewById(R.id.photo_preview_card);
photoPreview = view.findViewById(R.id.photo_preview);
deletePhotoButton = view.findViewById(R.id.delete_photo_button);
// Contact Form Input Fields
nameInput = view.findViewById(R.id.name_input_edittext);
contactInput = view.findViewById(R.id.contact_input_edittext);
emailInput = view.findViewById(R.id.email_input_edittext);
// Update the summary text view
updateSummary();
// Enable button by default (or based on validation)
validateAndEnableButton();
// --- LISTENERS ---
// Add text watchers to validate form inputs
TextWatcher validationWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
validateAndEnableButton();
}
};
// Only add watchers if representative is attending
if (nameInput != null) nameInput.addTextChangedListener(validationWatcher);
if (contactInput != null) contactInput.addTextChangedListener(validationWatcher);
// Handle Representative Checkbox - Show confirmation dialog
representativeCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
// Show confirmation dialog
showRepresentativeAttendingDialog();
} else {
// Hide both sections
photoSection.setVisibility(View.GONE);
contactSection.setVisibility(View.GONE);
// Clear photo
selectedImageUri = null;
photoPreviewCard.setVisibility(View.GONE);
addPhotoButton.setVisibility(View.VISIBLE);
// Clear form
if (nameInput != null) nameInput.setText("");
if (contactInput != null) contactInput.setText("");
if (emailInput != null) emailInput.setText("");
// Update ViewModel
viewModel.setRepresentativeAttending(false);
viewModel.clearRepresentativeData();
// Re-validate button
validateAndEnableButton();
}
});
// Handle Add Photo Button
addPhotoButton.setOnClickListener(v -> showPhotoOptions());
// Handle Photo Preview Click (View full image)
photoPreview.setOnClickListener(v -> {
if (selectedImageUri != null) {
showImageDialog();
}
});
// Handle Delete Photo Button
deletePhotoButton.setOnClickListener(v -> {
new AlertDialog.Builder(requireContext())
.setTitle("Remove Media")
.setMessage("Are you sure you want to remove this photo?")
.setPositiveButton("Remove", (dialog, which) -> {
selectedImageUri = null;
photoPreviewCard.setVisibility(View.GONE);
addPhotoButton.setVisibility(View.VISIBLE);
contactSection.setVisibility(View.GONE);
})
.setNegativeButton("Cancel", null)
.show();
});
// Handle click on the "Edit" button
editButton.setOnClickListener(v -> {
// Go back to the very first step
getParentFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
((MainActivity) requireActivity()).loadFragment(new Step1DateFragment(), false);
});
// Handle click on the "Confirm" button
confirmButton.setOnClickListener(v -> {
// Validate and save form data before showing confirmation
if (validateAndSaveFormData()) {
// Show confirmation dialog before confirming
showConfirmAppointmentDialog();
}
});
}
/**
* Validate form inputs and enable/disable the confirm button
*/
private void validateAndEnableButton() {
boolean isValid = true;
// If representative is attending, validate required fields
if (representativeCheckbox.isChecked() && contactSection.getVisibility() == View.VISIBLE) {
String name = nameInput != null && nameInput.getText() != null ? nameInput.getText().toString().trim() : "";
String contact = contactInput != null && contactInput.getText() != null ? contactInput.getText().toString().trim() : "";
// Name and Contact are required (marked with *)
isValid = !name.isEmpty() && !contact.isEmpty();
}
// Enable button if valid
confirmButton.setEnabled(isValid);
}
/**
* Validate and save form data to ViewModel
* @return true if validation passes, false otherwise
*/
private boolean validateAndSaveFormData() {
// Check if representative is attending
boolean hasRepresentative = representativeCheckbox.isChecked();
viewModel.setRepresentativeAttending(hasRepresentative);
if (hasRepresentative) {
// Validate required fields
String name = nameInput != null && nameInput.getText() != null ? nameInput.getText().toString().trim() : "";
String contact = contactInput != null && contactInput.getText() != null ? contactInput.getText().toString().trim() : "";
String email = emailInput != null && emailInput.getText() != null ? emailInput.getText().toString().trim() : "";
if (name.isEmpty()) {
Toast.makeText(getContext(), "Please enter your full name", Toast.LENGTH_SHORT).show();
return false;
}
if (contact.isEmpty()) {
Toast.makeText(getContext(), "Please enter your contact number", Toast.LENGTH_SHORT).show();
return false;
}
// Save to ViewModel
viewModel.setRepresentativeName(name);
viewModel.setContactNumber(contact);
viewModel.setContactEmail(email.isEmpty() ? null : email);
} else {
// Clear representative data if not attending
viewModel.clearRepresentativeData();
}
return true;
}
/**
* Show dialog asking if user has any representative attending
*/
private void showRepresentativeAttendingDialog() {
new AlertDialog.Builder(requireContext())
.setTitle("Alert")
.setMessage("Do you have any representative attending?")
.setPositiveButton("Yes", (dialog, which) -> {
// User confirmed - show photo section
photoSection.setVisibility(View.VISIBLE);
viewModel.setRepresentativeAttending(true);
validateAndEnableButton();
// Contact section will be shown after photo is added
})
.setNegativeButton("No", (dialog, which) -> {
// User cancelled - uncheck the checkbox
representativeCheckbox.setChecked(false);
viewModel.setRepresentativeAttending(false);
validateAndEnableButton();
})
.setCancelable(false)
.show();
}
/**
* Show dialog to confirm appointment before final submission
*/
private void showConfirmAppointmentDialog() {
new AlertDialog.Builder(requireContext())
.setTitle("Alert")
.setMessage("Confirm make appointment?")
.setPositiveButton("Yes", (dialog, which) -> {
// User confirmed - show success dialog
showSuccessDialog();
})
.setNegativeButton("No", (dialog, which) -> {
// User cancelled - do nothing
dialog.dismiss();
})
.setCancelable(false)
.show();
}
/**
* Show success dialog after appointment is confirmed
*/
private void showSuccessDialog() {
new AlertDialog.Builder(requireContext())
.setTitle("Success")
.setMessage("You have successfully made an appointment.")
.setPositiveButton("OK", (dialog, which) -> {
// Save appointment to database via MainActivity
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).saveAppointment();
}
})
.setCancelable(false)
.show();
}
/**
* Show dialog with options to take photo or choose from gallery
*/
private void showPhotoOptions() {
new AlertDialog.Builder(requireContext())
.setTitle("Attach your authorization letter")
.setPositiveButton("Take Photo", (dialog, which) -> {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(requireActivity().getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
} else {
Toast.makeText(getContext(), "Camera not available", Toast.LENGTH_SHORT).show();
}
})
.setNeutralButton("Choose Photo", (dialog, which) -> {
Intent pickPhotoIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhotoIntent, REQUEST_IMAGE_PICK);
})
.setNegativeButton("Cancel", null)
.show();
}
/**
* Show full image dialog when user taps on the preview
*/
private void showImageDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
View dialogView = LayoutInflater.from(requireContext()).inflate(android.R.layout.simple_list_item_1, null);
ImageView fullImageView = new ImageView(requireContext());
fullImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
if (selectedImageUri != null) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(requireActivity().getContentResolver(), selectedImageUri);
fullImageView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
builder.setView(fullImageView)
.setPositiveButton("Close", null)
.setNegativeButton("Delete", (dialog, which) -> {
selectedImageUri = null;
photoPreviewCard.setVisibility(View.GONE);
addPhotoButton.setVisibility(View.VISIBLE);
contactSection.setVisibility(View.GONE);
})
.show();
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == getActivity().RESULT_OK) {
if (requestCode == REQUEST_IMAGE_CAPTURE && data != null) {
// Handle camera image
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap imageBitmap = (Bitmap) extras.get("data");
photoPreview.setImageBitmap(imageBitmap);
addPhotoButton.setVisibility(View.GONE);
photoPreviewCard.setVisibility(View.VISIBLE);
// Show contact section after photo is added
contactSection.setVisibility(View.VISIBLE);
validateAndEnableButton();
}
} else if (requestCode == REQUEST_IMAGE_PICK && data != null) {
// Handle gallery image
selectedImageUri = data.getData();
if (selectedImageUri != null) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(requireActivity().getContentResolver(), selectedImageUri);
photoPreview.setImageBitmap(bitmap);
addPhotoButton.setVisibility(View.GONE);
photoPreviewCard.setVisibility(View.VISIBLE);
// Show contact section after photo is added
contactSection.setVisibility(View.VISIBLE);
validateAndEnableButton();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getContext(), "Failed to load image", Toast.LENGTH_SHORT).show();
}
}
}
}
}
/**
* Updates the summary TextView with the date and time from the ViewModel.
*/
private void updateSummary() {
Long daysSinceEpoch = viewModel.getSelectedDate().getValue();
String time = viewModel.getSelectedTime().getValue();
// Ensure both date and time are available before updating the text
if (daysSinceEpoch != null && time != null) {
LocalDate date = LocalDate.ofEpochDay(daysSinceEpoch);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMM yyyy", Locale.getDefault());
summaryDateTime.setText(String.format("%s . %s", date.format(formatter), time));
}
}
}
package com.example.qmsmakeappointment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ScrollView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.Fragment;
public class TermsConditionsFragment extends Fragment {
private ScrollView termsScrollView;
private Button agreeNextButton;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_terms_conditions, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
termsScrollView = view.findViewById(R.id.terms_scroll_view);
agreeNextButton = view.findViewById(R.id.agree_next_button);
// Monitor scroll to enable button when user scrolls to bottom
termsScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> {
View contentView = termsScrollView.getChildAt(0);
if (contentView != null) {
int diff = contentView.getBottom() - (termsScrollView.getHeight() + termsScrollView.getScrollY());
// If scrolled to bottom (with small threshold for better UX)
if (diff <= 50) {
enableAgreeButton();
}
}
});
// Handle Agree and Next button click
agreeNextButton.setOnClickListener(v -> {
// Navigate to Step 1
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadFragment(new Step1DateFragment(), false);
}
});
}
/**
* Enable the Agree button and change its appearance
*/
private void enableAgreeButton() {
if (!agreeNextButton.isEnabled()) {
agreeNextButton.setEnabled(true);
agreeNextButton.setBackgroundTintList(
getResources().getColorStateList(R.color.colorPrimary, null)
);
}
}
}
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorPrimary"/>
</shape>
\ No newline at end of file
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#F0F0F0"/>
</shape>
\ No newline at end of file
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#4CAF50"/>
</shape>
\ No newline at end of file
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FFA500"/>
</shape>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#808080"
android:pathData="M14,2H6c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8l-6,-6zM16,18H8v-2h8v2zM16,14H8v-2h8v2zM13,9V3.5L18.5,9H13z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/colorPrimary"
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/colorPrimary"
android:pathData="M8.59,16.59L10,18l6,-6 -6,-6 -1.41,1.41L13.17,12z"/>
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F5F5F5" />
<corners android:radius="8dp" />
<padding
android:left="12dp"
android:top="8dp"
android:right="12dp"
android:bottom="8dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<stroke
android:width="2dp"
android:color="@color/colorPrimary" />
<corners android:radius="8dp" />
<padding
android:left="8dp"
android:top="8dp"
android:right="8dp"
android:bottom="8dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F5F5F5" />
<corners android:radius="8dp" />
<padding
android:left="12dp"
android:top="12dp"
android:right="12dp"
android:bottom="12dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/calendar_day_text"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:gravity="center"
android:textSize="14sp"
tools:text="22" />
<LinearLayout
android:id="@+id/dots_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="4dp" />
</FrameLayout>
\ No newline at end of file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
\ No newline at end of file
......@@ -6,8 +6,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:padding="24dp">
android:padding="16dp">
<!-- Header Section -->
<TextView
android:id="@+id/unit_label_header"
android:layout_width="wrap_content"
......@@ -27,49 +28,140 @@
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/unit_label_header" />
app:layout_constraintTop_toBottomOf="@+id/unit_label_header" />
<!-- Grey Info Box -->
<TextView
android:id="@+id/step_indicator"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Step 1/3: Select your preferred date."
android:textColor="@color/colorPrimary"
android:text="Step 1/3 : Select your preferred date."
android:textColor="@android:color/black"
android:textSize="14sp"
android:background="@drawable/info_box_background"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/unit_label" />
app:layout_constraintTop_toBottomOf="@+id/unit_label" />
<CalendarView
android:id="@+id/calendar_view"
<!-- Custom Calendar Header -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/calendar_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/step_indicator"
app:layout_constraintTop_toBottomOf="@id/step_indicator">
<ImageView
android:id="@+id/calendar_prev_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_chevron_left"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/legend"
android:id="@+id/calendar_month_year_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/calendar_next_button"
app:layout_constraintStart_toEndOf="@+id/calendar_prev_button"
app:layout_constraintTop_toTopOf="parent"
tools:text="January 2025" />
<ImageView
android:id="@+id/calendar_next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Legend: Green = Available, Red = Limited"
android:src="@drawable/ic_chevron_right"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Days of the Week -->
<LinearLayout
android:id="@+id/calendar_days_legend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/calendar_header">
<!-- Day Headers will be added programmatically -->
</LinearLayout>
<!-- Kizitonwose Custom Calendar View -->
<com.kizitonwose.calendar.view.CalendarView
android:id="@+id/calendar_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/calendar_view"
app:cv_dayViewResource="@layout/calendar_day_layout"
app:cv_orientation="horizontal"
app:cv_outDateStyle="endOfGrid"
app:cv_scrollPaged="true"
app:layout_constraintTop_toBottomOf="@+id/calendar_days_legend" />
<!-- Legend Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/legend_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="8dp"
app:strokeWidth="1dp"
app:strokeColor="#E0E0E0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/calendar_view">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<View
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/circle_green"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Available"
android:layout_marginStart="8dp"/>
<View
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="16dp"
android:background="@drawable/circle_orange"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Limited"
android:layout_marginStart="8dp"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Bottom Buttons -->
<LinearLayout
android:id="@+id/bottom_buttons"
android:layout_width="match_parent"
android:layout_height="85dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:paddingTop="16dp"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:id="@+id/back_button_step1"
android:layout_width="165dp"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
......@@ -78,21 +170,19 @@
android:backgroundTint="@color/white"
app:cornerRadius="20dp"
app:strokeColor="@color/colorPrimary"
app:strokeWidth="1dp"
/>
app:strokeWidth="1dp"/>
<Button
android:id="@+id/button_step1"
android:layout_width="165dp"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="Next"
android:textColor="@color/white"
android:enabled="false"
android:backgroundTint="@color/colorPrimary"
app:cornerRadius="20dp"
/>
android:enabled="false"
app:cornerRadius="20dp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -30,13 +30,15 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/unit_label_header_step2" />
<!-- Step Indicator -->
<!-- Grey Info Box -->
<TextView
android:id="@+id/step_indicator_step2"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Step 2/3: Select your preferred time."
android:textColor="@color/colorPrimary"
android:text="Step 2/3 : Select your preferred time."
android:textColor="@android:color/black"
android:textSize="14sp"
android:background="@drawable/info_box_background"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/unit_label_step2" />
......@@ -57,95 +59,103 @@
<Button
android:id="@+id/time_slot_0900"
android:text="09:00 AM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1000"
android:text="10:00 AM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1100"
android:text="11:00 AM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1200"
android:text="12:00 PM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1400"
android:text="14:00 PM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1500"
android:text="15:00 PM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1600"
android:text="16:00 PM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
<Button
android:id="@+id/time_slot_1700"
android:text="17:00 PM"
android:textColor="@android:color/black"
android:textColor="@color/Grey"
android:backgroundTint="@android:color/white"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
app:strokeColor="@color/black"
app:cornerRadius="13dp"
app:strokeColor="@color/Grey"
app:strokeWidth="1dp"/>
......
......@@ -5,7 +5,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
android:background="@android:color/white"
tools:context=".Step4ConfirmFragment">
<ScrollView
android:layout_width="match_parent"
......@@ -21,86 +22,194 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="For Unit No.: A-3-11"
android:text="For Unit No.:"
android:textSize="16sp"
android:textStyle="bold"
android:paddingTop="10dp"
android:paddingStart="15dp"/>
android:textColor="@color/Grey"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Step 3/3: Confirm your appointment."
android:textColor="@color/colorPrimary"
android:paddingTop="10dp"
android:paddingStart="15dp"/>
android:text="A-3-11"
android:textSize="16sp"
android:textStyle="bold"
android:layout_marginStart="16dp" />
<!-- Grey Info Box -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Step 3/3 : Confirm your appointment."
android:textColor="@android:color/black"
android:textSize="14sp"
android:background="@drawable/info_box_background"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your Appointment Summary"
android:textStyle="bold"
android:paddingTop="10dp"
android:paddingStart="15dp"/>
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"/>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardBackgroundColor="@color/colorPrimary"
app:cardCornerRadius="8dp"
app:cardElevation="0dp" >
<LinearLayout
app:cardElevation="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:padding="16dp">
<TextView
android:id="@+id/summary_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Handover"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:paddingTop="10dp"
android:paddingStart="15dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingTop="1dp"
android:paddingStart="15dp">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/summary_date_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="9 Jan 2025 . 09.00AM"
android:textColor="@android:color/white" />
tools:text="9 Jan 2025 . 09.00AM"
android:textColor="@android:color/white"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/summary_title" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tower"
android:layout_marginStart="90dp">
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:contentDescription="Tower Icon" />
</ImageView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<!-- Representative Attending Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Representative Attending?"
android:textStyle="bold"
android:textSize="16sp"/>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/representative_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"/>
</LinearLayout>
<!-- Photo Section (Hidden by default) -->
<LinearLayout
android:id="@+id/photo_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone">
<!-- Add Photo Button -->
<Button
android:id="@+id/add_photo_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Attach your authorization letter"
android:textColor="@color/colorPrimary"
android:backgroundTint="@android:color/white"
app:strokeColor="@color/colorPrimary"
app:strokeWidth="1dp"
app:cornerRadius="8dp"/>
<!-- Photo Preview (Hidden by default) -->
<androidx.cardview.widget.CardView
android:id="@+id/photo_preview_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp"
android:visibility="gone">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<ImageView
android:id="@+id/photo_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="Authorization Letter Preview"/>
<ImageButton
android:id="@+id/delete_photo_button"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_margin="8dp"
android:background="@android:color/white"
android:src="@android:drawable/ic_menu_delete"
android:contentDescription="Delete Photo"
android:padding="4dp"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
<!-- Contact Information Section (Hidden by default) -->
<LinearLayout
android:id="@+id/contact_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Representative Attending?"
android:text="Contact Information"
android:layout_marginTop="24dp"
android:textStyle="bold"
android:paddingTop="10dp"
android:paddingStart="15dp" />
android:layout_marginStart="16dp"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/name_input_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="* Name"
android:layout_marginTop="16dp">
android:layout_marginTop="8dp"
android:hint="Full Name*"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/name_input_edittext"
android:layout_width="match_parent"
......@@ -111,11 +220,13 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/contact_input_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="* Contact No."
android:layout_marginTop="16dp">
android:layout_marginTop="8dp"
android:hint="Contact Number*"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/contact_input_edittext"
android:layout_width="match_parent"
......@@ -125,17 +236,20 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/email_input_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Email Address"
android:layout_marginTop="16dp">
android:layout_marginTop="8dp"
android:hint="Email Address"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/email_input_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<TextView
android:layout_width="match_parent"
......@@ -143,29 +257,23 @@
android:layout_marginTop="24dp"
android:textStyle="bold"
android:text="Terms &amp; Conditions :"
android:paddingTop="10dp"
android:paddingStart="15dp"/>
android:layout_marginStart="16dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textSize="12sp"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer tristique, odio id pellentesque sodales, tincidunt velit in aliquet, in ac ultrices nulla..."
android:paddingTop="10dp"
android:paddingStart="15dp"/>
android:layout_marginStart="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Attach your authorisation letter"
android:layout_marginTop="24dp"
android:textColor="@color/colorPrimary"
android:paddingTop="10dp"
android:paddingStart="15dp"/>
</LinearLayout>
</ScrollView>
<!-- ... rest of your file (bottom_buttons_step4) ... -->
<LinearLayout
android:id="@+id/bottom_buttons_step4"
android:layout_width="match_parent"
......@@ -176,7 +284,7 @@
<Button
android:id="@+id/edit_button_step4"
android:layout_width="165dp"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_weight="1"
android:layout_marginEnd="8dp"
......@@ -185,16 +293,18 @@
android:backgroundTint="@color/white"
app:cornerRadius="20dp"
app:strokeColor="@color/colorPrimary"
app:strokeWidth="1dp"/>
app:strokeWidth="1dp" />
<Button
android:id="@+id/confirm_button_step4"
android:layout_width="165dp"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:text="Confirm"
android:text="Next"
android:textColor="@color/white"
android:backgroundTint="@color/colorPrimary"
android:enabled="false"
app:cornerRadius="20dp" />
</LinearLayout>
......
<?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"
android:background="@android:color/white"
tools:context=".TermsConditionsFragment">
<!-- Header Section - Aligned to Left -->
<TextView
android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Terms &amp; Conditions"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@android:color/black"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- Scrollable Terms Content -->
<ScrollView
android:id="@+id/terms_scroll_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="16dp"
android:background="@android:color/transparent"
app:layout_constraintTop_toBottomOf="@id/header_title"
app:layout_constraintBottom_toTopOf="@id/agree_next_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:background="@drawable/terms_grey_box_background">
<TextView
android:id="@+id/terms_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This Privacy Policy explains how Ashlar Properties (&quot;we&quot;, &quot;our&quot;, or &quot;us&quot;) collects, uses, and protects your personal information when you use our website, services, or mobile application. By using our Services, you agree to the terms outlined in this Privacy Policy.\n\nWhen you use our Services, we may collect personal information such as your name, email address, phone number, billing information, and other data you provide us during registration or use of the Services.\n\nWe may use cookies, web beacons, and similar tracking technologies to enhance your experience and gather information about your usage of our Services. You can control cookie settings through your browser preferences.\n\nWe use your information for the following purposes:\n\n• To provide and improve our Services.\n• To communicate with you and tailor our offerings to your preferences.\n• To comply with legal obligations and enforce our policies.\n• To protect the security and integrity of our Services and users.\n\nWe do not sell your personal information to third parties. We may share your information with:\n\n• Service providers who assist us in operating our business.\n• Legal authorities if required by law.\n• Business partners with your consent.\n\nYou have the right to:\n\n• Access, update, or delete your personal information.\n• Opt-out of marketing communications.\n• Request a copy of your data.\n\nWe implement industry-standard security measures to protect your information. However, no method of transmission over the internet is 100% secure.\n\nWe may update this Privacy Policy from time to time. We will notify you of significant changes by posting the updated policy on our website.\n\nBy clicking &quot;Agree and Next&quot;, you acknowledge that you have read, understood, and agree to be bound by these Terms &amp; Conditions."
android:textSize="12sp"
android:textColor="@android:color/black"
android:lineSpacingExtra="4dp" />
</LinearLayout>
</ScrollView>
<!-- Agree and Next Button -->
<Button
android:id="@+id/agree_next_button"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="32dp"
android:text="Agree and Next"
android:textColor="@android:color/white"
android:textSize="16sp"
android:backgroundTint="#9E9E9E"
android:enabled="false"
app:cornerRadius="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
......@@ -2,6 +2,8 @@
<!-- Base application theme. -->
<style name="Base.Theme.QMSMakeAppointment" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryVariant">@color/colorPrimary</item>
<item name="colorOnPrimary">@color/white</item>
</style>
</resources>
\ No newline at end of file
......@@ -3,7 +3,7 @@
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="colorPrimary">#0E7392</color>
<color name="Grey">#A0A0A0</color>
<!-- Standard colors (leave these) -->
<color name="purple_200">#FFBB86FC</color>
......
......@@ -2,7 +2,9 @@
<!-- Base application theme. -->
<style name="Base.Theme.QMSMakeAppointment" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryVariant">@color/colorPrimary</item>
<item name="colorOnPrimary">@color/white</item>
</style>
<style name="Theme.QMSMakeAppointment" parent="Base.Theme.QMSMakeAppointment" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment