diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7356e55..8f200e8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,13 +17,16 @@
+ android:exported="true">
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/MenuActivity.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/MenuActivity.java
deleted file mode 100644
index 3c1c284..0000000
--- a/app/src/main/java/com/thebrokenrail/mtudining/activity/MenuActivity.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.thebrokenrail.mtudining.activity;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-/**
- * This activity lists the menu for a given dining hall.
- */
-public class MenuActivity extends AppCompatActivity {
-}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListActivity.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListActivity.java
index 80b406e..2edeb7e 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListActivity.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListActivity.java
@@ -14,7 +14,7 @@ import com.thebrokenrail.mtudining.R;
import com.thebrokenrail.mtudining.util.EdgeToEdgeUtil;
/**
- * This activity lists the available food halls.
+ * This activity lists the available dining halls.
*/
public class ListActivity extends AppCompatActivity {
private ListAdapter adapter;
@@ -41,4 +41,10 @@ public class ListActivity extends AppCompatActivity {
recyclerView.setAdapter(adapter);
EdgeToEdgeUtil.setup(this, recyclerView);
}
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ adapter.onDestroy();
+ }
}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListAdapter.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListAdapter.java
index 584d845..3801013 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListAdapter.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListAdapter.java
@@ -1,15 +1,13 @@
package com.thebrokenrail.mtudining.activity.list;
-import android.util.TypedValue;
+import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import androidx.annotation.NonNull;
-import androidx.appcompat.widget.AppCompatTextView;
import androidx.recyclerview.widget.RecyclerView;
-import com.thebrokenrail.mtudining.R;
+import com.thebrokenrail.mtudining.activity.menu.MenuActivity;
import com.thebrokenrail.mtudining.activity.task.Task;
import com.thebrokenrail.mtudining.activity.task.TaskAdapter;
import com.thebrokenrail.mtudining.widget.CategoryView;
@@ -17,60 +15,40 @@ import com.thebrokenrail.mtudining.widget.CategoryView;
/**
* Adapter for listing dining halls.
*/
-public class ListAdapter extends TaskAdapter {
- public static class ViewHolder extends RecyclerView.ViewHolder {
- private final CategoryView view;
- private ViewHolder(@NonNull View itemView) {
- super(itemView);
- view = (CategoryView) itemView;
- }
- }
-
- public ListAdapter(Task task) {
+class ListAdapter extends TaskAdapter {
+ ListAdapter(Task task) {
super(task);
}
@Override
- protected ViewHolder createItemViewHolder(@NonNull ViewGroup parent) {
+ protected View createItemView(@NonNull ViewGroup parent) {
// Create View
CategoryView category = new CategoryView(parent.getContext(), null);
RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT);
category.setLayoutParams(layoutParams);
- return new ViewHolder(category);
+ return category;
}
@Override
- protected void bindDataViewHolder(@NonNull ViewHolder holder, int position) {
- ListData.Category data = getResult().categories.get(position);
+ protected void bindItemView(View view, int position) {
+ ListData.Category data = getResult().categories.get(position - getFirstElementPosition());
// Setup View
- holder.view.setup(data.isOpen, data.name, () -> {
+ CategoryView category = (CategoryView) view;
+ category.setup(data.isOpen, data.name, () -> {
// Open/Close Category
data.isOpen = !data.isOpen;
- notifyItemChanged(getResult().categories.indexOf(data));
+ notifyItemChanged(getResult().categories.indexOf(data) + getFirstElementPosition());
});
// Add Locations
- holder.view.children.removeAllViews();
- for (ListData.Element location : data.locations) {
- AppCompatTextView item = new AppCompatTextView(holder.view.getContext());
- // Text
- item.setText(location.name);
- // Text Size
- item.setTextSize(TypedValue.COMPLEX_UNIT_PX, item.getResources().getDimension(R.dimen.item_font_size));
- // Padding
- int margin = holder.view.getResources().getDimensionPixelSize(R.dimen.margin);
- item.setPadding(margin, margin, margin, margin);
- // Make Clickable
- item.setClickable(true);
- item.setFocusable(true);
- // Ripple Effect
- TypedValue outValue = new TypedValue();
- holder.view.getContext().getTheme().resolveAttribute(androidx.appcompat.R.attr.selectableItemBackground, outValue, true);
- item.setBackgroundResource(outValue.resourceId);
- // Layout
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- item.setLayoutParams(layoutParams);
- // Add To View
- holder.view.children.addView(item);
+ category.clearItems();
+ for (ListData.Category.Element location : data.locations) {
+ category.addItem(location.name, () -> {
+ // Open Menu
+ Intent intent = new Intent(category.getContext(), MenuActivity.class);
+ intent.putExtra(MenuActivity.ID_EXTRA, location.id);
+ intent.putExtra(MenuActivity.NAME_EXTRA, location.name);
+ category.getContext().startActivity(intent);
+ });
}
}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListData.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListData.java
index ccbc168..b8f781a 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListData.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListData.java
@@ -6,18 +6,18 @@ import java.util.List;
/**
* Data to be displayed in {@link ListActivity}.
*/
-public class ListData {
- public static class Element {
- public final String id;
- public final String name;
-
- public Element(String id, String name) {
- this.id = id;
- this.name = name;
- }
- }
-
+class ListData {
public static class Category {
+ public static class Element {
+ public final String id;
+ public final String name;
+
+ public Element(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
public final String name;
public boolean isOpen = true;
public final List locations = new ArrayList<>();
@@ -30,7 +30,7 @@ public class ListData {
public final String siteId;
public final List categories = new ArrayList<>();
- public ListData(String siteId) {
+ ListData(String siteId) {
this.siteId = siteId;
}
}
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
new file mode 100644
index 0000000..9bb64b2
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListTask.java
@@ -0,0 +1,56 @@
+package com.thebrokenrail.mtudining.activity.list;
+
+import com.thebrokenrail.mtudining.activity.task.Task;
+import com.thebrokenrail.mtudining.api.Connection;
+import com.thebrokenrail.mtudining.api.method.AllLocations;
+import com.thebrokenrail.mtudining.api.method.Info;
+import com.thebrokenrail.mtudining.util.Constants;
+
+/**
+ * Task for retrieving site ID and list of dining halls.
+ */
+class ListTask extends Task {
+ private final Connection connection;
+
+ ListTask(Connection connection) {
+ this.connection = connection;
+ }
+
+ @Override
+ protected void startImpl(long id) {
+ // Load Site Info
+ Info info = new Info();
+ connection.send(info, infoResponse -> {
+ // Load Locations
+ AllLocations allLocations = new AllLocations(Constants.PLATFORM, infoResponse.site.id, true, false, true);
+ connection.send(allLocations, allLocationsResponse -> {
+ // Success
+ ListData data = new ListData(infoResponse.site.id);
+ // Find Active Locations
+ for (AllLocations.Response.Building building : allLocationsResponse.buildings) {
+ if (building.active) {
+ // Found Active Building
+ ListData.Category category = new ListData.Category(building.name);
+ for (AllLocations.Response.Location location : building.locations) {
+ if (location.active) {
+ // Found Active Location
+ category.locations.add(new ListData.Category.Element(location.id, location.name));
+ }
+ }
+ // Skip Empty Category
+ if (category.locations.size() > 0) {
+ data.categories.add(category);
+ }
+ }
+ }
+ done(id, data);
+ }, () -> {
+ // Failed Fetching Location Info
+ done(id, null);
+ });
+ }, () -> {
+ // Failed Fetching Site Info
+ done(id, null);
+ });
+ }
+}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListViewModel.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListViewModel.java
index 1891b44..100a897 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListViewModel.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/list/ListViewModel.java
@@ -4,52 +4,11 @@ import androidx.lifecycle.ViewModel;
import com.thebrokenrail.mtudining.activity.task.Task;
import com.thebrokenrail.mtudining.api.Connection;
-import com.thebrokenrail.mtudining.api.method.AllLocations;
-import com.thebrokenrail.mtudining.api.method.Info;
-import com.thebrokenrail.mtudining.util.Constants;
/**
* Data preserved between screen rotations for {@link ListActivity}.
*/
public class ListViewModel extends ViewModel {
private final Connection connection = new Connection();
- public final Task task = new Task() {
- @Override
- protected void startImpl() {
- // Load Site Info
- Info info = new Info();
- connection.send(info, infoResponse -> {
- // Load Locations
- AllLocations allLocations = new AllLocations(Constants.PLATFORM, infoResponse.site.id, true, false, true);
- connection.send(allLocations, allLocationsResponse -> {
- // Success
- ListData data = new ListData(infoResponse.site.id);
- // Find Active Locations
- for (AllLocations.Response.Building building : allLocationsResponse.buildings) {
- if (building.active) {
- // Found Active Building
- ListData.Category category = new ListData.Category(building.name);
- for (AllLocations.Response.Location location : building.locations) {
- if (location.active) {
- // Found Active Location
- category.locations.add(new ListData.Element(location.id, location.name));
- }
- }
- // Skip Empty Category
- if (category.locations.size() > 0) {
- data.categories.add(category);
- }
- }
- }
- done(data);
- }, () -> {
- // Failed Fetching Location Info
- done(null);
- });
- }, () -> {
- // Failed Fetching Site Info
- done(null);
- });
- }
- };
+ public final Task task = new ListTask(connection);
}
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
new file mode 100644
index 0000000..db04bbb
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuActivity.java
@@ -0,0 +1,76 @@
+package com.thebrokenrail.mtudining.activity.menu;
+
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import androidx.activity.EdgeToEdge;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.appbar.MaterialToolbar;
+import com.thebrokenrail.mtudining.R;
+import com.thebrokenrail.mtudining.util.EdgeToEdgeUtil;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * This activity lists the menu for a dining hall.
+ */
+public class MenuActivity extends AppCompatActivity {
+ public static final String NAME_EXTRA = "mtu_name";
+ public static final String ID_EXTRA = "mtu_id";
+
+ private MenuAdapter adapter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Setup UI
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.activity_list);
+
+ // Toolbar
+ MaterialToolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
+
+ // Get View Model
+ ViewModelProvider viewModelProvider = new ViewModelProvider(this);
+ MenuViewModel viewModel = viewModelProvider.get(MenuViewModel.class);
+
+ // Get Info
+ String name = getIntent().getStringExtra(NAME_EXTRA);
+ String id = getIntent().getStringExtra(ID_EXTRA);
+ toolbar.setTitle(name);
+ viewModel.task.setup(id, new Date());
+
+ // Setup RecyclerView
+ adapter = new MenuAdapter(viewModel.task);
+ RecyclerView recyclerView = findViewById(R.id.recycler_view);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ recyclerView.setAdapter(adapter);
+ EdgeToEdgeUtil.setup(this, recyclerView);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ adapter.onDestroy();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ // Make back button in toolbar act as normal back button.
+ if (item.getItemId() == android.R.id.home) {
+ getOnBackPressedDispatcher().onBackPressed();
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuAdapter.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuAdapter.java
new file mode 100644
index 0000000..53c7aa6
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuAdapter.java
@@ -0,0 +1,82 @@
+package com.thebrokenrail.mtudining.activity.menu;
+
+import android.text.InputType;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.textfield.MaterialAutoCompleteTextView;
+import com.google.android.material.textfield.TextInputEditText;
+import com.google.android.material.textfield.TextInputLayout;
+import com.thebrokenrail.mtudining.R;
+import com.thebrokenrail.mtudining.activity.task.Task;
+import com.thebrokenrail.mtudining.activity.task.TaskAdapter;
+import com.thebrokenrail.mtudining.util.DateUtil;
+import com.thebrokenrail.mtudining.widget.CategoryView;
+
+/**
+ * Adapter for listing dining halls.
+ */
+class MenuAdapter extends TaskAdapter {
+ MenuAdapter(Task task) {
+ super(task);
+ }
+
+ @Override
+ protected View createItemView(@NonNull ViewGroup parent) {
+ // Create View
+ CategoryView category = new CategoryView(parent.getContext(), null);
+ RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT);
+ category.setLayoutParams(layoutParams);
+ return category;
+ }
+
+ @Override
+ protected void bindItemView(View view, int position) {
+ /*ListData.Category data = getResult().categories.get(position);
+ // Setup View
+ CategoryView category = (CategoryView) view;
+ category.setup(data.isOpen, data.name, () -> {
+ // Open/Close Category
+ data.isOpen = !data.isOpen;
+ notifyItemChanged(getResult().categories.indexOf(data));
+ });
+ // Add Locations
+ category.clearItems();
+ for (ListData.Category.Element location : data.locations) {
+ category.addItem(location.name, () -> {
+ // Do Something!
+ });
+ }*/
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 0;
+ }
+
+ @Override
+ protected View createHeader(@NonNull ViewGroup parent) {
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ return layoutInflater.inflate(R.layout.menu_header, parent, false);
+ }
+
+ @Override
+ protected void bindHeader(View view) {
+ // Set Date
+ MaterialAutoCompleteTextView date = view.findViewById(R.id.menu_date);
+ // Retrieve from Task as this must show even when result is not available.
+ date.setText(DateUtil.toString(((MenuTask) getTask()).getDate()));
+
+ // Set Meal
+ boolean hasMeal = getResult() != null;
+ TextInputLayout meal = view.findViewById(R.id.menu_meal_field);
+ meal.setEnabled(hasMeal);
+ if (hasMeal) {
+
+ }
+ }
+}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuData.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuData.java
new file mode 100644
index 0000000..5028c34
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuData.java
@@ -0,0 +1,42 @@
+package com.thebrokenrail.mtudining.activity.menu;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MenuData {
+ public static class Meal {
+ public static class Category {
+ public static class Element {
+ public final String id;
+ public final String name;
+ public final String description;
+
+ public Element(String id, String name, String description) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ }
+ }
+
+ public final String name;
+ public boolean isOpen = true;
+ public final List locations = new ArrayList<>();
+
+ public Category(String name) {
+ this.name = name;
+ }
+ }
+
+ public final String id;
+ public final String name;
+ public final List categories = new ArrayList<>();
+
+ public Meal(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+ public final List meals = new ArrayList<>();
+ public String selectedMeal;
+}
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
new file mode 100644
index 0000000..0062db9
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuTask.java
@@ -0,0 +1,55 @@
+package com.thebrokenrail.mtudining.activity.menu;
+
+import com.thebrokenrail.mtudining.activity.task.Task;
+import com.thebrokenrail.mtudining.api.Connection;
+import com.thebrokenrail.mtudining.api.method.Periods;
+import com.thebrokenrail.mtudining.util.Constants;
+
+import java.util.Date;
+
+public class MenuTask extends Task {
+ private final Connection connection;
+
+ private String locationId;
+ private Date date;
+
+ public MenuTask(Connection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Setup task.
+ * @param locationId Location ID (or null to use existing)
+ * @param date Date
+ */
+ void setup(String locationId, Date date) {
+ if (locationId != null) {
+ this.locationId = locationId;
+ }
+ this.date = date;
+ }
+
+ /**
+ * Get date.
+ * @return The date
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ @Override
+ protected void startImpl(long id) {
+ // Get Periods
+ Periods periods = new Periods(Constants.PLATFORM, locationId, date);
+ connection.send(periods, periodsResponse -> {
+ // Loaded Periods
+ for (Periods.Response.Period period : periodsResponse.periods) {
+ System.out.println("Period: " + period.name);
+ }
+ done(id, null);
+ }, () -> {
+ // Error
+ done(id, null);
+ });
+ }
+}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuViewModel.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuViewModel.java
new file mode 100644
index 0000000..ad58d19
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/menu/MenuViewModel.java
@@ -0,0 +1,14 @@
+package com.thebrokenrail.mtudining.activity.menu;
+
+import androidx.lifecycle.ViewModel;
+
+import com.thebrokenrail.mtudining.activity.task.Task;
+import com.thebrokenrail.mtudining.api.Connection;
+
+/**
+ * Data preserved between screen rotations for {@link MenuActivity}.
+ */
+public class MenuViewModel extends ViewModel {
+ private final Connection connection = new Connection();
+ public final MenuTask task = new MenuTask(connection);
+}
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 80d2271..bbc6d7e 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
@@ -18,19 +18,26 @@ public abstract class Task {
}
private Status status = Status.NOT_STARTED;
+ /**
+ * Last time when {@link #start()} was called.
+ */
+ private long lastStart;
+
/**
* Start task.
*/
public void start() {
+ lastStart = System.currentTimeMillis();
status = Status.IN_PROGRESS;
- startImpl();
+ startImpl(lastStart);
// Update Listeners
sendDataToListeners();
}
/**
* Implementation of {@link #start()}.
+ * @param id Unique id for each call of {@link #start()}
*/
- protected abstract void startImpl();
+ protected abstract void startImpl(long id);
/**
* Currently stored result (or null if none).
@@ -39,9 +46,16 @@ public abstract class Task {
/**
* Store result.
+ * @param id ID from {@link #startImpl(long)}
* @param obj Result (or null if error)
*/
- protected void done(E obj) {
+ protected void done(long id, E obj) {
+ // Check ID
+ if (id != lastStart) {
+ // Ignore
+ return;
+ }
+ // Store
result = obj;
// Update Status
if (obj == null) {
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/activity/task/TaskAdapter.java b/app/src/main/java/com/thebrokenrail/mtudining/activity/task/TaskAdapter.java
index 98d887f..d94e292 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/activity/task/TaskAdapter.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/activity/task/TaskAdapter.java
@@ -1,18 +1,21 @@
package com.thebrokenrail.mtudining.activity.task;
+import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
+import com.thebrokenrail.mtudining.R;
import com.thebrokenrail.mtudining.widget.LoaderView;
/**
* RecyclerView adapter for a given {@link Task}.
*/
-public abstract class TaskAdapter extends RecyclerView.Adapter implements Task.Listener {
+public abstract class TaskAdapter extends RecyclerView.Adapter implements Task.Listener {
public static final int LOADER_TYPE = 1;
- public static final int DATA_TYPE = 0;
+ public static final int ITEM_TYPE = 0;
+ public static final int HEADER_TYPE = 2;
/**
* The task.
@@ -56,11 +59,25 @@ public abstract class TaskAdapter extends
}
/**
- * Create view holder for item in task's result.
+ * Create view for item in task's result.
* @param parent The view parent
- * @return The new view holder
+ * @return The new view
*/
- protected abstract VH createItemViewHolder(@NonNull ViewGroup parent);
+ protected abstract View createItemView(@NonNull ViewGroup parent);
+
+ /**
+ * Create view for header.
+ * @param parent The view parent
+ * @return The new view
+ */
+ protected View createHeader(@NonNull ViewGroup parent) {
+ // Just Create Margin
+ View view = new View(parent.getContext());
+ int margin = parent.getResources().getDimensionPixelSize(R.dimen.margin);
+ RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, margin);
+ view.setLayoutParams(layoutParams);
+ return view;
+ }
@NonNull
@Override
@@ -71,9 +88,12 @@ public abstract class TaskAdapter extends
RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT);
loader.setLayoutParams(layoutParams);
return new RecyclerView.ViewHolder(loader) {};
- } else if (viewType == DATA_TYPE) {
+ } else if (viewType == ITEM_TYPE) {
// Data
- return createItemViewHolder(parent);
+ return new RecyclerView.ViewHolder(createItemView(parent)) {};
+ } else if (viewType == HEADER_TYPE) {
+ // Header
+ return new RecyclerView.ViewHolder(createHeader(parent)) {};
} else {
// Unknown
throw new RuntimeException();
@@ -81,22 +101,31 @@ public abstract class TaskAdapter extends
}
/**
- * Bind view holder for item in task's result.
- * @param holder The view holder
+ * Bind view for item in task's result.
+ * @param view The view
* @param position The item's position
*/
- protected abstract void bindDataViewHolder(@NonNull VH holder, int position);
+ protected abstract void bindItemView(View view, int position);
+
+ /**
+ * Bind view for header.
+ * @param view The view
+ */
+ protected void bindHeader(View view) {
+ }
- @SuppressWarnings({"unchecked"})
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
int type = getItemViewType(position);
if (type == LOADER_TYPE) {
// Loader
((LoaderView) holder.itemView).setup(currentStatus == Task.Status.ERROR, task::start);
- } else if (type == DATA_TYPE) {
+ } else if (type == ITEM_TYPE) {
// Data
- bindDataViewHolder((VH) holder, position);
+ bindItemView(holder.itemView, position);
+ } else if (type == HEADER_TYPE) {
+ // Header
+ bindHeader(holder.itemView);
}
}
@@ -108,23 +137,39 @@ public abstract class TaskAdapter extends
@Override
public int getItemCount() {
+ int size;
if (currentStatus != Task.Status.DONE) {
// Only Loader
- return 1;
+ size = 1;
} else {
// Data Size
- return getDataSize();
+ size = getDataSize();
}
+ // Header
+ size++;
+ // Return
+ return size;
+ }
+
+ /**
+ * Get position of first non-header element.
+ * @return Element position
+ */
+ public int getFirstElementPosition() {
+ return 1;
}
@Override
public int getItemViewType(int position) {
- if (currentStatus != Task.Status.DONE && position == 0) {
+ if (currentStatus != Task.Status.DONE && position == getFirstElementPosition()) {
// Loader
return LOADER_TYPE;
+ } else if (position == 0) {
+ // Header
+ return HEADER_TYPE;
} else {
- // Data
- return DATA_TYPE;
+ // Item
+ return ITEM_TYPE;
}
}
@@ -160,4 +205,12 @@ public abstract class TaskAdapter extends
// Add Items
notifyItemRangeInserted(0, getItemCount());
}
+
+ /**
+ * Get task.
+ * @return The task
+ */
+ public Task getTask() {
+ return task;
+ }
}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/api/method/Periods.java b/app/src/main/java/com/thebrokenrail/mtudining/api/method/Periods.java
new file mode 100644
index 0000000..60daf99
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/api/method/Periods.java
@@ -0,0 +1,38 @@
+package com.thebrokenrail.mtudining.api.method;
+
+import com.thebrokenrail.mtudining.api.Method;
+import com.thebrokenrail.mtudining.util.DateUtil;
+
+import java.util.Date;
+import java.util.List;
+
+public class Periods implements Method {
+ private final int platform;
+ private final String locationId;
+ private final String date;
+
+ public Periods(int platform, String locationId, Date date) {
+ this.platform = platform;
+ this.locationId = locationId;
+ this.date = DateUtil.toString(date);
+ }
+
+ @Override
+ public String getPath() {
+ return "/location/" + locationId + "/periods?platform=" + platform + "&date=" + date;
+ }
+
+ @Override
+ public Class getResponseClass() {
+ return Response.class;
+ }
+
+ public static class Response {
+ public static class Period {
+ public String id;
+ public int sort_order;
+ public String name;
+ }
+ public List periods;
+ }
+}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/util/DateUtil.java b/app/src/main/java/com/thebrokenrail/mtudining/util/DateUtil.java
new file mode 100644
index 0000000..b391d74
--- /dev/null
+++ b/app/src/main/java/com/thebrokenrail/mtudining/util/DateUtil.java
@@ -0,0 +1,13 @@
+package com.thebrokenrail.mtudining.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class DateUtil {
+ public static String toString(Date date) {
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+ return df.format(date);
+ }
+}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/widget/CategoryView.java b/app/src/main/java/com/thebrokenrail/mtudining/widget/CategoryView.java
index 744c136..3b3bbad 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/widget/CategoryView.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/widget/CategoryView.java
@@ -19,7 +19,7 @@ import com.thebrokenrail.mtudining.R;
*/
public class CategoryView extends FrameLayout {
private final MaterialCardView card;
- public final LinearLayout children;
+ private final LinearLayout children;
private final AppCompatTextView title;
public CategoryView(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -31,7 +31,7 @@ public class CategoryView extends FrameLayout {
// Set Margin
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
int margin = getResources().getDimensionPixelSize(R.dimen.margin);
- layoutParams.setMargins(margin, margin, margin, margin);
+ layoutParams.setMargins(margin, 0, margin, margin);
inner.setLayoutParams(layoutParams);
// Add Title
@@ -74,4 +74,40 @@ public class CategoryView extends FrameLayout {
card.setVisibility(isOpen ? VISIBLE : GONE);
title.setOnClickListener(v -> onClickTitle.run());
}
+
+ /**
+ * Clear category.
+ */
+ public void clearItems() {
+ children.removeAllViews();
+ }
+
+ /**
+ * Add item.
+ * @param name Item name
+ * @param onClick Click handler
+ */
+ public void addItem(String name, Runnable onClick) {
+ AppCompatTextView item = new AppCompatTextView(getContext());
+ // Text
+ item.setText(name);
+ // Text Size
+ item.setTextSize(TypedValue.COMPLEX_UNIT_PX, item.getResources().getDimension(R.dimen.item_font_size));
+ // Padding
+ int margin = getResources().getDimensionPixelSize(R.dimen.margin);
+ item.setPadding(margin, margin, margin, margin);
+ // Make Clickable
+ item.setClickable(true);
+ item.setFocusable(true);
+ item.setOnClickListener(v -> onClick.run());
+ // Ripple Effect
+ TypedValue outValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(androidx.appcompat.R.attr.selectableItemBackground, outValue, true);
+ item.setBackgroundResource(outValue.resourceId);
+ // Layout
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ item.setLayoutParams(layoutParams);
+ // Add To View
+ children.addView(item);
+ }
}
diff --git a/app/src/main/java/com/thebrokenrail/mtudining/widget/LoaderView.java b/app/src/main/java/com/thebrokenrail/mtudining/widget/LoaderView.java
index bd86944..417b984 100644
--- a/app/src/main/java/com/thebrokenrail/mtudining/widget/LoaderView.java
+++ b/app/src/main/java/com/thebrokenrail/mtudining/widget/LoaderView.java
@@ -29,7 +29,7 @@ public class LoaderView extends LinearLayout {
// Set Margin
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
int margin = getResources().getDimensionPixelSize(R.dimen.margin);
- layoutParams.setMargins(margin, margin, margin, margin);
+ layoutParams.setMargins(margin, 0, margin, margin);
inner.setLayoutParams(layoutParams);
}
diff --git a/app/src/main/res/layout/menu_header.xml b/app/src/main/res/layout/menu_header.xml
new file mode 100644
index 0000000..6f58736
--- /dev/null
+++ b/app/src/main/res/layout/menu_header.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1debc29..f6ade4c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -3,4 +3,6 @@
Dining[MTU]
Retry
Unable to load data!
+ Date
+ Meal
\ No newline at end of file