More Improvements!

This commit is contained in:
TheBrokenRail 2024-02-18 00:41:47 -05:00
parent 2da59312c5
commit 64f9fe7f63
11 changed files with 134 additions and 75 deletions

View File

@ -32,7 +32,6 @@ android {
dependencies { dependencies {
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0") implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
// OkHttp (For HTTP) // OkHttp (For HTTP)
implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Moshi (For JSON) // Moshi (For JSON)

View File

@ -36,6 +36,7 @@ public class ListActivity extends AppCompatActivity {
// Setup RecyclerView // Setup RecyclerView
adapter = new ListAdapter(viewModel.task); adapter = new ListAdapter(viewModel.task);
viewModel.task.sendDataToListeners();
RecyclerView recyclerView = findViewById(R.id.recycler_view); RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);

View File

@ -61,7 +61,9 @@ public class ItemDialog {
message.append("\n\n"); message.append("\n\n");
} }
message.append(context.getString(R.string.portion), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); message.append(context.getString(R.string.portion), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
message.append(item.portion); if (item.portion != null) {
message.append(item.portion);
}
message.append('\n'); message.append('\n');
message.append(context.getString(R.string.ingredients), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); message.append(context.getString(R.string.ingredients), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (item.ingredients != null) { if (item.ingredients != null) {

View File

@ -61,15 +61,14 @@ public class MenuActivity extends AppCompatActivity {
String name = getIntent().getStringExtra(NAME_EXTRA); String name = getIntent().getStringExtra(NAME_EXTRA);
toolbar.setTitle(name); toolbar.setTitle(name);
String id = getIntent().getStringExtra(ID_EXTRA); String id = getIntent().getStringExtra(ID_EXTRA);
if (!viewModel.task.isSetup()) { viewModel.task.setup(id);
viewModel.task.setup(id, new Date());
}
latitude = getIntent().getDoubleExtra(LATITUDE_EXTRA, 0); latitude = getIntent().getDoubleExtra(LATITUDE_EXTRA, 0);
longitude = getIntent().getDoubleExtra(LONGITUDE_EXTRA, 0); longitude = getIntent().getDoubleExtra(LONGITUDE_EXTRA, 0);
street = getIntent().getStringExtra(STREET_EXTRA); street = getIntent().getStringExtra(STREET_EXTRA);
// Setup RecyclerView // Setup RecyclerView
adapter = new MenuAdapter(viewModel.task); adapter = new MenuAdapter(viewModel.task, viewModel.state);
viewModel.task.sendDataToListeners();
RecyclerView recyclerView = findViewById(R.id.recycler_view); RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
@ -113,7 +112,7 @@ public class MenuActivity extends AppCompatActivity {
* @param newDate New date * @param newDate New date
*/ */
public void updateDate(Date newDate) { public void updateDate(Date newDate) {
viewModel.task.setup(null, newDate); viewModel.state.setDate(newDate);
viewModel.task.start(); viewModel.task.start();
} }

View File

@ -24,8 +24,14 @@ import java.util.Date;
* Adapter for listing dining halls. * Adapter for listing dining halls.
*/ */
class MenuAdapter extends TaskAdapter<MenuData> { class MenuAdapter extends TaskAdapter<MenuData> {
MenuAdapter(Task<MenuData> task) { /**
* Current state.
*/
private final MenuState state;
MenuAdapter(Task<MenuData> task, MenuState state) {
super(task); super(task);
this.state = state;
} }
@Override @Override
@ -43,8 +49,9 @@ class MenuAdapter extends TaskAdapter<MenuData> {
*/ */
private MenuData.Meal getMeal() { private MenuData.Meal getMeal() {
if (getResult() != null) { if (getResult() != null) {
String selectedMeal = state.getSelectedMeal();
for (MenuData.Meal meal : getResult().meals) { for (MenuData.Meal meal : getResult().meals) {
if (meal.name.equals(getResult().selectedMeal)) { if (meal.name.equals(selectedMeal)) {
// Found Meal // Found Meal
return meal; return meal;
} }
@ -93,8 +100,7 @@ class MenuAdapter extends TaskAdapter<MenuData> {
// Set Date // Set Date
CustomDropDownView dateField = view.findViewById(R.id.menu_date_field); CustomDropDownView dateField = view.findViewById(R.id.menu_date_field);
MaterialAutoCompleteTextView date = view.findViewById(R.id.menu_date); MaterialAutoCompleteTextView date = view.findViewById(R.id.menu_date);
// Retrieve from Task as this must show even when result is not available. Date current = state.getDate();
Date current = ((MenuTask) getTask()).getDate();
date.setText(DateUtil.toString(current)); date.setText(DateUtil.toString(current));
// Handle Click // Handle Click
dateField.setup(); dateField.setup();
@ -104,26 +110,28 @@ class MenuAdapter extends TaskAdapter<MenuData> {
}); });
// Set Meal // Set Meal
boolean hasMeal = getResult() != null; boolean isLoaded = getResult() != null;
TextInputLayout mealField = view.findViewById(R.id.menu_meal_field); TextInputLayout mealField = view.findViewById(R.id.menu_meal_field);
MaterialAutoCompleteTextView meal = view.findViewById(R.id.menu_meal); MaterialAutoCompleteTextView meal = view.findViewById(R.id.menu_meal);
if (hasMeal) { if (isLoaded) {
// Enable/Disable Field // Enable/Disable Field
hasMeal = getResult().meals.size() > 0; isLoaded = getResult().meals.size() > 0;
mealField.setEnabled(hasMeal); mealField.setEnabled(isLoaded);
if (hasMeal) { if (isLoaded) {
// Set Dropdown Options // Set Dropdown Options
meal.setSimpleItems(getResult().meals.stream().map(x -> x.name).toArray(String[]::new)); meal.setSimpleItems(getResult().meals.stream().map(x -> x.name).toArray(String[]::new));
// Set Selection // Set Selection
meal.setText(getResult().selectedMeal, false); meal.setText(state.getSelectedMeal(), false);
// Handle Meal Selection // Handle Meal Selection
meal.setOnItemClickListener((parent, view1, position, id) -> { meal.setOnItemClickListener((parent, view1, position, id) -> {
// Get New Meal // Get New Meal
String newMeal = (String) parent.getAdapter().getItem(position); String newMeal = (String) parent.getAdapter().getItem(position);
// Update UI // Update UI
int oldItemCount = getItemCount(); if (!newMeal.equals(state.getSelectedMeal())) {
getResult().selectedMeal = newMeal; int oldItemCount = getItemCount();
reloadUI(oldItemCount); state.setSelectedMeal(newMeal);
reloadUI(oldItemCount);
}
}); });
} else { } else {
// Show N/A // Show N/A

View File

@ -17,8 +17,5 @@ class MenuData {
this.name = name; this.name = name;
} }
} }
public final List<Meal> meals = new ArrayList<>(); public final List<Meal> meals = new ArrayList<>();
// This may be changed at runtime.
public String selectedMeal = null;
} }

View File

@ -0,0 +1,61 @@
package com.thebrokenrail.mtudining.activity.menu;
import androidx.lifecycle.SavedStateHandle;
import java.util.Date;
/**
* Current state of menu screen.
*/
public class MenuState {
private static final String DATE_KEY = "date";
private static final String SELECTED_MEAL_KEY = "selected_meal";
/**
* Data that should survive process-death.
*/
private final SavedStateHandle savedStateHandle;
public MenuState(SavedStateHandle savedStateHandle) {
this.savedStateHandle = savedStateHandle;
if (!savedStateHandle.contains(DATE_KEY)) {
setDate(new Date());
}
if (!savedStateHandle.contains(SELECTED_MEAL_KEY)) {
setSelectedMeal("");
}
}
/**
* Get currently selected date.
* @return The data
*/
@SuppressWarnings({"DataFlowIssue"})
public Date getDate() {
return new Date((long) savedStateHandle.get(DATE_KEY));
}
/**
* Set selected date.
* @param date The new date
*/
public void setDate(Date date) {
savedStateHandle.set(DATE_KEY, date.getTime());
}
/**
* Get currently selected meal.
* @return The meal
*/
public String getSelectedMeal() {
return savedStateHandle.get(SELECTED_MEAL_KEY);
}
/**
* Set selected meal.
* @param selectedMeal The new meal
*/
public void setSelectedMeal(String selectedMeal) {
savedStateHandle.set(SELECTED_MEAL_KEY, selectedMeal);
}
}

View File

@ -8,7 +8,6 @@ import com.thebrokenrail.mtudining.util.Category;
import com.thebrokenrail.mtudining.util.Constants; import com.thebrokenrail.mtudining.util.Constants;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
/** /**
* Task for loading menu information. * Task for loading menu information.
@ -17,44 +16,25 @@ public class MenuTask extends Task<MenuData> {
private final Connection connection; private final Connection connection;
private String locationId; private String locationId;
private Date date; private final MenuState state;
public MenuTask(Connection connection) { public MenuTask(Connection connection, MenuState state) {
this.connection = connection; this.connection = connection;
this.state = state;
} }
/** /**
* Setup task. * Setup task.
* @param locationId Location ID (or null to use existing) * @param locationId Location ID
* @param date Date
*/ */
void setup(String locationId, Date date) { void setup(String locationId) {
if (locationId != null) { this.locationId = locationId;
this.locationId = locationId;
}
this.date = date;
}
/**
* Check if task is setup.
* @return If the task is setup
*/
boolean isSetup() {
return locationId != null;
}
/**
* Get date.
* @return The date
*/
public Date getDate() {
return date;
} }
@Override @Override
protected void startImpl(long id) { protected void startImpl(long id) {
// Get Periods // Get Periods
Periods periods = new Periods(Constants.PLATFORM, locationId, date); Periods periods = new Periods(Constants.PLATFORM, locationId, state.getDate());
connection.send(periods, periodsResponse -> { connection.send(periods, periodsResponse -> {
// Loaded Periods // Loaded Periods
@ -69,7 +49,7 @@ public class MenuTask extends Task<MenuData> {
for (Periods.Response.Period period : periodsResponse.periods) { for (Periods.Response.Period period : periodsResponse.periods) {
// Load Period Details // Load Period Details
MenuData.Meal meal = new MenuData.Meal(period.id, period.name); MenuData.Meal meal = new MenuData.Meal(period.id, period.name);
PeriodDetail periodDetail = new PeriodDetail(Constants.PLATFORM, locationId, date, period.id); PeriodDetail periodDetail = new PeriodDetail(Constants.PLATFORM, locationId, state.getDate(), period.id);
connection.send(periodDetail, periodDetailResponse -> { connection.send(periodDetail, periodDetailResponse -> {
// Loaded Period Details // Loaded Period Details
@ -104,8 +84,6 @@ public class MenuTask extends Task<MenuData> {
}); });
data.meals.add(meal); data.meals.add(meal);
} }
// Set Selected Meal
data.selectedMeal = data.meals.get(0).name;
} else { } else {
// No Periods To Load // No Periods To Load
done(id, data); done(id, data);
@ -115,4 +93,29 @@ public class MenuTask extends Task<MenuData> {
done(id, null); done(id, null);
}); });
} }
@Override
protected void done(long id, MenuData obj) {
// Update Selected Meal If Needed
if (obj != null && obj.meals.size() > 0) {
boolean currentSelectedMealIsValid = false;
String selectedMeal = state.getSelectedMeal();
if (selectedMeal != null) {
// Check If Current Selection Is Valid
for (MenuData.Meal meal : obj.meals) {
if (selectedMeal.equals(meal.name)) {
currentSelectedMealIsValid = true;
break;
}
}
}
if (!currentSelectedMealIsValid) {
// Current Selection Is Invalid, Change It
state.setSelectedMeal(obj.meals.get(0).name);
}
}
// Call Parent
super.done(id, obj);
}
} }

View File

@ -1,8 +1,8 @@
package com.thebrokenrail.mtudining.activity.menu; package com.thebrokenrail.mtudining.activity.menu;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import com.thebrokenrail.mtudining.activity.task.Task;
import com.thebrokenrail.mtudining.api.Connection; import com.thebrokenrail.mtudining.api.Connection;
/** /**
@ -10,5 +10,11 @@ import com.thebrokenrail.mtudining.api.Connection;
*/ */
public class MenuViewModel extends ViewModel { public class MenuViewModel extends ViewModel {
private final Connection connection = new Connection(); private final Connection connection = new Connection();
public final MenuTask task = new MenuTask(connection); public final MenuState state;
public final MenuTask task;
public MenuViewModel(SavedStateHandle savedStateHandle) {
state = new MenuState(savedStateHandle);
task = new MenuTask(connection, state);
}
} }

View File

@ -29,6 +29,7 @@ public abstract class Task<E> {
public void start() { public void start() {
lastStart = System.currentTimeMillis(); lastStart = System.currentTimeMillis();
status = Status.IN_PROGRESS; status = Status.IN_PROGRESS;
result = null;
startImpl(lastStart); startImpl(lastStart);
// Update Listeners // Update Listeners
sendDataToListeners(); sendDataToListeners();
@ -95,25 +96,15 @@ public abstract class Task<E> {
public void addListener(Listener<E> listener) { public void addListener(Listener<E> listener) {
if (!listeners.contains(listener)) { if (!listeners.contains(listener)) {
listeners.add(listener); listeners.add(listener);
// Send Data
sendDataToListener(listener);
} }
} }
/**
* Send data to specific listener.
* @param listener The listener
*/
private void sendDataToListener(Listener<E> listener) {
listener.update(status, status == Status.DONE ? result : null);
}
/** /**
* Send data to all listeners. * Send data to all listeners.
*/ */
private void sendDataToListeners() { public void sendDataToListeners() {
for (Listener<E> listener : listeners) { for (Listener<E> listener : listeners) {
sendDataToListener(listener); listener.update(status, status == Status.DONE ? result : null);
} }
} }

View File

@ -208,12 +208,4 @@ public abstract class TaskAdapter<E> extends RecyclerView.Adapter<RecyclerView.V
// Add Items // Add Items
notifyItemRangeInserted(1, getItemCount() - 1); notifyItemRangeInserted(1, getItemCount() - 1);
} }
/**
* Get task.
* @return The task
*/
public Task<E> getTask() {
return task;
}
} }