diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index b268ef3..338890f 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -5,6 +5,9 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 8a5381f..1fde962 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -16,7 +16,7 @@
@@ -60,4 +64,11 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/other.xml b/.idea/other.xml
new file mode 100644
index 0000000..b45a6e0
--- /dev/null
+++ b/.idea/other.xml
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index b3e998a..98b6f7f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
+apply plugin: 'androidx.room'
android {
@@ -8,27 +9,39 @@ android {
applicationId "de.schkola.kitchenscanner"
minSdkVersion 24
targetSdkVersion 34
- versionCode 1800
- versionName "1.8.0"
+ versionCode 1900
+ versionName "1.9.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'de.schkola.kitchenscanner'
+ buildFeatures {
+ viewBinding true
+ }
+ room {
+ schemaDirectory "$projectDir/schemas"
+ }
}
dependencies {
- implementation 'org.jetbrains:annotations:24.0.1'
+ implementation 'org.jetbrains:annotations:26.0.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.7'
+ implementation 'androidx.navigation:navigation-fragment:2.8.5'
+ implementation 'androidx.navigation:navigation-ui:2.8.5'
+ implementation 'androidx.activity:activity:1.9.3'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.7'
runtimeOnly fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.fragment:fragment:1.8.5'
implementation 'androidx.preference:preference:1.2.1'
- implementation 'androidx.room:room-runtime:2.6.1'
- annotationProcessor 'androidx.room:room-compiler:2.6.1'
+ implementation "androidx.room:room-runtime:$room_version"
+ annotationProcessor "androidx.room:room-compiler:$room_version"
implementation 'com.google.android.material:material:1.12.0'
implementation 'io.github.g00fy2.quickie:quickie-bundled:1.10.0'
- implementation 'org.apache.commons:commons-csv:1.11.0'
+ implementation 'org.apache.commons:commons-csv:1.12.0'
def lifecycle_version = "2.8.7"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
diff --git a/app/schemas/de.schkola.kitchenscanner.database.LunchDatabase/1.json b/app/schemas/de.schkola.kitchenscanner.database.LunchDatabase/1.json
new file mode 100644
index 0000000..dbc5bd7
--- /dev/null
+++ b/app/schemas/de.schkola.kitchenscanner.database.LunchDatabase/1.json
@@ -0,0 +1,90 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 1,
+ "identityHash": "e86d491c82440c2f55e948ed0b642905",
+ "entities": [
+ {
+ "tableName": "customers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`xba` INTEGER NOT NULL, `name` TEXT, `grade` TEXT, `lunch` INTEGER NOT NULL, `gotLunch` INTEGER NOT NULL, PRIMARY KEY(`xba`))",
+ "fields": [
+ {
+ "fieldPath": "xba",
+ "columnName": "xba",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "grade",
+ "columnName": "grade",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lunch",
+ "columnName": "lunch",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gotLunch",
+ "columnName": "gotLunch",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "xba"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "allergies",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`allergyId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `allergy` TEXT, `xba` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "allergyId",
+ "columnName": "allergyId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "allergy",
+ "columnName": "allergy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "xba",
+ "columnName": "xba",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "allergyId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e86d491c82440c2f55e948ed0b642905')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/schemas/de.schkola.kitchenscanner.database.LunchDatabase/2.json b/app/schemas/de.schkola.kitchenscanner.database.LunchDatabase/2.json
new file mode 100644
index 0000000..9d85aa4
--- /dev/null
+++ b/app/schemas/de.schkola.kitchenscanner.database.LunchDatabase/2.json
@@ -0,0 +1,116 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 2,
+ "identityHash": "a781fc58faae154032387af6bb4353de",
+ "entities": [
+ {
+ "tableName": "customers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`xba` INTEGER NOT NULL, `name` TEXT, `grade` TEXT, `lunch` INTEGER NOT NULL, `gotLunch` INTEGER NOT NULL, PRIMARY KEY(`xba`))",
+ "fields": [
+ {
+ "fieldPath": "xba",
+ "columnName": "xba",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "grade",
+ "columnName": "grade",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lunch",
+ "columnName": "lunch",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "gotLunch",
+ "columnName": "gotLunch",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "xba"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "allergies",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`allergyId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `allergy` TEXT, `xba` INTEGER NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "allergyId",
+ "columnName": "allergyId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "allergy",
+ "columnName": "allergy",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "xba",
+ "columnName": "xba",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "allergyId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "master_data",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`key`))",
+ "fields": [
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "key"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a781fc58faae154032387af6bb4353de')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2ed250..e5fa722 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
@@ -28,15 +29,19 @@
+ android:parentActivityName=".activity.MainBottomNavActivity" />
+ android:parentActivityName=".activity.MainBottomNavActivity" />
+ android:name=".activity.HelpActivity"
+ android:label="@string/help_display"
+ android:parentActivityName=".activity.MainBottomNavActivity" />
+
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/DisplayActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/DisplayActivity.java
index 97a9479..c91ab9e 100644
--- a/app/src/main/java/de/schkola/kitchenscanner/activity/DisplayActivity.java
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/DisplayActivity.java
@@ -155,6 +155,14 @@ private int getRescanTime() {
return 2;
}
+ private boolean shouldPlaySuccessSound() {
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
+ if (pref != null) {
+ return pref.getBoolean("success_sound", true);
+ }
+ return true;
+ }
+
/**
* Starts barcode scan
*/
@@ -208,8 +216,10 @@ private void processResult(@NotNull String rawValue) {
}, lunchResult -> {
torchManager.enable();
fillInformation(lunchResult);
- mediaPlayer.seekTo(0);
- mediaPlayer.start();
+ if (shouldPlaySuccessSound()) {
+ mediaPlayer.seekTo(0);
+ mediaPlayer.start();
+ }
if (isRescanEnabled()) {
executorService.schedule(this::startScan, getRescanTime(), TimeUnit.SECONDS);
}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/HelpActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/HelpActivity.java
new file mode 100644
index 0000000..8f18968
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/HelpActivity.java
@@ -0,0 +1,14 @@
+package de.schkola.kitchenscanner.activity;
+
+import android.os.Bundle;
+import androidx.appcompat.app.AppCompatActivity;
+import de.schkola.kitchenscanner.R;
+
+public class HelpActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_help);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/ImportExportActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/ImportExportActivity.java
new file mode 100644
index 0000000..2bcf1c8
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/ImportExportActivity.java
@@ -0,0 +1,231 @@
+package de.schkola.kitchenscanner.activity;
+
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.appcompat.app.AppCompatActivity;
+import de.schkola.kitchenscanner.R;
+import de.schkola.kitchenscanner.database.DatabaseAccess;
+import de.schkola.kitchenscanner.task.TaskRunner;
+import de.schkola.kitchenscanner.task.import_export.AllergyImportTask;
+import de.schkola.kitchenscanner.task.import_export.LunchExportTask;
+import de.schkola.kitchenscanner.task.import_export.LunchImportTask;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+public class ImportExportActivity extends AppCompatActivity {
+
+ public static final String EXTRA_TYPE = "TYPE";
+ public static final String TYPE_LUNCH_IMPORT = "LUNCH_IMPORT";
+ public static final String TYPE_ALLERGY_IMPORT = "ALLERGY_IMPORT";
+ public static final String TYPE_LUNCH_EXPORT = "LUNCH_EXPORT";
+
+ private static final String[] mimeTypes = {"text/csv", "text/comma-separated-values", "application/octet-stream"};
+
+ private final ActivityResultLauncher getFileLunchExport = registerForActivityResult(new ActivityResultContracts.CreateDocument("text/csv"), this::handleSetUri);
+ private final ActivityResultLauncher getFileLunchImport = registerForActivityResult(new ActivityResultContracts.OpenDocument(), this::handleSetUri);
+ private final ActivityResultLauncher getFileAllergyImport = registerForActivityResult(new ActivityResultContracts.OpenDocument(), this::handleSetUri);
+
+ private DatabaseAccess dbAccess;
+ private String importExportType;
+ private Uri uri;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_import_export);
+
+ dbAccess = new DatabaseAccess(getApplicationContext());
+
+ Intent intent = getIntent();
+ if (intent != null) {
+ TextView display = findViewById(R.id.importExportTypeDisplay);
+ importExportType = intent.getStringExtra(EXTRA_TYPE);
+
+ switch (importExportType != null ? importExportType : "") {
+ case TYPE_LUNCH_IMPORT:
+ display.setText(R.string.import_lunch_data);
+ break;
+ case TYPE_ALLERGY_IMPORT:
+ display.setText(R.string.import_allergy_data);
+ break;
+ case TYPE_LUNCH_EXPORT:
+ display.setText(R.string.export_lunch_data);
+ break;
+ default:
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.error)
+ .setMessage(R.string.error_parameter)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ break;
+ }
+ }
+
+ Button fileChooseButton = findViewById(R.id.fileChooseButton);
+ fileChooseButton.setOnClickListener(this::fileChooseButtonClick);
+ EditText fileEditText = findViewById(R.id.fileEditText);
+ fileEditText.setOnClickListener(this::fileChooseButtonClick);
+
+ Button startActionButton = findViewById(R.id.startActionButton);
+ startActionButton.setOnClickListener(this::startActionButtonClick);
+ }
+
+ private void fileChooseButtonClick(View view) {
+ EditText fileEditText = findViewById(R.id.fileEditText);
+ fileEditText.setText("");
+ this.uri = null;
+
+ switch (importExportType != null ? importExportType : "") {
+ case TYPE_LUNCH_IMPORT:
+ Toast.makeText(this, R.string.choose_day, Toast.LENGTH_LONG).show();
+ getFileLunchImport.launch(mimeTypes);
+ break;
+ case TYPE_ALLERGY_IMPORT:
+ Toast.makeText(this, R.string.choose_allergy, Toast.LENGTH_LONG).show();
+ getFileAllergyImport.launch(mimeTypes);
+ break;
+ case TYPE_LUNCH_EXPORT:
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
+ Date date = new Date(System.currentTimeMillis());
+ getFileLunchExport.launch(String.format("export-lunch-%s.csv", formatter.format(date)));
+ break;
+ default:
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.error)
+ .setMessage(R.string.error_parameter)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ break;
+ }
+ }
+
+ private void startActionButtonClick(View view) {
+ if (this.uri == null) {
+ return;
+ }
+ TextView importExportLoadingText = findViewById(R.id.importExportLoadingText);
+ switch (importExportType != null ? importExportType : "") {
+ case TYPE_LUNCH_IMPORT:
+ importExportLoadingText.setText(R.string.import_ongoing);
+ findViewById(R.id.importExportLoadingScreen).setVisibility(View.VISIBLE);
+ startLunchImport(this.uri);
+ break;
+ case TYPE_ALLERGY_IMPORT:
+ importExportLoadingText.setText(R.string.import_ongoing);
+ findViewById(R.id.importExportLoadingScreen).setVisibility(View.VISIBLE);
+ startAllergyImport(this.uri);
+ break;
+ case TYPE_LUNCH_EXPORT:
+ importExportLoadingText.setText(R.string.export_ongoing);
+ findViewById(R.id.importExportLoadingScreen).setVisibility(View.VISIBLE);
+ startLunchExport(this.uri);
+ break;
+ default:
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.error)
+ .setMessage(R.string.error_parameter)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ break;
+ }
+ }
+
+ private void handleSetUri(Uri uri) {
+ EditText fileEditText = findViewById(R.id.fileEditText);
+ this.uri = uri;
+ if (uri == null) {
+ fileEditText.setText("");
+ } else {
+ fileEditText.setText(uri.getLastPathSegment());
+ }
+ }
+
+ private void startLunchImport(Uri uri) {
+ try {
+ InputStream inputStream = getContentResolver().openInputStream(uri);
+ LunchImportTask lunchImportTask = new LunchImportTask(dbAccess.getDatabase(), inputStream, duplicates -> {
+ findViewById(R.id.importExportLoadingScreen).setVisibility(View.GONE);
+ if (duplicates.isEmpty()) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.success)
+ .setMessage(R.string.import_successful)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ } else {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.duplicate_entries)
+ .setItems(duplicates.stream().map(duplicate -> String.format(Locale.GERMANY, "[%d] %s {%s}", duplicate.getXba(), duplicate.getName(), duplicate.getLunches().stream().map(Object::toString).collect(Collectors.joining(",")))).toArray(String[]::new), null)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ }
+ });
+ TaskRunner.INSTANCE.executeAsyncTask(lunchImportTask);
+ } catch (FileNotFoundException e) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.error)
+ .setMessage(R.string.error_file_not_found)
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show();
+ Log.e(ImportExportActivity.class.getName(), "File not found (lunch import)", e);
+ }
+ }
+
+ private void startAllergyImport(Uri uri) {
+ try {
+ InputStream inputStream = getContentResolver().openInputStream(uri);
+ AllergyImportTask allergyImportTask = new AllergyImportTask(dbAccess.getDatabase(), inputStream, () -> {
+ findViewById(R.id.importExportLoadingScreen).setVisibility(View.GONE);
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.success)
+ .setMessage(R.string.import_successful)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ });
+ TaskRunner.INSTANCE.executeAsyncTask(allergyImportTask);
+ } catch (FileNotFoundException e) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.error)
+ .setMessage(R.string.error_file_not_found)
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show();
+ Log.e(ImportExportActivity.class.getName(), "File not found (allergy import)", e);
+ }
+ }
+
+ private void startLunchExport(Uri uri) {
+ try {
+ OutputStream outputStream = getContentResolver().openOutputStream(uri);
+ LunchExportTask lunchExportTask = new LunchExportTask(dbAccess.getDatabase(), outputStream, () -> {
+ findViewById(R.id.importExportLoadingScreen).setVisibility(View.GONE);
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.success)
+ .setMessage(R.string.export_successful)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish())
+ .create().show();
+ });
+ TaskRunner.INSTANCE.executeAsyncTask(lunchExportTask);
+ } catch (FileNotFoundException e) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.error)
+ .setMessage(R.string.error_file_not_found)
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show();
+ Log.e(ImportExportActivity.class.getName(), "File not found (lunch export)", e);
+ }
+ }
+}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/MainActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/MainActivity.java
deleted file mode 100644
index 5253b72..0000000
--- a/app/src/main/java/de/schkola/kitchenscanner/activity/MainActivity.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * MIT License
- *
- * Copyright 2016 Niklas Merkelt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package de.schkola.kitchenscanner.activity;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import de.schkola.kitchenscanner.R;
-
-public class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //Set Content
- setContentView(R.layout.activity_main);
-
- //Set Action Buttons
- FloatingActionButton fab = findViewById(R.id.fab);
- fab.setOnClickListener(view -> {
- Intent intent = new Intent(this, DisplayActivity.class);
- intent.setAction(Intent.ACTION_RUN);
- startActivity(intent);
- });
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (item.getItemId() == R.id.action_settings) {
- //Start settings
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- } else if (item.getItemId() == R.id.action_stats) {
- startActivity(new Intent(this, StatsActivity.class));
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/MainBottomNavActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/MainBottomNavActivity.java
new file mode 100644
index 0000000..5dd3a7d
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/MainBottomNavActivity.java
@@ -0,0 +1,58 @@
+package de.schkola.kitchenscanner.activity;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
+import androidx.navigation.ui.AppBarConfiguration;
+import androidx.navigation.ui.NavigationUI;
+import com.google.android.material.bottomnavigation.BottomNavigationView;
+import de.schkola.kitchenscanner.R;
+import de.schkola.kitchenscanner.databinding.ActivityBottomNavBinding;
+
+public class MainBottomNavActivity extends AppCompatActivity {
+
+ private ActivityBottomNavBinding binding;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ binding = ActivityBottomNavBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+
+ BottomNavigationView navView = findViewById(R.id.nav_view);
+ // Passing each menu ID as a set of Ids because each
+ // menu should be considered as top level destinations.
+ AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
+ R.id.navigation_home, R.id.navigation_lunch_list, R.id.navigation_search, R.id.navigation_import_export)
+ .build();
+ NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_bottom_nav);
+ NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
+ NavigationUI.setupWithNavController(binding.navView, navController);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == R.id.action_settings) {
+ //Start settings activity
+ startActivity(new Intent(this, SettingsActivity.class));
+ return true;
+ } else if (item.getItemId() == R.id.action_help) {
+ //Start help activity
+ startActivity(new Intent(this, HelpActivity.class));
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/SettingsActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/SettingsActivity.java
index 1a5cad7..ecf6fe3 100644
--- a/app/src/main/java/de/schkola/kitchenscanner/activity/SettingsActivity.java
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/SettingsActivity.java
@@ -25,42 +25,24 @@
package de.schkola.kitchenscanner.activity;
import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
-import android.widget.Toast;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import de.schkola.kitchenscanner.R;
import de.schkola.kitchenscanner.database.DatabaseAccess;
-import de.schkola.kitchenscanner.task.CsvImportTask;
-import de.schkola.kitchenscanner.task.LunchExportTask;
+import de.schkola.kitchenscanner.database.LunchDatabase;
import de.schkola.kitchenscanner.task.TaskRunner;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
public class SettingsActivity extends AppCompatActivity {
- private DatabaseAccess dbAccess;
- private final ActivityResultLauncher createDocument = registerForActivityResult(new ActivityResultContracts.CreateDocument("text/csv"), this::handleExport);
- private final ActivityResultLauncher getContentDay = registerForActivityResult(new ActivityResultContracts.OpenDocument(), this::handleUriDay);
- private final ActivityResultLauncher getContentAllergy = registerForActivityResult(new ActivityResultContracts.OpenDocument(), this::handleUriAllergy);
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set Content
setContentView(R.layout.activity_settings);
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new SettingsFragment()).commit();
- dbAccess = new DatabaseAccess(getApplicationContext());
}
@Override
@@ -71,29 +53,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (item.getItemId() == R.id.action_CSV_copy) {
- //Start copy CSV-Files
- new AlertDialog.Builder(this)
- .setTitle(R.string.csv_import)
- .setMessage(R.string.copy_request_day)
- .setPositiveButton(R.string.yes, (dialogInterface, i) -> {
- deleteFiles();
- startImport(false);
- })
- .setNegativeButton(R.string.no, (dialog, witch) -> startImport(false))
- .setNeutralButton(R.string.cancel, null)
- .create().show();
- return true;
- } else if (item.getItemId() == R.id.action_CSV_copy_allergy) {
- //Start copy CSV-Files
- new AlertDialog.Builder(this)
- .setTitle(R.string.csv_import)
- .setMessage(R.string.copy_request_allergy)
- .setPositiveButton(R.string.yes, (dialogInterface, i) -> startImport(true))
- .setNegativeButton(R.string.no, null)
- .create().show();
- return true;
- } else if (item.getItemId() == R.id.action_delete_data) {
+ if (item.getItemId() == R.id.action_delete_data) {
//Delete Cache
new AlertDialog.Builder(this)
.setTitle(R.string.delete)
@@ -102,90 +62,16 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
.setNegativeButton(R.string.no, null)
.create().show();
return true;
- } else if (item.getItemId() == R.id.action_export_lunch_data) {
- //Export Lunch Data to CSV
- startExport();
- return true;
}
return super.onOptionsItemSelected(item);
}
- private void startImport(boolean allergy) {
- int text = allergy ? R.string.choose_allergy : R.string.choose_day;
- Toast.makeText(this, text, Toast.LENGTH_LONG).show();
- String[] mimeTypes = {"text/csv", "text/comma-separated-values", "application/octet-stream"};
- if (allergy) {
- getContentAllergy.launch(mimeTypes);
- } else {
- getContentDay.launch(mimeTypes);
- }
- }
-
private void deleteFiles() {
- TaskRunner.INSTANCE.executeAsync(() -> dbAccess.getDatabase().customerDao().deleteAll());
- }
-
- private void startExport() {
- SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
- Date date = new Date(System.currentTimeMillis());
- createDocument.launch(String.format("export-lunch-%s.csv", formatter.format(date)));
- }
-
- @NonNull
- private LunchExportTask createExportTask(OutputStream outputStream) {
- ProgressDialog dialog = new ProgressDialog(this);
- dialog.setCancelable(false);
- dialog.setTitle(getString(R.string.lunch_export));
- dialog.setMessage(getString(R.string.lunch_export_ongoing));
- LunchExportTask lunchExportTask = new LunchExportTask(dbAccess.getDatabase(), outputStream);
- lunchExportTask.setProgressDialog(dialog);
- return lunchExportTask;
- }
-
- @NonNull
- private CsvImportTask createImportTask(boolean allergy, InputStream inputStream) {
- ProgressDialog dialog = new ProgressDialog(this);
- dialog.setCancelable(false);
- dialog.setTitle(getString(R.string.csv_import));
- dialog.setMessage(getString(R.string.csv_import_ongoing));
- CsvImportTask csvImportTask = new CsvImportTask(dbAccess.getDatabase(), allergy, inputStream);
- csvImportTask.setProgressDialog(dialog);
- csvImportTask.setCsvImportListener(duplicateXba -> new AlertDialog.Builder(this)
- .setTitle(R.string.duplicate_xba)
- .setItems(duplicateXba.toArray(new String[0]), null)
- .setPositiveButton(android.R.string.ok, null)
- .create().show());
- return csvImportTask;
- }
-
- private void handleUriDay(Uri uri) {
- handleUri(uri, false);
- }
-
- private void handleUriAllergy(Uri uri) {
- handleUri(uri, true);
- }
-
- private void handleUri(Uri data, boolean allergy) {
- if (data != null) {
- InputStream inputStream;
- try {
- inputStream = getContentResolver().openInputStream(data);
- } catch (FileNotFoundException ignored) {
- return;
- }
- TaskRunner.INSTANCE.executeAsyncTask(createImportTask(allergy, inputStream));
- }
- }
-
- private void handleExport(Uri data) {
- if (data != null) {
- try {
- OutputStream outputStream = getContentResolver().openOutputStream(data);
- TaskRunner.INSTANCE.executeAsyncTask(createExportTask(outputStream));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- }
+ DatabaseAccess dbAccess = new DatabaseAccess(getApplicationContext());
+ TaskRunner.INSTANCE.executeAsync(() -> {
+ LunchDatabase database = dbAccess.getDatabase();
+ database.customerDao().deleteAll();
+ database.close();
+ });
}
}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/StatsActivity.java b/app/src/main/java/de/schkola/kitchenscanner/activity/StatsActivity.java
deleted file mode 100644
index 96a9136..0000000
--- a/app/src/main/java/de/schkola/kitchenscanner/activity/StatsActivity.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * MIT License
- *
- * Copyright 2017 Niklas Merkelt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package de.schkola.kitchenscanner.activity;
-
-import android.os.Bundle;
-import androidx.appcompat.app.AppCompatActivity;
-import de.schkola.kitchenscanner.R;
-import de.schkola.kitchenscanner.fragment.StatsChartFragment;
-
-public class StatsActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_stats);
- getSupportFragmentManager().beginTransaction()
- .replace(R.id.container, new StatsChartFragment())
- .commit();
- }
-}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/fragment/StatsChartFragment.java b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/home/HomeFragment.java
similarity index 51%
rename from app/src/main/java/de/schkola/kitchenscanner/fragment/StatsChartFragment.java
rename to app/src/main/java/de/schkola/kitchenscanner/activity/ui/home/HomeFragment.java
index 3cf8178..381f074 100644
--- a/app/src/main/java/de/schkola/kitchenscanner/fragment/StatsChartFragment.java
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/home/HomeFragment.java
@@ -1,41 +1,39 @@
-package de.schkola.kitchenscanner.fragment;
+package de.schkola.kitchenscanner.activity.ui.home;
+import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.core.view.MenuProvider;
import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
import de.schkola.kitchenscanner.R;
+import de.schkola.kitchenscanner.activity.DisplayActivity;
import de.schkola.kitchenscanner.database.DatabaseAccess;
import de.schkola.kitchenscanner.database.LunchDatabase;
import de.schkola.kitchenscanner.task.StatTask;
import de.schkola.kitchenscanner.task.TaskRunner;
-public class StatsChartFragment extends Fragment {
+public class HomeFragment extends Fragment {
- private final OptionsMenuProvider optionsMenuProvider = new OptionsMenuProvider();
-
- @Nullable
@Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- FragmentActivity activity = getActivity();
- if (activity != null) {
- activity.addMenuProvider(optionsMenuProvider);
- }
- return inflater.inflate(R.layout.content_stats_overview, container, false);
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_home, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ FloatingActionButton fab = view.findViewById(R.id.fab);
+ fab.setOnClickListener(v -> {
+ Intent intent = new Intent(getContext(), DisplayActivity.class);
+ intent.setAction(Intent.ACTION_RUN);
+ startActivity(intent);
+ });
LunchDatabase database = new DatabaseAccess(getContext()).getDatabase();
TaskRunner.INSTANCE.executeAsyncTask(new StatTask(database, result -> {
database.close();
@@ -48,35 +46,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
((TextView) view.findViewById(R.id.orderedS)).setText(String.valueOf(result.getLunchS()));
((TextView) view.findViewById(R.id.gotS)).setText(String.valueOf(result.getDispensedS()));
((TextView) view.findViewById(R.id.getS)).setText(String.valueOf(result.getToDispenseS().size()));
- view.findViewById(R.id.statsOverviewLoadingScreen).setVisibility(View.GONE);
+ view.findViewById(R.id.home_loading_screen).setVisibility(View.GONE);
}));
}
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- FragmentActivity activity = getActivity();
- if (activity != null) {
- activity.removeMenuProvider(optionsMenuProvider);
- }
- }
-
- public class OptionsMenuProvider implements MenuProvider {
-
- @Override
- public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.menu_stats_chart, menu);
- }
-
- @Override
- public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
- if (menuItem.getItemId() == R.id.action_list) {
- getParentFragmentManager().beginTransaction()
- .replace(R.id.container, new StatsListFragment())
- .commit();
- return true;
- }
- return false;
- }
- }
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/ui/lunch_list/LunchListFragment.java b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/lunch_list/LunchListFragment.java
new file mode 100644
index 0000000..6f5984e
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/lunch_list/LunchListFragment.java
@@ -0,0 +1,37 @@
+package de.schkola.kitchenscanner.activity.ui.lunch_list;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ExpandableListView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import de.schkola.kitchenscanner.R;
+import de.schkola.kitchenscanner.database.DatabaseAccess;
+import de.schkola.kitchenscanner.database.LunchDatabase;
+import de.schkola.kitchenscanner.task.StatTask;
+import de.schkola.kitchenscanner.task.TaskRunner;
+import de.schkola.kitchenscanner.util.LunchListAdapter;
+
+public class LunchListFragment extends Fragment {
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_lunch_list, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ LunchDatabase database = new DatabaseAccess(getContext()).getDatabase();
+ TaskRunner.INSTANCE.executeAsyncTask(new StatTask(database, result -> {
+ database.close();
+ ExpandableListView listView = view.findViewById(R.id.lunch_list_view);
+ listView.setAdapter(new LunchListAdapter(getContext(), result.getToDispenseA(), result.getToDispenseB(), result.getToDispenseS()));
+ view.findViewById(R.id.lunch_list_loading_screen).setVisibility(View.GONE);
+ }));
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/ui/notifications/ImportExportFragment.java b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/notifications/ImportExportFragment.java
new file mode 100644
index 0000000..7b635f3
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/notifications/ImportExportFragment.java
@@ -0,0 +1,41 @@
+package de.schkola.kitchenscanner.activity.ui.notifications;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.RadioGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import de.schkola.kitchenscanner.R;
+import de.schkola.kitchenscanner.activity.ImportExportActivity;
+
+public class ImportExportFragment extends Fragment {
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_import_export, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ Button importExportStartButton = view.findViewById(R.id.import_export_start);
+ importExportStartButton.setOnClickListener(v -> {
+ RadioGroup importExportType = view.findViewById(R.id.import_export_type);
+ Intent intent = new Intent(getContext(), ImportExportActivity.class);
+ if (importExportType.getCheckedRadioButtonId() == R.id.type_lunch_import) {
+ intent.putExtra(ImportExportActivity.EXTRA_TYPE, ImportExportActivity.TYPE_LUNCH_IMPORT);
+ } else if (importExportType.getCheckedRadioButtonId() == R.id.type_allergy_import) {
+ intent.putExtra(ImportExportActivity.EXTRA_TYPE, ImportExportActivity.TYPE_ALLERGY_IMPORT);
+ } else if (importExportType.getCheckedRadioButtonId() == R.id.type_lunch_export) {
+ intent.putExtra(ImportExportActivity.EXTRA_TYPE, ImportExportActivity.TYPE_LUNCH_EXPORT);
+ }
+ startActivity(intent);
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/activity/ui/search/SearchFragment.java b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/search/SearchFragment.java
new file mode 100644
index 0000000..5910550
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/activity/ui/search/SearchFragment.java
@@ -0,0 +1,29 @@
+package de.schkola.kitchenscanner.activity.ui.search;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import de.schkola.kitchenscanner.R;
+
+public class SearchFragment extends Fragment {
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_search, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/schkola/kitchenscanner/database/LunchDatabase.java b/app/src/main/java/de/schkola/kitchenscanner/database/LunchDatabase.java
index 5670999..59d47b9 100644
--- a/app/src/main/java/de/schkola/kitchenscanner/database/LunchDatabase.java
+++ b/app/src/main/java/de/schkola/kitchenscanner/database/LunchDatabase.java
@@ -1,11 +1,14 @@
package de.schkola.kitchenscanner.database;
+import androidx.room.AutoMigration;
import androidx.room.Database;
import androidx.room.RoomDatabase;
-@Database(entities = {Customer.class, Allergy.class}, version = 1)
+@Database(entities = {Customer.class, Allergy.class, MasterData.class}, version = 2, autoMigrations = {@AutoMigration(from = 1, to = 2)})
public abstract class LunchDatabase extends RoomDatabase {
public abstract CustomerDao customerDao();
public abstract AllergyDao allergyDao();
public abstract LunchDao lunchDao();
+
+ public abstract MasterDataDao masterDataDao();
}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/database/MasterData.java b/app/src/main/java/de/schkola/kitchenscanner/database/MasterData.java
new file mode 100644
index 0000000..d627afc
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/database/MasterData.java
@@ -0,0 +1,15 @@
+package de.schkola.kitchenscanner.database;
+
+import androidx.annotation.NonNull;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "master_data")
+public class MasterData {
+
+ @PrimaryKey
+ @NonNull
+ public String key;
+ @NonNull
+ public String value;
+}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/database/MasterDataDao.java b/app/src/main/java/de/schkola/kitchenscanner/database/MasterDataDao.java
new file mode 100644
index 0000000..91d3a3a
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/database/MasterDataDao.java
@@ -0,0 +1,22 @@
+package de.schkola.kitchenscanner.database;
+
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+
+@Dao
+public interface MasterDataDao {
+
+ @Insert
+ void insertData(MasterData masterData);
+
+ @Update
+ void updateData(MasterData masterData);
+
+ @Query("SELECT value FROM master_data WHERE `key` = :key")
+ String getValue(String key);
+
+ @Query("DELETE FROM master_data WHERE `key` = :key")
+ void deleteKey(String key);
+}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/fragment/StatsListFragment.java b/app/src/main/java/de/schkola/kitchenscanner/fragment/StatsListFragment.java
deleted file mode 100644
index 1687805..0000000
--- a/app/src/main/java/de/schkola/kitchenscanner/fragment/StatsListFragment.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package de.schkola.kitchenscanner.fragment;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ExpandableListView;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.view.MenuProvider;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import de.schkola.kitchenscanner.R;
-import de.schkola.kitchenscanner.database.DatabaseAccess;
-import de.schkola.kitchenscanner.database.LunchDatabase;
-import de.schkola.kitchenscanner.task.StatTask;
-import de.schkola.kitchenscanner.task.TaskRunner;
-import de.schkola.kitchenscanner.util.LunchListAdapter;
-
-public class StatsListFragment extends Fragment {
-
- private final OptionsMenuProvider optionsMenuProvider = new OptionsMenuProvider();
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- FragmentActivity activity = getActivity();
- if (activity != null) {
- activity.addMenuProvider(optionsMenuProvider);
- }
- return inflater.inflate(R.layout.content_stats_list, container, false);
- }
-
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- LunchDatabase database = new DatabaseAccess(getContext()).getDatabase();
- TaskRunner.INSTANCE.executeAsyncTask(new StatTask(database, result -> {
- database.close();
- ExpandableListView listView = view.findViewById(R.id.listview);
- listView.setAdapter(new LunchListAdapter(getContext(), result.getToDispenseA(), result.getToDispenseB(), result.getToDispenseS()));
- view.findViewById(R.id.statsListLoadingScreen).setVisibility(View.GONE);
- }));
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- FragmentActivity activity = getActivity();
- if (activity != null) {
- activity.removeMenuProvider(optionsMenuProvider);
- }
- }
-
- public class OptionsMenuProvider implements MenuProvider {
-
- @Override
- public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.menu_stats_list, menu);
- }
-
- @Override
- public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
- if (menuItem.getItemId() == R.id.action_chart) {
- getParentFragmentManager().beginTransaction()
- .replace(R.id.container, new StatsChartFragment())
- .commit();
- return true;
- }
- return false;
- }
- }
-}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/task/CsvImportTask.java b/app/src/main/java/de/schkola/kitchenscanner/task/CsvImportTask.java
deleted file mode 100644
index bd9d47a..0000000
--- a/app/src/main/java/de/schkola/kitchenscanner/task/CsvImportTask.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package de.schkola.kitchenscanner.task;
-
-import de.schkola.kitchenscanner.database.Allergy;
-import de.schkola.kitchenscanner.database.Customer;
-import de.schkola.kitchenscanner.database.LunchDatabase;
-import de.schkola.kitchenscanner.util.StringUtil;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVParser;
-import org.apache.commons.csv.CSVRecord;
-import org.apache.commons.csv.QuoteMode;
-
-public class CsvImportTask extends ProgressAsyncTask {
-
- private final LunchDatabase database;
- private final boolean allergy;
- private final InputStream inputStream;
- private final Set duplicateXba = Collections.synchronizedSet(new LinkedHashSet<>());
- private CsvImportTask.CsvImportListener cil;
-
- public CsvImportTask(LunchDatabase db, boolean allergy, InputStream inputStream) {
- this.database = db;
- this.allergy = allergy;
- this.inputStream = inputStream;
- }
-
- public void setCsvImportListener(CsvImportTask.CsvImportListener cil) {
- this.cil = cil;
- }
-
- @Override
- public Void doInBackground() {
- try {
- CSVFormat format = CSVFormat.Builder.create(CSVFormat.DEFAULT)
- .setAllowMissingColumnNames(true)
- .build();
- if (!allergy) {
- format = CSVFormat.Builder.create(format)
- .setQuoteMode(QuoteMode.MINIMAL)
- .setSkipHeaderRecord(true)
- .setHeader()
- .build();
- }
-
- CSVParser csvParser = CSVParser.parse(inputStream, StandardCharsets.UTF_8, format);
- if (allergy) {
- database.allergyDao().deleteAll();
- scanAllergy(csvParser, database);
- } else {
- scanDay(csvParser, database);
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- inputStream.close();
- } catch (IOException ignored) {
- // Empty on purpose
- }
- }
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- super.onPostExecute(result);
- if (cil != null && !duplicateXba.isEmpty()) {
- cil.onDuplicateXba(duplicateXba);
- }
- }
-
- private void scanDay(CSVParser csvParser, LunchDatabase database) {
- try {
- for (CSVRecord r : csvParser) {
-
- Customer customer = new Customer();
- customer.grade = r.get("Klasse");
- customer.xba = Integer.parseInt(r.get("XBA"));
- customer.name = r.get("Name");
- customer.lunch = StringUtil.getLunch(r.get("Gericht"));
- Customer checkCustomer = database.customerDao().getCustomer(customer.xba);
- if (checkCustomer != null) {
- duplicateXba.add(String.format("[%s]: %s", r.get("XBA"), r.get("Name")));
- continue;
- }
- database.customerDao().insertCustomer(customer);
- }
- } catch (Exception ex) {
- throw new RuntimeException("Error in reading CSV file: ", ex);
- }
- }
-
- private void scanAllergy(CSVParser csvParser, LunchDatabase database) {
- try {
- for (CSVRecord r : csvParser) {
- Allergy a = new Allergy();
- a.xba = Integer.parseInt(r.get(0));
- a.allergy = r.get(1);
- database.allergyDao().insertAllergy(a);
- }
- } catch (Exception ex) {
- throw new RuntimeException("Error in reading CSV file: " + ex);
- }
- }
-
- public interface CsvImportListener {
- void onDuplicateXba(Set duplicateXba);
- }
-}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/task/ProgressAsyncTask.java b/app/src/main/java/de/schkola/kitchenscanner/task/ProgressAsyncTask.java
deleted file mode 100644
index 7e81d71..0000000
--- a/app/src/main/java/de/schkola/kitchenscanner/task/ProgressAsyncTask.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.schkola.kitchenscanner.task;
-
-import android.app.ProgressDialog;
-
-public abstract class ProgressAsyncTask implements AsyncTask {
-
- private ProgressDialog dialog;
-
- public void setProgressDialog(ProgressDialog dialog) {
- this.dialog = dialog;
- }
-
- @Override
- public void onPreExecute() {
- if (dialog != null)
- dialog.show();
- }
-
- @Override
- public void onPostExecute(R result) {
- if (dialog != null) {
- dialog.dismiss();
- dialog.cancel();
- }
- }
-}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/task/import_export/AllergyImportTask.java b/app/src/main/java/de/schkola/kitchenscanner/task/import_export/AllergyImportTask.java
new file mode 100644
index 0000000..a19836a
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/task/import_export/AllergyImportTask.java
@@ -0,0 +1,64 @@
+package de.schkola.kitchenscanner.task.import_export;
+
+import android.util.Log;
+import de.schkola.kitchenscanner.database.Allergy;
+import de.schkola.kitchenscanner.database.LunchDatabase;
+import de.schkola.kitchenscanner.task.AsyncTask;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+
+public class AllergyImportTask implements AsyncTask {
+
+ private final LunchDatabase database;
+ private final InputStream inputStream;
+ private final Runnable resultListener;
+
+ public AllergyImportTask(LunchDatabase db, InputStream inputStream, Runnable resultListener) {
+ this.database = db;
+ this.inputStream = inputStream;
+ this.resultListener = resultListener;
+ }
+
+ @Override
+ public Void doInBackground() {
+ try {
+ CSVFormat format = CSVFormat.Builder.create(CSVFormat.DEFAULT)
+ .setAllowMissingColumnNames(true)
+ .build();
+ CSVParser csvParser = CSVParser.parse(inputStream, StandardCharsets.UTF_8, format);
+ database.allergyDao().deleteAll();
+ scanAllergy(csvParser, database);
+ } catch (IOException e) {
+ Log.e("AllergyImportTask", "Error in allergy import", e);
+ } finally {
+ try {
+ inputStream.close();
+ } catch (IOException ignored) {
+ // Empty on purpose
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onPostExecute(Void result) {
+ resultListener.run();
+ }
+
+ private void scanAllergy(CSVParser csvParser, LunchDatabase database) {
+ try {
+ for (CSVRecord r : csvParser) {
+ Allergy a = new Allergy();
+ a.xba = Integer.parseInt(r.get(0));
+ a.allergy = r.get(1);
+ database.allergyDao().insertAllergy(a);
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException("Error in reading CSV file: " + ex);
+ }
+ }
+}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/task/LunchExportTask.java b/app/src/main/java/de/schkola/kitchenscanner/task/import_export/LunchExportTask.java
similarity index 73%
rename from app/src/main/java/de/schkola/kitchenscanner/task/LunchExportTask.java
rename to app/src/main/java/de/schkola/kitchenscanner/task/import_export/LunchExportTask.java
index 46eefb8..6d294c9 100644
--- a/app/src/main/java/de/schkola/kitchenscanner/task/LunchExportTask.java
+++ b/app/src/main/java/de/schkola/kitchenscanner/task/import_export/LunchExportTask.java
@@ -1,7 +1,9 @@
-package de.schkola.kitchenscanner.task;
+package de.schkola.kitchenscanner.task.import_export;
+import android.util.Log;
import de.schkola.kitchenscanner.database.Customer;
import de.schkola.kitchenscanner.database.LunchDatabase;
+import de.schkola.kitchenscanner.task.AsyncTask;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@@ -10,14 +12,16 @@
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
-public class LunchExportTask extends ProgressAsyncTask {
+public class LunchExportTask implements AsyncTask {
private final LunchDatabase database;
private final OutputStream outputStream;
+ private final Runnable resultListener;
- public LunchExportTask(LunchDatabase database, OutputStream outputStream) {
+ public LunchExportTask(LunchDatabase database, OutputStream outputStream, Runnable resultListener) {
this.database = database;
this.outputStream = outputStream;
+ this.resultListener = resultListener;
}
@Override
@@ -29,7 +33,7 @@ public Void doInBackground() {
printer.printRecord(customer.xba, customer.name, customer.lunch);
}
} catch (IOException e) {
- e.printStackTrace();
+ Log.e("LunchExportTask", "Error in lunch export", e);
} finally {
try {
outputStream.flush();
@@ -40,4 +44,9 @@ public Void doInBackground() {
}
return null;
}
+
+ @Override
+ public void onPostExecute(Void result) {
+ resultListener.run();
+ }
}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/task/import_export/LunchImportTask.java b/app/src/main/java/de/schkola/kitchenscanner/task/import_export/LunchImportTask.java
new file mode 100644
index 0000000..b2d8720
--- /dev/null
+++ b/app/src/main/java/de/schkola/kitchenscanner/task/import_export/LunchImportTask.java
@@ -0,0 +1,144 @@
+package de.schkola.kitchenscanner.task.import_export;
+
+import android.util.Log;
+import de.schkola.kitchenscanner.database.Customer;
+import de.schkola.kitchenscanner.database.LunchDatabase;
+import de.schkola.kitchenscanner.task.AsyncTask;
+import de.schkola.kitchenscanner.util.StringUtil;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.csv.QuoteMode;
+
+public class LunchImportTask implements AsyncTask {
+
+ private final LunchDatabase database;
+ private final InputStream inputStream;
+ private final Map duplicateEntries = Collections.synchronizedMap(new HashMap<>());
+ private final Consumer> resultListener;
+
+ public LunchImportTask(LunchDatabase db, InputStream inputStream, Consumer> resultListener) {
+ this.database = db;
+ this.inputStream = inputStream;
+ this.resultListener = resultListener;
+ }
+
+ @Override
+ public Void doInBackground() {
+ try {
+ CSVFormat format = CSVFormat.Builder.create(CSVFormat.DEFAULT)
+ .setAllowMissingColumnNames(true)
+ .setQuoteMode(QuoteMode.MINIMAL)
+ .setSkipHeaderRecord(true)
+ .setHeader()
+ .build();
+
+ CSVParser csvParser = CSVParser.parse(inputStream, StandardCharsets.UTF_8, format);
+ database.customerDao().deleteAll();
+ scanDay(csvParser, database);
+ } catch (IOException e) {
+ Log.e("LunchImportTask", "Error in lunch import", e);
+ } finally {
+ try {
+ inputStream.close();
+ } catch (IOException ignored) {
+ // Empty on purpose
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onPostExecute(Void result) {
+ resultListener.accept(duplicateEntries.values());
+ }
+
+ private void scanDay(CSVParser csvParser, LunchDatabase database) {
+ try {
+ for (CSVRecord r : csvParser) {
+ Customer customer = new Customer();
+ customer.grade = r.get("Klasse");
+ customer.xba = Integer.parseInt(r.get("XBA"));
+ customer.name = r.get("Name");
+ customer.lunch = StringUtil.getLunch(r.get("Gericht"));
+ Customer checkCustomer = database.customerDao().getCustomer(customer.xba);
+ if (checkCustomer != null) {
+ Duplicate duplicate = duplicateEntries.get(customer.xba);
+ if (duplicate == null) {
+ duplicate = new Duplicate(customer.name, customer.xba);
+ duplicate.lunches.add(checkCustomer.lunch);
+ }
+ duplicate.addLunch(customer.lunch);
+ duplicateEntries.put(customer.xba, duplicate);
+ continue;
+ }
+ database.customerDao().insertCustomer(customer);
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException("Error in reading CSV file: ", ex);
+ }
+ }
+
+ public static class Duplicate {
+ private final int xba;
+ private final String name;
+ private final List lunches = new ArrayList<>();
+
+ public Duplicate(String name, int xba) {
+ this.name = name;
+ this.xba = xba;
+ }
+
+ public List getLunches() {
+ return lunches;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isPlausible() {
+ byte compare = -1;
+ for (Byte lunch : lunches) {
+ if (compare == -1) {
+ compare = lunch;
+ } else if (compare != lunch) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int getXba() {
+ return xba;
+ }
+
+ public void addLunch(byte lunch) {
+ lunches.add(lunch);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Duplicate)) return false;
+ Duplicate duplicate = (Duplicate) o;
+ return xba == duplicate.xba;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(xba);
+ }
+ }
+}
diff --git a/app/src/main/java/de/schkola/kitchenscanner/util/LunchListAdapter.java b/app/src/main/java/de/schkola/kitchenscanner/util/LunchListAdapter.java
index fb9e348..6788961 100644
--- a/app/src/main/java/de/schkola/kitchenscanner/util/LunchListAdapter.java
+++ b/app/src/main/java/de/schkola/kitchenscanner/util/LunchListAdapter.java
@@ -14,15 +14,15 @@
public class LunchListAdapter extends BaseExpandableListAdapter {
private final Context context;
- private final List getLunchA;
- private final List getLunchB;
- private final List getLunchS;
+ private final List lunchA;
+ private final List lunchB;
+ private final List lunchS;
- public LunchListAdapter(Context context, List getLunchA, List getLunchB, List getLunchS) {
+ public LunchListAdapter(Context context, List lunchA, List lunchB, List lunchS) {
this.context = context;
- this.getLunchA = getLunchA;
- this.getLunchB = getLunchB;
- this.getLunchS = getLunchS;
+ this.lunchA = lunchA;
+ this.lunchB = lunchB;
+ this.lunchS = lunchS;
}
@Override
@@ -58,11 +58,17 @@ public int getChildrenCount(int groupPosition) {
public List getGroup(int groupPosition) {
switch (groupPosition) {
case 0:
- return getLunchA;
+ if (!lunchA.isEmpty()) {
+ return lunchA;
+ }
case 1:
- return getLunchB;
+ if (!lunchB.isEmpty()) {
+ return lunchB;
+ }
case 2:
- return getLunchS;
+ if (!lunchS.isEmpty()) {
+ return lunchS;
+ }
default:
return Collections.emptyList();
}
@@ -70,7 +76,17 @@ public List getGroup(int groupPosition) {
@Override
public int getGroupCount() {
- return 3;
+ int i = 0;
+ if (!lunchA.isEmpty()) {
+ i++;
+ }
+ if (!lunchB.isEmpty()) {
+ i++;
+ }
+ if (!lunchS.isEmpty()) {
+ i++;
+ }
+ return i;
}
@Override
@@ -83,14 +99,20 @@ public View getGroupView(int groupPosition, boolean isExpanded, View convertView
int headerTitle;
switch (groupPosition) {
case 0:
- headerTitle = R.string.getLunchA;
- break;
+ if (!lunchA.isEmpty()) {
+ headerTitle = R.string.getLunchA;
+ break;
+ }
case 1:
- headerTitle = R.string.getLunchB;
- break;
+ if (!lunchB.isEmpty()) {
+ headerTitle = R.string.getLunchB;
+ break;
+ }
case 2:
- headerTitle = R.string.getLunchS;
- break;
+ if (!lunchS.isEmpty()) {
+ headerTitle = R.string.getLunchS;
+ break;
+ }
default:
headerTitle = 0;
}
diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml
new file mode 100644
index 0000000..46fc8de
--- /dev/null
+++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_help_white_24dp.xml b/app/src/main/res/drawable/ic_help_white_24dp.xml
new file mode 100644
index 0000000..e6fd648
--- /dev/null
+++ b/app/src/main/res/drawable/ic_help_white_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml
new file mode 100644
index 0000000..f8bb0b5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_home_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_list_black_24dp.xml b/app/src/main/res/drawable/ic_list_black_24dp.xml
new file mode 100644
index 0000000..9922b56
--- /dev/null
+++ b/app/src/main/res/drawable/ic_list_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml
new file mode 100644
index 0000000..78b75c3
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_search_black_24dp.xml b/app/src/main/res/drawable/ic_search_black_24dp.xml
new file mode 100644
index 0000000..3cd9ae0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_swap_horiz_black_24dp.xml b/app/src/main/res/drawable/ic_swap_horiz_black_24dp.xml
new file mode 100644
index 0000000..eb9ef4c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_swap_horiz_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_bottom_nav.xml b/app/src/main/res/layout/activity_bottom_nav.xml
new file mode 100644
index 0000000..5770b6d
--- /dev/null
+++ b/app/src/main/res/layout/activity_bottom_nav.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_help.xml
similarity index 69%
rename from app/src/main/res/layout/activity_main.xml
rename to app/src/main/res/layout/activity_help.xml
index 109981c..a58ff6b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_help.xml
@@ -1,11 +1,10 @@
-
+ tools:context=".activity.HelpActivity">
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_import_export.xml b/app/src/main/res/layout/activity_import_export.xml
new file mode 100644
index 0000000..f6fd31e
--- /dev/null
+++ b/app/src/main/res/layout/activity_import_export.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_stats.xml b/app/src/main/res/layout/activity_stats.xml
deleted file mode 100644
index 5f57e8c..0000000
--- a/app/src/main/res/layout/activity_stats.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/layout/content_stats_overview.xml b/app/src/main/res/layout/fragment_home.xml
similarity index 88%
rename from app/src/main/res/layout/content_stats_overview.xml
rename to app/src/main/res/layout/fragment_home.xml
index 600a7a9..93078a6 100644
--- a/app/src/main/res/layout/content_stats_overview.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -2,16 +2,15 @@
+ tools:context=".activity.ui.home.HomeFragment">
+
+
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_import_export.xml b/app/src/main/res/layout/fragment_import_export.xml
new file mode 100644
index 0000000..b58df7d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_import_export.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_stats_list.xml b/app/src/main/res/layout/fragment_lunch_list.xml
similarity index 85%
rename from app/src/main/res/layout/content_stats_list.xml
rename to app/src/main/res/layout/fragment_lunch_list.xml
index 85bce61..9ae0972 100644
--- a/app/src/main/res/layout/content_stats_list.xml
+++ b/app/src/main/res/layout/fragment_lunch_list.xml
@@ -1,12 +1,13 @@
+ android:layout_height="match_parent"
+ tools:context=".activity.ui.lunch_list.LunchListFragment">
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml
new file mode 100644
index 0000000..c9d2048
--- /dev/null
+++ b/app/src/main/res/layout/fragment_search.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
new file mode 100644
index 0000000..8a5b0e0
--- /dev/null
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -0,0 +1,25 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
index 978ab3c..cad8d95 100644
--- a/app/src/main/res/menu/menu_main.xml
+++ b/app/src/main/res/menu/menu_main.xml
@@ -1,12 +1,12 @@