commit f8235dbfa55227a4ff79f6a74bccc8c9453d30c6 Author: H Malik Date: Fri Dec 29 14:05:32 2017 +1100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..48b26e3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..69b2905 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.2" + defaultConfig { + applicationId "com.example.h_mal.shift_tracker" + minSdkVersion 15 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:25.3.1' + compile 'com.android.support:design:25.3.1' + compile 'com.android.support.constraint:constraint-layout:1.0.2' + testCompile 'junit:junit:4.12' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..5543844 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\h_mal\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/com/example/h_mal/shift_tracker/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/h_mal/shift_tracker/ExampleInstrumentedTest.java new file mode 100644 index 0000000..7887498 --- /dev/null +++ b/app/src/androidTest/java/com/example/h_mal/shift_tracker/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.h_mal.shift_tracker; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.example.h_mal.shift_tracker", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..3c36f94 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/AddItem.java b/app/src/main/java/com/example/h_mal/shift_tracker/AddItem.java new file mode 100644 index 0000000..cd55820 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/AddItem.java @@ -0,0 +1,500 @@ +package com.example.h_mal.shift_tracker; + +import android.app.DatePickerDialog; +import android.app.LoaderManager; +import android.app.TimePickerDialog; +import android.content.ContentValues; +import android.content.CursorLoader; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.Loader; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.NavUtils; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.TimePicker; +import android.widget.Toast; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import com.example.h_mal.shift_tracker.Data.ShiftsContract.ShiftsEntry; + +/** + * Created by h_mal on 26/12/2017. + */ + +public class AddItem extends AppCompatActivity implements + LoaderManager.LoaderCallbacks{ + + private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1; + + private static final int EXISTING_PRODUCT_LOADER = 0; + + private Uri mCurrentProductUri; + + private EditText mLocationEditText; + + private EditText mDateEditText; + + private TextView mDurationTextView; + + private EditText mTimeInEditText; + private EditText mTimeOutEditText; + private EditText mBreakEditText; + + private static final int RESULT_LOAD_IMAGE = 1; + + private boolean mProductHasChanged = false; + + private static final int PICK_IMAGE_REQUEST = 0; + + private View.OnTouchListener mTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + mProductHasChanged = true; + return false; + } + }; + private int mDay; + private int mMonth; + private int mYear; + private int mHoursIn; + private int mMinutesIn; + private int mHoursOut; + private int mMinutesOut; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_add_item); + + mLocationEditText = (EditText) findViewById(R.id.locationEditText); + mDateEditText = (EditText) findViewById(R.id.dateEditText); + mTimeInEditText = (EditText) findViewById(R.id.timeInEditText); + mBreakEditText = (EditText) findViewById(R.id.breakEditText); + mTimeOutEditText = (EditText) findViewById(R.id.timeOutEditText); + mDurationTextView = (TextView) findViewById(R.id.ShiftDuration); + + Intent intent = getIntent(); + mCurrentProductUri = intent.getData(); + + if (mCurrentProductUri == null) { + setTitle(getString(R.string.add_item_title)); + + invalidateOptionsMenu(); + } else { + + setTitle(getString(R.string.edit_item_title)); + + + getLoaderManager().initLoader(EXISTING_PRODUCT_LOADER, null, this); + } + + if (mDateEditText.getText().toString().equals("")) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); + mDateEditText.setText(sdf.format(new Date())); + } + + mBreakEditText.setText("0"); + + mDateEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //To show current date in the datepicker + Calendar mcurrentDate=Calendar.getInstance(); + mYear=mcurrentDate.get(Calendar.YEAR); + mMonth=mcurrentDate.get(Calendar.MONTH); + mDay=mcurrentDate.get(Calendar.DAY_OF_MONTH); + + DatePickerDialog mDatePicker=new DatePickerDialog(AddItem.this, new DatePickerDialog.OnDateSetListener() { + public void onDateSet(DatePicker datepicker, int selectedyear, int selectedmonth, int selectedday) { + mDateEditText.setText(String.format("%02d", selectedday) + "/" + String.format("%02d", (selectedmonth = selectedmonth + 1)) + "/" + selectedyear); + setDate(selectedyear, selectedmonth, selectedday); + } + },mYear, mMonth, mDay); + mDatePicker.setTitle("Select date"); + mDatePicker.show(); } + }); + + mTimeInEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mTimeInEditText.getText().toString().equals("")) { + Calendar mcurrentTime = Calendar.getInstance(); + mHoursIn = mcurrentTime.get(Calendar.HOUR_OF_DAY); + mMinutesIn = mcurrentTime.get(Calendar.MINUTE); + } else { + mHoursIn = Integer.parseInt((mTimeInEditText.getText().toString().subSequence(0,2)).toString()); + mMinutesIn = Integer.parseInt((mTimeInEditText.getText().toString().subSequence(3,5)).toString()); + } + TimePickerDialog mTimePicker; + mTimePicker = new TimePickerDialog(AddItem.this, new TimePickerDialog.OnTimeSetListener() { + @Override + public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) { + String ddTime = String.format("%02d", selectedHour) + ":" + String.format("%02d", selectedMinute); + setTime(selectedMinute, selectedHour); + mTimeInEditText.setText(ddTime); + } + }, mHoursIn, mMinutesIn, true);//Yes 24 hour time + mTimePicker.setTitle("Select Time"); + mTimePicker.show(); + + } + }); + + mTimeOutEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mTimeOutEditText.getText().toString().equals("")) { + Calendar mcurrentTime = Calendar.getInstance(); + mHoursOut = mcurrentTime.get(Calendar.HOUR_OF_DAY); + mMinutesOut = mcurrentTime.get(Calendar.MINUTE); + }else { + mHoursOut = Integer.parseInt((mTimeOutEditText.getText().toString().subSequence(0,2)).toString()); + mMinutesOut = Integer.parseInt((mTimeOutEditText.getText().toString().subSequence(3,5)).toString()); + } + TimePickerDialog mTimePicker; + mTimePicker = new TimePickerDialog(AddItem.this, new TimePickerDialog.OnTimeSetListener() { + @Override + public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) { + String ddTime = String.format("%02d", selectedHour) + ":" + String.format("%02d", selectedMinute); + setTime2(selectedMinute,selectedHour); + mTimeOutEditText.setText(ddTime); + } + }, mHoursOut, mMinutesOut, true);//Yes 24 hour time + mTimePicker.setTitle("Select Time"); + mTimePicker.show(); + } + }); + + mTimeInEditText.addTextChangedListener(new TextWatcher() + { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) + { + + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int aft ) + { + + } + + @Override + public void afterTextChanged(Editable s) + { + setDuration(); + + } + }); + + mTimeOutEditText.addTextChangedListener(new TextWatcher() + { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) + { + + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int aft ) + { + + } + + @Override + public void afterTextChanged(Editable s) + { + setDuration(); + + } + }); + + mBreakEditText.addTextChangedListener(new TextWatcher() + { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) + { + + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int aft ) + { + + } + + @Override + public void afterTextChanged(Editable s) + { + setDuration(); + + } + }); + + Button SubmitProduct = (Button) findViewById(R.id.submit); + SubmitProduct.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + saveProduct(); + + } + }); + + mLocationEditText.setOnTouchListener(mTouchListener); + + } + + @Override + public void onBackPressed() { + new AlertDialog.Builder(this) + .setTitle("Discard changes?") + .setMessage("Are you sure you want to discard changes?") + .setNegativeButton(android.R.string.no, null) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface arg0, int arg1) { + AddItem.super.onBackPressed(); + } + }).create().show(); + } + + private void saveProduct() { + + String descriptionString = mLocationEditText.getText().toString().trim(); + String dateString = mDateEditText.getText().toString().trim(); + String timeInString = mTimeInEditText.getText().toString().trim(); + String timeOutString = mTimeOutEditText.getText().toString().trim(); + String breakMins = mBreakEditText.getText().toString().trim(); + int breaks = Integer.parseInt(breakMins); + float duration = calculateDuration(mHoursIn,mMinutesIn,mHoursOut,mMinutesOut,breaks); + + if ( + TextUtils.isEmpty(descriptionString)) { + Toast.makeText(AddItem.this, "please insert all product data", Toast.LENGTH_SHORT).show(); + return; + } + + ContentValues values = new ContentValues(); + values.put(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION, descriptionString); + values.put(ShiftsEntry.COLUMN_SHIFT_DATE, dateString); + values.put(ShiftsEntry.COLUMN_SHIFT_TIME_IN, timeInString); + values.put(ShiftsEntry.COLUMN_SHIFT_TIME_OUT, timeOutString); + values.put(ShiftsEntry.COLUMN_SHIFT_DURATION, duration); + values.put(ShiftsEntry.COLUMN_SHIFT_BREAK, breaks); + + if (mCurrentProductUri == null) { + + Uri newUri = getContentResolver().insert(ShiftsEntry.CONTENT_URI, values); + + if (newUri == null) { + Toast.makeText(this, getString(R.string.insert_item_failed), + Toast.LENGTH_SHORT).show(); + } else { + + Toast.makeText(this, getString(R.string.insert_item_successful), + Toast.LENGTH_SHORT).show(); + } + } else { + int rowsAffected = getContentResolver().update(mCurrentProductUri, values, null, null); + + if (rowsAffected == 0) { + Toast.makeText(this, getString(R.string.update_item_failed), + Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, getString(R.string.update_item_successful), + Toast.LENGTH_SHORT).show(); + } + } + NavUtils.navigateUpFromSameTask(AddItem.this); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + private void setDuration (){ + int breaks = 0; + if (!mBreakEditText.getText().toString().equals("")){ + breaks = Integer.parseInt(mBreakEditText.getText().toString()); + } + if (mTimeOutEditText.getText().toString().equals("")) { + Calendar mcurrentTime = Calendar.getInstance(); + mHoursOut = mcurrentTime.get(Calendar.HOUR_OF_DAY); + mMinutesOut = mcurrentTime.get(Calendar.MINUTE); + }else { + mHoursOut = Integer.parseInt((mTimeOutEditText.getText().toString().subSequence(0,2)).toString()); + mMinutesOut = Integer.parseInt((mTimeOutEditText.getText().toString().subSequence(3,5)).toString()); + } + if (mTimeInEditText.getText().toString().equals("")) { + Calendar mcurrentTime = Calendar.getInstance(); + mHoursIn = mcurrentTime.get(Calendar.HOUR_OF_DAY); + mMinutesIn = mcurrentTime.get(Calendar.MINUTE); + } else { + mHoursIn = Integer.parseInt((mTimeInEditText.getText().toString().subSequence(0,2)).toString()); + mMinutesIn = Integer.parseInt((mTimeInEditText.getText().toString().subSequence(3,5)).toString()); + } + mDurationTextView.setText(calculateDuration(mHoursIn,mMinutesIn,mHoursOut,mMinutesOut,breaks) + " hours"); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.delete_all: + DeleteDialog(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void DeleteDialog() { + android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this); + builder.setMessage("Are you sure you want to delete"); + builder.setPositiveButton("delete", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + deleteProduct(); + } + }); + builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + + if (dialog != null) { + dialog.dismiss(); + } + } + }); + + android.app.AlertDialog alertDialog = builder.create(); + alertDialog.show(); + } + + private void deleteProduct() { + + if (mCurrentProductUri != null) { + + int rowsDeleted = getContentResolver().delete(mCurrentProductUri, null, null); + + if (rowsDeleted == 0) { + Toast.makeText(this, "error deleting product", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, "Product deleted", Toast.LENGTH_SHORT).show(); + } + } + + finish(); + } + + + private void setDate (int year, int month, int day){ + mYear = year; + mMonth = month; + mDay = day; + } + + + private void setTime (int minutes, int hours){ + mMinutesIn = minutes; + mHoursIn = hours; + + } + + private void setTime2 (int minutes, int hours){ + mMinutesOut = minutes; + mHoursOut = hours; + + } + + private float calculateDuration (int hoursIn, int minutesIn, int hoursOut, int minutesOut, int breaks){ + float duration; + if (hoursOut > hoursIn){ + duration = (((float)hoursOut + ((float)minutesOut/60)) - ((float) hoursIn + ((float)minutesIn/60))) - ((float)breaks / 60); + }else{ + duration = ((((float)hoursOut + ((float)minutesOut/60)) - ((float)hoursIn + ((float)minutesIn/60)) - ((float)breaks / 60)) + 24); + } + + String s = String.format("%.2f",duration); + return Float.parseFloat(s); + } + + + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + String[] projection = { + ShiftsEntry._ID, + ShiftsEntry.COLUMN_SHIFT_DESCRIPTION, + ShiftsEntry.COLUMN_SHIFT_DATE, + ShiftsEntry.COLUMN_SHIFT_TIME_IN, + ShiftsEntry.COLUMN_SHIFT_TIME_OUT, + ShiftsEntry.COLUMN_SHIFT_BREAK, + ShiftsEntry.COLUMN_SHIFT_DURATION}; + + return new CursorLoader(this, + mCurrentProductUri, + projection, + null, + null, + null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + if (cursor == null || cursor.getCount() < 1) { + return; + } + + if (cursor.moveToFirst()) { + int descriptionColumnIndex = cursor.getColumnIndex(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION); + int dateColumnIndex = cursor.getColumnIndex(ShiftsEntry.COLUMN_SHIFT_DATE); + int timeInColumnIndex = cursor.getColumnIndex(ShiftsEntry.COLUMN_SHIFT_TIME_IN); + int timeOutColumnIndex = cursor.getColumnIndex(ShiftsEntry.COLUMN_SHIFT_TIME_OUT); + int breakColumnIndex = cursor.getColumnIndex(ShiftsEntry.COLUMN_SHIFT_BREAK); + int durationColumnIndex = cursor.getColumnIndex(ShiftsEntry.COLUMN_SHIFT_DURATION); + + String description = cursor.getString(descriptionColumnIndex); + String date = cursor.getString(dateColumnIndex); + String timeIn = cursor.getString(timeInColumnIndex); + String timeOut = cursor.getString(timeOutColumnIndex); + int breaks = cursor.getInt(breakColumnIndex); + float duration = cursor.getFloat(durationColumnIndex); + + mLocationEditText.setText(description); + mDateEditText.setText(date); + mTimeInEditText.setText(timeIn); + mTimeOutEditText.setText(timeOut); + mBreakEditText.setText(Integer.toString(breaks)); + mDurationTextView.setText(Float.toString(duration) + " Hours"); + + } + } + + + @Override + public void onLoaderReset(Loader loader) { + + } +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftProvider.java b/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftProvider.java new file mode 100644 index 0000000..78c4d9c --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftProvider.java @@ -0,0 +1,236 @@ +package com.example.h_mal.shift_tracker.Data; + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.util.Log; + +import com.example.h_mal.shift_tracker.Data.ShiftsContract.ShiftsEntry; + +/** + * Created by h_mal on 26/12/2017. + */ + +public class ShiftProvider extends ContentProvider { + + + public static final String LOG_TAG = ShiftProvider.class.getSimpleName(); + + private static final int SHIFTS = 100; + private static final int SHIFT_ID = 101; + + private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + + + static { + + sUriMatcher.addURI(ShiftsContract.CONTENT_AUTHORITY, ShiftsContract.PATH_SHIFTS, SHIFTS); + + sUriMatcher.addURI(ShiftsContract.CONTENT_AUTHORITY, ShiftsContract.PATH_SHIFTS + "/#", SHIFT_ID); + } + + ShiftsDbHelper mDbHelper; + + @Override + public boolean onCreate() { + mDbHelper = new ShiftsDbHelper(getContext()); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + + SQLiteDatabase database = mDbHelper.getReadableDatabase(); + + Cursor cursor; + + int match = sUriMatcher.match(uri); + switch (match) { + case SHIFTS: + + cursor = database.query(ShiftsEntry.TABLE_NAME, projection, selection, selectionArgs, + null, null, sortOrder); + break; + case SHIFT_ID: + + selection = ShiftsEntry._ID + "=?"; + selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) }; + cursor = database.query(ShiftsEntry.TABLE_NAME, projection, selection, selectionArgs, + null, null, sortOrder); + break; + default: + throw new IllegalArgumentException("Cannot query " + uri); + } + + cursor.setNotificationUri(getContext().getContentResolver(), uri); + + return cursor; + } + + @Override + public Uri insert(Uri uri, ContentValues contentValues) { + final int match = sUriMatcher.match(uri); + switch (match) { + case SHIFTS: + return insertShift(uri, contentValues); + default: + throw new IllegalArgumentException("Insertion is not supported for " + uri); + } + } + + private Uri insertShift(Uri uri, ContentValues values) { + + + String description = values.getAsString(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION); + if (description == null) { + throw new IllegalArgumentException("Description required"); + } + + String date = values.getAsString(ShiftsEntry.COLUMN_SHIFT_DATE); + if (date == null) { + throw new IllegalArgumentException("Date required"); + } + + String timeIn = values.getAsString(ShiftsEntry.COLUMN_SHIFT_TIME_IN); + if (timeIn == null) { + throw new IllegalArgumentException("Time In required"); + } + + String timeOut = values.getAsString(ShiftsEntry.COLUMN_SHIFT_TIME_OUT); + if (timeOut == null) { + throw new IllegalArgumentException("Time Out required"); + } + + values.getAsFloat(ShiftsEntry.COLUMN_SHIFT_DURATION); + + Integer breakMins = values.getAsInteger(ShiftsEntry.COLUMN_SHIFT_BREAK); + if (breakMins < 0) { + throw new IllegalArgumentException("Break cannot be negative"); + } + + SQLiteDatabase database = mDbHelper.getWritableDatabase(); + + long id = database.insert(ShiftsEntry.TABLE_NAME, null, values); + if (id == -1) { + Log.e(LOG_TAG, "row failed " + uri); + return null; + } + + getContext().getContentResolver().notifyChange(uri, null); + + return ContentUris.withAppendedId(uri, id); + } + + @Override + public int update(Uri uri, ContentValues contentValues, String selection, + String[] selectionArgs) { + final int match = sUriMatcher.match(uri); + switch (match) { + case SHIFTS: + return updateShift(uri, contentValues, selection, selectionArgs); + case SHIFT_ID: + + selection = ShiftsEntry._ID + "=?"; + selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) }; + return updateShift(uri, contentValues, selection, selectionArgs); + default: + throw new IllegalArgumentException("Update is not supported for " + uri); + } + } + + + private int updateShift(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + + if (values.containsKey(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION)) { + String description = values.getAsString(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION); + if (description == null) { + throw new IllegalArgumentException("description required"); + } + } + + if (values.containsKey(ShiftsEntry.COLUMN_SHIFT_DATE)) { + String date = values.getAsString(ShiftsEntry.COLUMN_SHIFT_DATE); + if (date == null) { + throw new IllegalArgumentException("date required"); + } + } + + if (values.containsKey(ShiftsEntry.COLUMN_SHIFT_TIME_IN)) { + String timeIn = values.getAsString(ShiftsEntry.COLUMN_SHIFT_TIME_IN); + if (timeIn == null) { + throw new IllegalArgumentException("time in required"); + } + } + + if (values.containsKey(ShiftsEntry.COLUMN_SHIFT_TIME_OUT)) { + String timeOut = values.getAsString(ShiftsEntry.COLUMN_SHIFT_TIME_OUT); + if (timeOut == null) { + throw new IllegalArgumentException("time out required"); + } + } + + if (values.containsKey(ShiftsEntry.COLUMN_SHIFT_BREAK)) { + String breaks = values.getAsString(ShiftsEntry.COLUMN_SHIFT_BREAK); + if (breaks == null) { + throw new IllegalArgumentException("break required"); + } + } + + if (values.size() == 0) { + return 0; + } + + SQLiteDatabase database = mDbHelper.getWritableDatabase(); + int rowsUpdated = database.update(ShiftsEntry.TABLE_NAME, values, selection, selectionArgs); + if (rowsUpdated != 0) { + getContext().getContentResolver().notifyChange(uri, null); + } + + return rowsUpdated; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + SQLiteDatabase database = mDbHelper.getWritableDatabase(); + + int rowsDeleted; + + final int match = sUriMatcher.match(uri); + switch (match) { + case SHIFTS: + rowsDeleted = database.delete(ShiftsEntry.TABLE_NAME, selection, selectionArgs); + break; + case SHIFT_ID: + selection = ShiftsEntry._ID + "=?"; + selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) }; + rowsDeleted = database.delete(ShiftsEntry.TABLE_NAME, selection, selectionArgs); + break; + default: + throw new IllegalArgumentException("Deletion is not supported for " + uri); + } + + if (rowsDeleted != 0) { + getContext().getContentResolver().notifyChange(uri, null); + } + + return rowsDeleted; + } + + @Override + public String getType(Uri uri) { + final int match = sUriMatcher.match(uri); + switch (match) { + case SHIFTS: + return ShiftsEntry.CONTENT_LIST_TYPE; + case SHIFT_ID: + return ShiftsEntry.CONTENT_ITEM_TYPE; + default: + throw new IllegalStateException("Unknown URI " + uri + " with match " + match); + } + } +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftsContract.java b/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftsContract.java new file mode 100644 index 0000000..0cce669 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftsContract.java @@ -0,0 +1,52 @@ +package com.example.h_mal.shift_tracker.Data; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * Created by h_mal on 26/12/2017. + */ + +public class ShiftsContract { + + private ShiftsContract() {} + + public static final String CONTENT_AUTHORITY = "com.example.h_mal.shift_tracker"; + + public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); + + public static final String PATH_SHIFTS = "shifts"; + + public static final class ShiftsEntry implements BaseColumns { + + public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, PATH_SHIFTS); + + public static final String CONTENT_LIST_TYPE = + ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_SHIFTS; + + + public static final String CONTENT_ITEM_TYPE = + ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_SHIFTS; + + + public final static String TABLE_NAME = "shifts"; + + public final static String _ID = BaseColumns._ID; + + public final static String COLUMN_SHIFT_DESCRIPTION = "description"; + + public final static String COLUMN_SHIFT_DATE = "date"; + + public final static String COLUMN_SHIFT_TIME_IN = "timein"; + + public final static String COLUMN_SHIFT_TIME_OUT = "timeout"; + + public final static String COLUMN_SHIFT_BREAK = "break"; + + public final static String COLUMN_SHIFT_DURATION = "duration"; + + + + } +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftsDbHelper.java b/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftsDbHelper.java new file mode 100644 index 0000000..e3c714b --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/Data/ShiftsDbHelper.java @@ -0,0 +1,47 @@ +package com.example.h_mal.shift_tracker.Data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.example.h_mal.shift_tracker.Data.ShiftsContract.ShiftsEntry; + +/** + * Created by h_mal on 26/12/2017. + */ + +public class ShiftsDbHelper extends SQLiteOpenHelper { + + public static final String LOG_TAG = ShiftsDbHelper.class.getSimpleName(); + + private static final String DATABASE_NAME = "shifts.db"; + + private static final int DATABASE_VERSION = 1; + + + public ShiftsDbHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + + String SQL_CREATE_PRODUCTS_TABLE = "CREATE TABLE " + ShiftsEntry.TABLE_NAME + " (" + + ShiftsEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ShiftsEntry.COLUMN_SHIFT_DESCRIPTION + " TEXT NOT NULL, " + + ShiftsEntry.COLUMN_SHIFT_DATE + " DATE NOT NULL, " + + ShiftsEntry.COLUMN_SHIFT_TIME_IN + " TIME NOT NULL, " + + ShiftsEntry.COLUMN_SHIFT_TIME_OUT + " TIME NOT NULL, " + + ShiftsEntry.COLUMN_SHIFT_BREAK + " INTEGER NOT NULL DEFAULT 0, " + + ShiftsEntry.COLUMN_SHIFT_DURATION + " FLOAT NOT NULL DEFAULT 0)"; + + db.execSQL(SQL_CREATE_PRODUCTS_TABLE); + } + + + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/LoginScreen.java b/app/src/main/java/com/example/h_mal/shift_tracker/LoginScreen.java new file mode 100644 index 0000000..2c17c38 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/LoginScreen.java @@ -0,0 +1,76 @@ +package com.example.h_mal.shift_tracker; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +/** + * Created by h_mal on 27/06/2017. + */ + +public class LoginScreen extends AppCompatActivity{ + + private EditText mPasswordEditText; + + String password; + + int count = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.login_screen); + + SharedPreferences settings = getSharedPreferences("PREFS", 0); + password = settings.getString("password", ""); + + mPasswordEditText = (EditText) findViewById(R.id.loginPassword); + + Button login = (Button) findViewById(R.id.loginButton); + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + login(); + mPasswordEditText.getText().clear(); + + } + }); + + + } + + private void login() { + String PasswordString = mPasswordEditText.getText().toString().trim(); + + if ( + TextUtils.isEmpty(PasswordString) ) { + Toast.makeText(LoginScreen.this, "please enter password", Toast.LENGTH_SHORT).show(); + return; + } + + if(PasswordString.equals(password)){ + Intent i = new Intent(LoginScreen.this, MainActivity.class); + startActivity(i); + }else{ + addCount(); + Toast.makeText(LoginScreen.this, "password incorrect " + (4 - count) + " tries left", Toast.LENGTH_SHORT).show(); + + } + } + + private void addCount(){ + count = count + 1; + if (count == 4){ + finish(); + System.exit(0); + } + } + + +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/LoginSetup.java b/app/src/main/java/com/example/h_mal/shift_tracker/LoginSetup.java new file mode 100644 index 0000000..9b30418 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/LoginSetup.java @@ -0,0 +1,73 @@ +package com.example.h_mal.shift_tracker; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +/** + * Created by h_mal on 27/06/2017. + */ + +public class LoginSetup extends Activity { + + private EditText mPasswordInitialEditText; + private EditText mPasswordCheckEditText; + + public SharedPreferences prefs = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.login_setup); + + mPasswordInitialEditText = (EditText) findViewById(R.id.loginPasswordInitial); + mPasswordCheckEditText = (EditText) findViewById(R.id.loginPasswordCheck); + + Button login = (Button) findViewById(R.id.loginButton); + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + clickLogin(); + + } + }); + + + } + + private void clickLogin() { + + String initialPasswordString = mPasswordInitialEditText.getText().toString().trim(); + String checkPasswordString = mPasswordCheckEditText.getText().toString().trim(); + + if ( + TextUtils.isEmpty(initialPasswordString) || + TextUtils.isEmpty(checkPasswordString) ) { + Toast.makeText(LoginSetup.this, "please set password", Toast.LENGTH_SHORT).show(); + return; + } + + if (!initialPasswordString.equals(checkPasswordString)){ + Toast.makeText(LoginSetup.this, "Passwords do not match", Toast.LENGTH_SHORT).show(); + return;} + + if(initialPasswordString.equals(checkPasswordString)){ + SharedPreferences settings = getSharedPreferences("PREFS", 0); + SharedPreferences.Editor editor = settings.edit(); + editor.putString("password", initialPasswordString); + editor.apply(); + + } + + Intent i = new Intent(LoginSetup.this, MainActivity.class); + startActivity(i); + + } + +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/MainActivity.java b/app/src/main/java/com/example/h_mal/shift_tracker/MainActivity.java new file mode 100644 index 0000000..c723e41 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/MainActivity.java @@ -0,0 +1,157 @@ +package com.example.h_mal.shift_tracker; + +import android.app.LoaderManager; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.CursorLoader; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.Loader; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ListView; +import android.support.design.widget.FloatingActionButton; + +import com.example.h_mal.shift_tracker.Data.ShiftsContract.ShiftsEntry; +import com.example.h_mal.shift_tracker.Data.ShiftsDbHelper; + + +public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { + + private static final int ACHIEVEMENT_LOADER = 0; + + ShiftsCursorAdapter mCursorAdapter; + ShiftsDbHelper shiftsDbhelper; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main_view); + + FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab1); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(MainActivity.this, AddItem.class); + startActivity(intent); + } + }); + + ListView productListView = (ListView) findViewById(R.id.list_item_view); + + View emptyView = findViewById(R.id.empty_view); + productListView.setEmptyView(emptyView); + + mCursorAdapter = new ShiftsCursorAdapter(this, null); + productListView.setAdapter(mCursorAdapter); + + getLoaderManager().initLoader(ACHIEVEMENT_LOADER, null, this); + + } + + private void insertProduct() { + ContentValues values = new ContentValues(); + values.put(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION, "Random Location"); + values.put(ShiftsEntry.COLUMN_SHIFT_DATE, "1970/01/01"); + values.put(ShiftsEntry.COLUMN_SHIFT_TIME_IN, "00:00"); + values.put(ShiftsEntry.COLUMN_SHIFT_TIME_OUT, "12:00"); + values.put(ShiftsEntry.COLUMN_SHIFT_BREAK, 30); + values.put(ShiftsEntry.COLUMN_SHIFT_DURATION, 12); + + getContentResolver().insert(ShiftsEntry.CONTENT_URI, values); + } + + + private void deleteAllProducts() { + int rowsDeleted = getContentResolver().delete(ShiftsEntry.CONTENT_URI, null, null); + Log.v("MainActivity", rowsDeleted + " rows deleted"); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + public void clickOnViewItem(long id) { + Intent intent = new Intent(MainActivity.this, AddItem.class); + Uri currentProductUri = ContentUris.withAppendedId(ShiftsEntry.CONTENT_URI, id); + intent.setData(currentProductUri); + startActivity(intent); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.delete_all: + deleteAllProducts(); + return true; + + case R.id.insert_placeholder_data: + insertProduct(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + String[] projection = { + ShiftsEntry._ID, + ShiftsEntry.COLUMN_SHIFT_DESCRIPTION, + ShiftsEntry.COLUMN_SHIFT_DATE, + ShiftsEntry.COLUMN_SHIFT_TIME_IN, + ShiftsEntry.COLUMN_SHIFT_TIME_OUT, + ShiftsEntry.COLUMN_SHIFT_BREAK, + ShiftsEntry.COLUMN_SHIFT_DURATION}; + + return new CursorLoader(this, + ShiftsEntry.CONTENT_URI, + projection, + null, + null, + null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + mCursorAdapter.swapCursor(data); + } + + @Override + public void onLoaderReset(Loader loader) { + mCursorAdapter.swapCursor(null); + } + + @Override + public void onBackPressed() { + new AlertDialog.Builder(this) + .setTitle("Leave?") + .setMessage("Are you sure you want to exit Shifts?") + .setNegativeButton(android.R.string.no, null) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface arg0, int arg1) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.addCategory(Intent.CATEGORY_HOME); + startActivity(intent); + finish(); + System.exit(0); + } + }).create().show(); + } + +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/ShiftsCursorAdapter.java b/app/src/main/java/com/example/h_mal/shift_tracker/ShiftsCursorAdapter.java new file mode 100644 index 0000000..78f1640 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/ShiftsCursorAdapter.java @@ -0,0 +1,65 @@ +package com.example.h_mal.shift_tracker; + +import android.content.Context; +import android.database.Cursor; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.TextView; + +import com.example.h_mal.shift_tracker.Data.ShiftsContract.ShiftsEntry; + +/** + * Created by h_mal on 26/12/2017. + */ + +public class ShiftsCursorAdapter extends CursorAdapter { + + private final MainActivity activity; + + private Context mContext; + + public ShiftsCursorAdapter(MainActivity context, Cursor c) { + super(context, c, 0); + this.activity = context; + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return LayoutInflater.from(context).inflate(R.layout.list_item, parent, false); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + mContext = context; + + TextView descriptionTextView = (TextView) view.findViewById(R.id.editText); + TextView dateTextView = (TextView) view.findViewById(R.id.textView5); + TextView timeTextView = (TextView) view.findViewById(R.id.textView5out); + TextView durationTextView = (TextView) view.findViewById(R.id.textView7); + + final String descriptionColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_DESCRIPTION)); + final String dateColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_DATE)); + final String timeInColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_TIME_IN)); + final String timeOutColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_TIME_OUT)); + final String durationColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_DURATION)); + final String breakOutColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ShiftsEntry.COLUMN_SHIFT_BREAK)); + + descriptionTextView.setText(descriptionColumnIndex); + dateTextView.setText(dateColumnIndex); + timeTextView.setText(timeInColumnIndex + "-" + timeOutColumnIndex); + durationTextView.setText(durationColumnIndex + " Hours worked (+ "+ breakOutColumnIndex +" minutes break)"); + + final long id = cursor.getLong(cursor.getColumnIndexOrThrow(ShiftsEntry._ID)); + + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + activity.clickOnViewItem(id); + } + }); + + } + +} diff --git a/app/src/main/java/com/example/h_mal/shift_tracker/SplashScreen.java b/app/src/main/java/com/example/h_mal/shift_tracker/SplashScreen.java new file mode 100644 index 0000000..b3a1285 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shift_tracker/SplashScreen.java @@ -0,0 +1,57 @@ +package com.example.h_mal.shift_tracker; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; + +/** + * Created by h_mal on 27/06/2017. + */ + +public class SplashScreen extends Activity { + + // Splash screen timer + private static int SPLASH_TIME_OUT = 3000; + + String password; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash); + + SharedPreferences settings = getSharedPreferences("PREFS", 0); + password = settings.getString("password", ""); + + + new Handler().postDelayed(new Runnable() { + + /* + * Showing splash screen with a timer. This will be useful when you + * want to show case your app logo / company + */ + + @Override + public void run() { + // This method will be executed once the timer is over + // Start your app main activity + if (password.equals("")) { + Intent i = new Intent(SplashScreen.this, LoginSetup.class); + startActivity(i); + }else { + Intent i = new Intent(SplashScreen.this, LoginScreen.class); + startActivity(i); + } + + // close this activity + finish(); + + + } + }, SPLASH_TIME_OUT); + } + + +} \ No newline at end of file diff --git a/app/src/main/res/drawable/img248.jpg b/app/src/main/res/drawable/img248.jpg new file mode 100644 index 0000000..ac5fbb8 Binary files /dev/null and b/app/src/main/res/drawable/img248.jpg differ diff --git a/app/src/main/res/layout/activity_add_item.xml b/app/src/main/res/layout/activity_add_item.xml new file mode 100644 index 0000000..5275dd2 --- /dev/null +++ b/app/src/main/res/layout/activity_add_item.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +