diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListTask.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListTask.java index 14d1a74..497520a 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListTask.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListTask.java @@ -19,6 +19,8 @@ class ListTask extends Task { @Override protected void startImpl(long id) { + // Cancel Existing HTTP Calls + connection.cancelAll(); // Load Site Info Info info = new Info(); connection.send(info, infoResponse -> { diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/ItemDialog.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/ItemDialog.java index a027f1c..ec5833b 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/ItemDialog.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/ItemDialog.java @@ -10,16 +10,23 @@ import android.text.style.StyleSpan; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.fragment.app.DialogFragment; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.thebrokenrail.mtudining.R; import com.thebrokenrail.mtudining.api.method.PeriodDetail; +import java.util.ArrayList; +import java.util.List; + /** * Dialog for a food item. */ public class ItemDialog { + private static final String ALLERGEN_FILTER = "allergen"; + private static final String LABEL_FILTER = "label"; + /** * Fragment for dialog. */ @@ -57,30 +64,98 @@ public class ItemDialog { public static void show(Context context, PeriodDetail.Response.Menu.PeriodData.MenuCategory.MenuItem item) { // Build Message SpannableStringBuilder message = new SpannableStringBuilder(item.desc != null ? item.desc.trim() : ""); - if (message.length() > 0) { - message.append("\n\n"); + writeNewline(message, 2); + for (String filterType : new String[]{LABEL_FILTER, ALLERGEN_FILTER}) { + List filters = getFilters(item, filterType); + if (filters.size() > 0) { + writeNewline(message, 1); + @StringRes int filterName = filterType.equals(LABEL_FILTER) ? R.string.labels : R.string.allergens; + message.append(context.getString(filterName), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + for (String filter : filters) { + writeBullet(message, null, filter); + } + } } - message.append(context.getString(R.string.portion), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + writeNewline(message, 2); if (item.portion != null) { + message.append(context.getString(R.string.portion), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); message.append(item.portion); } - message.append('\n'); - message.append(context.getString(R.string.ingredients), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + writeNewline(message, 1); if (item.ingredients != null) { + message.append(context.getString(R.string.ingredients), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); message.append(item.ingredients); } - message.append('\n'); - message.append(context.getString(R.string.nutrients), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - for (PeriodDetail.Response.Menu.PeriodData.MenuCategory.MenuItem.Nutrient nutrient : item.nutrients) { - message.append('\n'); - message.append("• " + nutrient.name + ": ", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - if (nutrient.value != null) { - message.append(nutrient.value); + writeNewline(message, 2); + if (item.nutrients.size() > 0) { + message.append(context.getString(R.string.nutrients), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + for (PeriodDetail.Response.Menu.PeriodData.MenuCategory.MenuItem.Nutrient nutrient : item.nutrients) { + writeBullet(message, nutrient.name, nutrient.value); } } + // Remove Newlines From End + while (message.length() > 0 && message.charAt(message.length() - 1) == '\n') { + message.delete(message.length() - 1, message.length()); + } + // Show Fragment fragment = new Fragment(item.name, message); fragment.show(((MenuActivity) context).getSupportFragmentManager(), "item_" + item.name.hashCode()); } + + /** + * Get filters of a specific type in food item. + * @param item The item + * @param type The filter type + * @return List of filters + */ + private static List getFilters(PeriodDetail.Response.Menu.PeriodData.MenuCategory.MenuItem item, String type) { + List out = new ArrayList<>(); + for (PeriodDetail.Response.Menu.PeriodData.MenuCategory.MenuItem.Filter filter : item.filters) { + if (filter.type.equals(type)) { + out.add(filter.name); + } + } + return out; + } + + /** + * Write bullet point to string. + * @param message The string to modify + * @param name The first part + * @param value The second part + */ + private static void writeBullet(SpannableStringBuilder message, String name, String value) { + writeNewline(message, 1); + message.append("• ", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (name != null) { + message.append(name + ": ", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + message.append(value); + } + + /** + * Write newline to string. + * @param message The string to modify + * @param count The amount of newlines to write + */ + private static void writeNewline(SpannableStringBuilder message, int count) { + if (message.length() > 0) { + int existingCount = 0; + for (int i = message.length() - 1; i >= 0; i--) { + if (message.charAt(i) == '\n') { + existingCount++; + } else { + break; + } + } + count -= existingCount; + if (count > 0) { + for (int i = 0; i < count; i++) { + message.append('\n'); + } + } + } + } } diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuActivity.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuActivity.java index 4206a2d..bd85872 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuActivity.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuActivity.java @@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.appbar.MaterialToolbar; import com.thebrokenrail.mtudining.R; +import com.thebrokenrail.mtudining.util.DateUtil; import com.thebrokenrail.mtudining.util.EdgeToEdgeUtil; import java.io.UnsupportedEncodingException; @@ -112,8 +113,10 @@ public class MenuActivity extends AppCompatActivity { * @param newDate New date */ public void updateDate(Date newDate) { - viewModel.state.setDate(newDate); - viewModel.task.start(); + if (!DateUtil.toString(newDate).equals(DateUtil.toString(viewModel.state.getDate()))) { + viewModel.state.setDate(newDate); + viewModel.task.start(); + } } @Override diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuTask.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuTask.java index 6487089..f8d7c0b 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuTask.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuTask.java @@ -33,6 +33,8 @@ public class MenuTask extends Task { @Override protected void startImpl(long id) { + // Cancel Existing HTTP Calls + connection.cancelAll(); // Get Periods Periods periods = new Periods(Constants.PLATFORM, locationId, state.getDate()); connection.send(periods, periodsResponse -> { diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/task/Task.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/task/Task.java index 879132c..658a0ef 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/activity/task/Task.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/task/Task.java @@ -34,6 +34,7 @@ public abstract class Task { // Update Listeners sendDataToListeners(); } + /** * Implementation of {@link #start()}. * @param id Unique id for each call of {@link #start()} diff --git a/app/src/main/java/com/thebrokenrail/mtudining/api/Connection.java b/app/src/main/java/com/thebrokenrail/mtudining/api/Connection.java index fd8889c..2341d4e 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/api/Connection.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/api/Connection.java @@ -10,6 +10,8 @@ import com.squareup.moshi.Moshi; import com.thebrokenrail.mtudining.util.Constants; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -39,6 +41,11 @@ public class Connection { */ private final Handler mainThread = new Handler(Looper.getMainLooper()); + /** + * List of current HTTP calls. + */ + private final List calls = new ArrayList<>(); + /** * Send API method. * @param method API method @@ -56,7 +63,11 @@ public class Connection { .build(); // Call - client.newCall(request).enqueue(new Callback() { + Call call = client.newCall(request); + synchronized (calls) { + calls.add(call); + } + call.enqueue(new Callback() { private void error(Exception e) { // Print Error e.printStackTrace(); @@ -66,12 +77,20 @@ public class Connection { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { + synchronized (calls) { + calls.remove(call); + } + // Log Error error(e); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + synchronized (calls) { + calls.remove(call); + } try { + // Read Response try (ResponseBody responseBody = response.body()) { // Check Response if (!response.isSuccessful()) { @@ -96,4 +115,16 @@ public class Connection { } }); } + + /** + * Cancel all current calls. + */ + public void cancelAll() { + synchronized (calls) { + for (Call call : calls) { + call.cancel(); + } + calls.clear(); + } + } } diff --git a/app/src/main/java/com/thebrokenrail/mtudining/api/method/PeriodDetail.java b/app/src/main/java/com/thebrokenrail/mtudining/api/method/PeriodDetail.java index 47063fe..77765ba 100644 --- a/app/src/main/java/com/thebrokenrail/mtudining/api/method/PeriodDetail.java +++ b/app/src/main/java/com/thebrokenrail/mtudining/api/method/PeriodDetail.java @@ -40,11 +40,17 @@ public class PeriodDetail implements Method { public String value; } + public static class Filter { + public String name; + public String type; + } + public String name; public String desc; public String ingredients; public String portion; public List nutrients; + public List filters; public int sort_order; @Override diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ce66a16..97fc109 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,4 +12,6 @@ Portion:\u0020 Nutrients: Open Map + Labels: + Allergens: \ No newline at end of file