From c0f912d3202a3ef4194eaad38b46808c783210ba Mon Sep 17 00:00:00 2001 From: H Malik Date: Mon, 5 Jun 2017 21:03:23 +0100 Subject: [PATCH] Initial commit --- .gitignore | 9 + .idea/compiler.xml | 22 + .idea/copyright/profiles_settings.xml | 3 + .idea/gradle.xml | 18 + .idea/misc.xml | 46 +++ .idea/modules.xml | 9 + .idea/runConfigurations.xml | 12 + app/.gitignore | 1 + app/build.gradle | 30 ++ app/proguard-rules.pro | 17 + .../inventoryapp/ExampleInstrumentedTest.java | 26 ++ app/src/main/AndroidManifest.xml | 38 ++ .../h_mal/inventoryapp/AddProduct.java | 380 ++++++++++++++++++ .../h_mal/inventoryapp/MainActivity.java | 136 +++++++ .../inventoryapp/ProductCursorAdapter.java | 98 +++++ .../inventoryapp/data/ProductContract.java | 47 +++ .../inventoryapp/data/ProductDbHelper.java | 45 +++ .../inventoryapp/data/ProductProvider.java | 214 ++++++++++ app/src/main/res/drawable/sad.jpg | Bin 0 -> 31648 bytes .../main/res/layout/activity_add_product.xml | 168 ++++++++ app/src/main/res/layout/activity_main.xml | 53 +++ app/src/main/res/layout/list_item.xml | 99 +++++ app/src/main/res/menu/menu_editor.xml | 23 ++ app/src/main/res/menu/menu_main.xml | 15 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10486 bytes app/src/main/res/values-v21/styles.xml | 9 + app/src/main/res/values-w820dp/dimens.xml | 6 + app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/dimens.xml | 6 + app/src/main/res/values/strings.xml | 12 + app/src/main/res/values/styles.xml | 20 + .../h_mal/inventoryapp/ExampleUnitTest.java | 17 + build.gradle | 23 ++ gradle.properties | 17 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 160 ++++++++ gradlew.bat | 90 +++++ settings.gradle | 1 + 43 files changed, 1882 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/example/h_mal/inventoryapp/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/example/h_mal/inventoryapp/AddProduct.java create mode 100644 app/src/main/java/com/example/h_mal/inventoryapp/MainActivity.java create mode 100644 app/src/main/java/com/example/h_mal/inventoryapp/ProductCursorAdapter.java create mode 100644 app/src/main/java/com/example/h_mal/inventoryapp/data/ProductContract.java create mode 100644 app/src/main/java/com/example/h_mal/inventoryapp/data/ProductDbHelper.java create mode 100644 app/src/main/java/com/example/h_mal/inventoryapp/data/ProductProvider.java create mode 100644 app/src/main/res/drawable/sad.jpg create mode 100644 app/src/main/res/layout/activity_add_product.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/list_item.xml create mode 100644 app/src/main/res/menu/menu_editor.xml create mode 100644 app/src/main/res/menu/menu_main.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/values-v21/styles.xml create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/com/example/h_mal/inventoryapp/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle 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..16a28ec --- /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..189d74c --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.2" + defaultConfig { + applicationId "com.example.h_mal.inventoryapp" + 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.0' + compile 'com.android.support:design:25.3.0' + testCompile 'junit:junit:4.12' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..05e856b --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# 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 *; +#} diff --git a/app/src/androidTest/java/com/example/h_mal/inventoryapp/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/h_mal/inventoryapp/ExampleInstrumentedTest.java new file mode 100644 index 0000000..787e363 --- /dev/null +++ b/app/src/androidTest/java/com/example/h_mal/inventoryapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.h_mal.inventoryapp; + +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.inventoryapp", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..70edb27 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/inventoryapp/AddProduct.java b/app/src/main/java/com/example/h_mal/inventoryapp/AddProduct.java new file mode 100644 index 0000000..384e746 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/inventoryapp/AddProduct.java @@ -0,0 +1,380 @@ +package com.example.h_mal.inventoryapp; + +import android.Manifest; +import android.app.LoaderManager; +import android.content.ContentValues; +import android.content.CursorLoader; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.Loader; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.NavUtils; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.Toast; + +import com.example.h_mal.inventoryapp.data.ProductContract.ProductEntry; + +public class AddProduct 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 mNameEditText; + + private EditText mQuantityEditText; + + private EditText mPriceEditText; + + private ImageView mImageView; + + private Uri mImageURI; + + 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; + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_add_product); + + mNameEditText = (EditText) findViewById(R.id.productName); + mQuantityEditText = (EditText) findViewById(R.id.productQuantity); + mPriceEditText = (EditText) findViewById(R.id.productPrice); + mImageView = (ImageView) findViewById(R.id.imageView2); + + Intent intent = getIntent(); + mCurrentProductUri = intent.getData(); + + if (mCurrentProductUri == null) { + setTitle(getString(R.string.add_product_title)); + + invalidateOptionsMenu(); + } else { + + setTitle(getString(R.string.edit_product_title)); + + + getLoaderManager().initLoader(EXISTING_PRODUCT_LOADER, null, this); + } + + Button Browse = (Button) findViewById(R.id.BrowseImage); + Browse.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + tryToOpenImageSelector(); + + } + }); + + Button SubmitProduct = (Button) findViewById(R.id.submit); + SubmitProduct.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + saveProduct(); + } + }); + + ImageButton ContactSupplier = (ImageButton) findViewById(R.id.ContactSupplier); + ContactSupplier.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(Intent.ACTION_SENDTO); + intent.setData(Uri.parse("mailto:")); // only email apps should handle this + intent.putExtra(Intent.EXTRA_SUBJECT, "Order Stock " + mNameEditText.getText().toString().trim()); + intent.putExtra(Intent.EXTRA_TEXT, "I would like to order more " + mNameEditText.getText().toString().trim()); + if (intent.resolveActivity(getPackageManager()) != null) { + startActivity(intent); + } + } + }); + + Button Incrament = (Button) findViewById(R.id.buttonAdd); + Incrament.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + IncramentQuantity(); + } + }); + + Button decrament = (Button) findViewById(R.id.buttonMinus); + decrament.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + DecramentQuantity(); + } + }); + + + mNameEditText.setOnTouchListener(mTouchListener); + mQuantityEditText.setOnTouchListener(mTouchListener); + mPriceEditText.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) { + AddProduct.super.onBackPressed(); + } + }).create().show(); + } + + private void saveProduct() { + + String nameString = mNameEditText.getText().toString().trim(); + String quantityString = mQuantityEditText.getText().toString().trim(); + String priceString = mPriceEditText.getText().toString().trim(); + + if ( + TextUtils.isEmpty(nameString) || TextUtils.isEmpty(quantityString) || + TextUtils.isEmpty(priceString) || mImageURI == null) { + Toast.makeText(AddProduct.this, "please insert all product data", Toast.LENGTH_SHORT).show(); + return; + } + + int quantity = Integer.parseInt(quantityString); + int price = Integer.parseInt(priceString); + + ContentValues values = new ContentValues(); + values.put(ProductEntry.COLUMN_PRODUCT_NAME, nameString); + values.put(ProductEntry.COLUMN_PRODUCT_PRICE, price); + values.put(ProductEntry.COLUMN_PRODUCT_QUANTITY, quantity); + values.put(ProductEntry.COLUMN_PRODUCT_IMAGE, String.valueOf(mImageURI)); + + if (mCurrentProductUri == null) { + + Uri newUri = getContentResolver().insert(ProductEntry.CONTENT_URI, values); + + if (newUri == null) { + Toast.makeText(this, getString(R.string.insert_product_failed), + Toast.LENGTH_SHORT).show(); + } else { + + Toast.makeText(this, getString(R.string.insert_product_successful), + Toast.LENGTH_SHORT).show(); + } + } else { + int rowsAffected = getContentResolver().update(mCurrentProductUri, values, null, null); + + if (rowsAffected == 0) { + Toast.makeText(this, getString(R.string.update_product_failed), + Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, getString(R.string.update_product_successful), + Toast.LENGTH_SHORT).show(); + } + } + NavUtils.navigateUpFromSameTask(AddProduct.this); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_editor, menu); + return true; + } + + public void tryToOpenImageSelector() { + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE); + return; + } + openImageSelector(); + } + + private void openImageSelector() { + + Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + startActivityForResult(galleryIntent, RESULT_LOAD_IMAGE); + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: { + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + openImageSelector(); + + } + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.action_delete: + 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(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && data != null) { + Uri selectedImage = data.getData(); + mImageView.setImageURI(selectedImage); + mImageURI = Uri.parse(selectedImage.toString()); + + } + } + + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + String[] projection = { + ProductEntry._ID, + ProductEntry.COLUMN_PRODUCT_IMAGE, + ProductEntry.COLUMN_PRODUCT_NAME, + ProductEntry.COLUMN_PRODUCT_QUANTITY, + ProductEntry.COLUMN_PRODUCT_PRICE }; + + 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 nameColumnIndex = cursor.getColumnIndex(ProductEntry.COLUMN_PRODUCT_NAME); + int quantityColumnIndex = cursor.getColumnIndex(ProductEntry.COLUMN_PRODUCT_QUANTITY); + int priceColumnIndex = cursor.getColumnIndex(ProductEntry.COLUMN_PRODUCT_PRICE); + int selectedImage = cursor.getColumnIndex(ProductEntry.COLUMN_PRODUCT_IMAGE); + + String name = cursor.getString(nameColumnIndex); + int quantity = cursor.getInt(quantityColumnIndex); + int price = cursor.getInt(priceColumnIndex); + String image = cursor.getString(selectedImage); + + mNameEditText.setText(name); + mQuantityEditText.setText(Integer.toString(quantity)); + mPriceEditText.setText(Integer.toString(price)); + mImageView.setImageURI(Uri.parse(image)); + mImageURI = Uri.parse(image); + + + } + } + + private void IncramentQuantity() { + String quantityString = mQuantityEditText.getText().toString(); + int initialQuantity; + if (quantityString.isEmpty()) { + initialQuantity = 0; + } else { + initialQuantity = Integer.parseInt(quantityString); + } + mQuantityEditText.setText(String.valueOf(initialQuantity + 1)); + } + + private void DecramentQuantity() { + String quantityString = mQuantityEditText.getText().toString(); + int initialQuantity; + if (quantityString.isEmpty()) { + return; + } else if (quantityString.equals("0")) { + return; + } else { + initialQuantity = Integer.parseInt(quantityString); + mQuantityEditText.setText(String.valueOf(initialQuantity - 1)); + } + } + + @Override + public void onLoaderReset(Loader loader) { + + } +} diff --git a/app/src/main/java/com/example/h_mal/inventoryapp/MainActivity.java b/app/src/main/java/com/example/h_mal/inventoryapp/MainActivity.java new file mode 100644 index 0000000..addfeda --- /dev/null +++ b/app/src/main/java/com/example/h_mal/inventoryapp/MainActivity.java @@ -0,0 +1,136 @@ +package com.example.h_mal.inventoryapp; + +import android.app.LoaderManager; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.CursorLoader; +import android.content.Intent; +import android.content.Loader; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +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 com.example.h_mal.inventoryapp.data.ProductContract.ProductEntry; +import com.example.h_mal.inventoryapp.data.ProductDbHelper; + +public class MainActivity extends AppCompatActivity implements + LoaderManager.LoaderCallbacks{ + + private static final int PRODUCT_LOADER = 0; + + ProductCursorAdapter mCursorAdapter; + ProductDbHelper productDbhelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + + FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(MainActivity.this, AddProduct.class); + startActivity(intent); + } + }); + + ListView productListView = (ListView) findViewById(R.id.list_item_view); + + View emptyView = findViewById(R.id.empty_view); + productListView.setEmptyView(emptyView); + + mCursorAdapter = new ProductCursorAdapter(this, null); + productListView.setAdapter(mCursorAdapter); + + getLoaderManager().initLoader(PRODUCT_LOADER, null, this); + + } + + private void insertProduct() { + ContentValues values = new ContentValues(); + values.put(ProductEntry.COLUMN_PRODUCT_NAME, "demoItem"); + values.put(ProductEntry.COLUMN_PRODUCT_PRICE, 8); + values.put(ProductEntry.COLUMN_PRODUCT_QUANTITY, 4); + Uri SadImageuri = Uri.parse("android.resource://com.example.h_mal.inventoryapp/drawable/sad"); + values.put(ProductEntry.COLUMN_PRODUCT_IMAGE, String.valueOf(SadImageuri)); + + Uri newUri = getContentResolver().insert(ProductEntry.CONTENT_URI, values); + } + + + private void deleteAllProducts() { + int rowsDeleted = getContentResolver().delete(ProductEntry.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, AddProduct.class); + Uri currentProductUri = ContentUris.withAppendedId(ProductEntry.CONTENT_URI, id); + intent.setData(currentProductUri); + startActivity(intent); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.action_settings: + deleteAllProducts(); + return true; + + case R.id.insert_placeholder_data: + insertProduct(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + // Define a projection that specifies the columns from the table we care about. + String[] projection = { + ProductEntry._ID, + ProductEntry.COLUMN_PRODUCT_IMAGE, + ProductEntry.COLUMN_PRODUCT_NAME, + ProductEntry.COLUMN_PRODUCT_QUANTITY, + ProductEntry.COLUMN_PRODUCT_PRICE}; + + // This loader will execute the ContentProvider's query method on a background thread + return new CursorLoader(this, // Parent activity context + ProductEntry.CONTENT_URI, // Provider content URI to query + projection, // Columns to include in the resulting Cursor + null, // No selection clause + null, // No selection arguments + null); // Default sort order + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + mCursorAdapter.swapCursor(data); + } + + @Override + public void onLoaderReset(Loader loader) { + mCursorAdapter.swapCursor(null); + } + + +} diff --git a/app/src/main/java/com/example/h_mal/inventoryapp/ProductCursorAdapter.java b/app/src/main/java/com/example/h_mal/inventoryapp/ProductCursorAdapter.java new file mode 100644 index 0000000..7a19d1e --- /dev/null +++ b/app/src/main/java/com/example/h_mal/inventoryapp/ProductCursorAdapter.java @@ -0,0 +1,98 @@ +package com.example.h_mal.inventoryapp; + +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.CursorAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.h_mal.inventoryapp.data.ProductContract.ProductEntry; + +/** + * Created by h_mal on 04/04/2017. + */ + +public class ProductCursorAdapter extends CursorAdapter { + + private final MainActivity activity; + + private Context mContext; + + public ProductCursorAdapter(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; + + ImageView picImageView = (ImageView) view.findViewById(R.id.imageView); + TextView nameTextView = (TextView) view.findViewById(R.id.Product); + TextView priceTextView = (TextView) view.findViewById(R.id.price); + TextView quantityTextView = (TextView) view.findViewById(R.id.Qn); + Button sellButton = (Button) view.findViewById(R.id.button); + + final String nameColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ProductEntry.COLUMN_PRODUCT_NAME)); + final Integer priceColumnIndex = cursor.getInt(cursor.getColumnIndexOrThrow(ProductEntry.COLUMN_PRODUCT_PRICE)); + final Integer quantityColumnIndex = cursor.getInt(cursor.getColumnIndexOrThrow(ProductEntry.COLUMN_PRODUCT_QUANTITY)); + final String imageColumnIndex = cursor.getString(cursor.getColumnIndexOrThrow(ProductEntry.COLUMN_PRODUCT_IMAGE)); + + nameTextView.setText(nameColumnIndex); + priceTextView.setText(Integer.toString(priceColumnIndex)); + quantityTextView.setText(String.valueOf(quantityColumnIndex)); + +// picImageView.setImageURI(Uri.parse(cursor.getString(cursor.getColumnIndex(ProductEntry.COLUMN_PRODUCT_IMAGE)))); + + if (imageColumnIndex == null) { + picImageView.setVisibility(View.GONE); + }else { + picImageView.setVisibility(View.VISIBLE); + picImageView.setImageURI(Uri.parse(imageColumnIndex)); + } + + final long id = cursor.getLong(cursor.getColumnIndexOrThrow(ProductEntry._ID)); + + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + activity.clickOnViewItem(id); + } + }); + + sellButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (view != null) { + Object obj = view.getTag(); + String st = obj.toString(); + ContentValues values = new ContentValues(); + values.put(ProductEntry.COLUMN_PRODUCT_NAME, nameColumnIndex); + values.put(ProductEntry.COLUMN_PRODUCT_IMAGE, imageColumnIndex); + values.put(ProductEntry.COLUMN_PRODUCT_QUANTITY, quantityColumnIndex >= 1? quantityColumnIndex-1: 0); + values.put(ProductEntry.COLUMN_PRODUCT_PRICE, priceColumnIndex); + + Uri currentPetUri = ContentUris.withAppendedId(ProductEntry.CONTENT_URI, Integer.parseInt(st)); + + int rowsAffected = mContext.getContentResolver().update(currentPetUri, values, null, null); + + } + } + }); + Object obj = cursor.getInt(cursor.getColumnIndex(ProductEntry._ID)); + sellButton.setTag(obj); + + } +} diff --git a/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductContract.java b/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductContract.java new file mode 100644 index 0000000..125c029 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductContract.java @@ -0,0 +1,47 @@ +package com.example.h_mal.inventoryapp.data; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * Created by h_mal on 04/04/2017. + */ + +public class ProductContract { + + private ProductContract() {} + + public static final String CONTENT_AUTHORITY = "com.example.h_mal.inventoryapp"; + + public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); + + public static final String PATH_PRODUCTS = "products"; + + public static final class ProductEntry implements BaseColumns { + + public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, PATH_PRODUCTS); + + public static final String CONTENT_LIST_TYPE = + ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_PRODUCTS; + + + public static final String CONTENT_ITEM_TYPE = + ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_PRODUCTS; + + + public final static String TABLE_NAME = "products"; + + public final static String _ID = BaseColumns._ID; + + public final static String COLUMN_PRODUCT_IMAGE = "image"; + + public final static String COLUMN_PRODUCT_NAME ="name"; + + public final static String COLUMN_PRODUCT_QUANTITY = "quantity"; + + public final static String COLUMN_PRODUCT_PRICE = "price"; + + + } +} diff --git a/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductDbHelper.java b/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductDbHelper.java new file mode 100644 index 0000000..70d8adf --- /dev/null +++ b/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductDbHelper.java @@ -0,0 +1,45 @@ +package com.example.h_mal.inventoryapp.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.example.h_mal.inventoryapp.data.ProductContract.ProductEntry; + +/** + * Created by h_mal on 04/04/2017. + */ + +public class ProductDbHelper extends SQLiteOpenHelper{ + + public static final String LOG_TAG = ProductDbHelper.class.getSimpleName(); + + private static final String DATABASE_NAME = "inventory.db"; + + private static final int DATABASE_VERSION = 1; + + + public ProductDbHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + + String SQL_CREATE_PRODUCTS_TABLE = "CREATE TABLE " + ProductEntry.TABLE_NAME + " (" + + ProductEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ProductEntry.COLUMN_PRODUCT_IMAGE + " TEXT, " + + ProductEntry.COLUMN_PRODUCT_NAME + " TEXT NOT NULL, " + + ProductEntry.COLUMN_PRODUCT_QUANTITY + " INTEGER NOT NULL DEFAULT 0, " + + ProductEntry.COLUMN_PRODUCT_PRICE + " INTEGER 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/inventoryapp/data/ProductProvider.java b/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductProvider.java new file mode 100644 index 0000000..6cfa7a4 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/inventoryapp/data/ProductProvider.java @@ -0,0 +1,214 @@ +package com.example.h_mal.inventoryapp.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.inventoryapp.data.ProductContract.ProductEntry; + +public class ProductProvider extends ContentProvider { + + + public static final String LOG_TAG = ProductProvider.class.getSimpleName(); + + private static final int PRODUCTS = 100; + private static final int PRODUCT_ID = 101; + + private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + + + static { + + sUriMatcher.addURI(ProductContract.CONTENT_AUTHORITY, ProductContract.PATH_PRODUCTS, PRODUCTS); + + sUriMatcher.addURI(ProductContract.CONTENT_AUTHORITY, ProductContract.PATH_PRODUCTS + "/#", PRODUCT_ID); + } + + ProductDbHelper mDbHelper; + + @Override + public boolean onCreate() { + mDbHelper = new ProductDbHelper(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 PRODUCTS: + + cursor = database.query(ProductEntry.TABLE_NAME, projection, selection, selectionArgs, + null, null, sortOrder); + break; + case PRODUCT_ID: + + selection = ProductEntry._ID + "=?"; + selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) }; + cursor = database.query(ProductEntry.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 PRODUCTS: + return insertProduct(uri, contentValues); + default: + throw new IllegalArgumentException("Insertion is not supported for " + uri); + } + } + + private Uri insertProduct(Uri uri, ContentValues values) { + + String name = values.getAsString(ProductEntry.COLUMN_PRODUCT_NAME); + if (name == null) { + throw new IllegalArgumentException("name required"); + } + + Integer quantity = values.getAsInteger(ProductEntry.COLUMN_PRODUCT_QUANTITY); + if (quantity != null && quantity < 0) { + throw new IllegalArgumentException("quantity required"); + } + + + Integer price = values.getAsInteger(ProductEntry.COLUMN_PRODUCT_PRICE); + if (price != null && price < 0) { + throw new IllegalArgumentException("Price required"); + } + + String image = values.getAsString(ProductEntry.COLUMN_PRODUCT_IMAGE); + if (image == null) { + throw new IllegalArgumentException("image required"); + } + + SQLiteDatabase database = mDbHelper.getWritableDatabase(); + + long id = database.insert(ProductEntry.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 PRODUCTS: + return updateProduct(uri, contentValues, selection, selectionArgs); + case PRODUCT_ID: + + selection = ProductEntry._ID + "=?"; + selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) }; + return updateProduct(uri, contentValues, selection, selectionArgs); + default: + throw new IllegalArgumentException("Update is not supported for " + uri); + } + } + + + private int updateProduct(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + + if (values.containsKey(ProductEntry.COLUMN_PRODUCT_NAME)) { + String name = values.getAsString(ProductEntry.COLUMN_PRODUCT_NAME); + if (name == null) { + throw new IllegalArgumentException("Name required"); + } + } + + if (values.containsKey(ProductEntry.COLUMN_PRODUCT_QUANTITY)) { + Integer quantity = values.getAsInteger(ProductEntry.COLUMN_PRODUCT_QUANTITY); + if (quantity != null && quantity < 0) { + throw new IllegalArgumentException("quantity required"); + } + } + + if (values.containsKey(ProductEntry.COLUMN_PRODUCT_PRICE)) { + Integer price = values.getAsInteger(ProductEntry.COLUMN_PRODUCT_PRICE); + if (price != null && price < 0) { + throw new IllegalArgumentException("Price required"); + } + } + + + if (values.size() == 0) { + return 0; + } + + SQLiteDatabase database = mDbHelper.getWritableDatabase(); + int rowsUpdated = database.update(ProductEntry.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 PRODUCTS: + rowsDeleted = database.delete(ProductEntry.TABLE_NAME, selection, selectionArgs); + break; + case PRODUCT_ID: + selection = ProductEntry._ID + "=?"; + selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) }; + rowsDeleted = database.delete(ProductEntry.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 PRODUCTS: + return ProductEntry.CONTENT_LIST_TYPE; + case PRODUCT_ID: + return ProductEntry.CONTENT_ITEM_TYPE; + default: + throw new IllegalStateException("Unknown URI " + uri + " with match " + match); + } + } + + +} \ No newline at end of file diff --git a/app/src/main/res/drawable/sad.jpg b/app/src/main/res/drawable/sad.jpg new file mode 100644 index 0000000000000000000000000000000000000000..90dde208749c51314b2d17e6084eb5df9b9f6125 GIT binary patch literal 31648 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 c4so;3 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

Hap}VJ z*V{srUKhS^{Yy;rG`uX5lMovlXaaneGKApIB^)4X2aUCSX_qZ8Ju-GEN~GZNeUl_d zfi9f{gr;p(s;6d^Kp@A}%savtML|+c?R?2*a^K?{x2&}Lr2LBRh&}+tC6hS-`6~{8 zhk$^5>W&a+#=h~pBYUQAGV+v8;3C8Cl@A#tW^!!3U{y=^Xw=k9_!Tw#1bf!8^460M z4Va7iTRBHaUR%ciIl6bdJqL=@Sp)^trwT$0QQmXwxr&emC;OR<=Y~dpf)ZxiK;mzL z?YF^HOgH;TQ0J$u$_KAnrQZ#dTrGdW)MYhLLh0s831xu(OzA^Uz9em*!>dRt21j_!rO~ z?h0?Rl+10Fv_2@l=xK9P@NJ2V2_`^GVZPzsCfKf4D2J3Mr|BL!i9=6v-qZFFDYigd zj*h>ww1C{mTXJ z$)C9$icVaeT+$1!yaXIFJQ|PGVl!w1!4wxu2ZY&?odItU8L0$hPi`&2_#rdQ|OAGqFoJa3fzDJRXP;ewD1$X4;_d$7_d zFbz!X)1wGrAB?vmuNpe0r2Kinfs%$iCkaY;OgoNYsMSyn>t6wcX5C4IUh zh?uJZNW~=ybd8x3xO0oW>PlvIq0`XrX&>1J&3&RIDg}`@o?vD=T>&FrmCwPv}YHxh;uCDH#y-@ zx;pT`E21wY=hPibk7`Wz+RsK=Z8}%svJHd^(ZL`8$W$OFQ`8A^YMyA;x(oDX&%g3N zR_{$B2+KoC5GIdQBLyY6=G^Hv|3_V49tdR@zCE@`7(3ZUAqokJgrTyf(k3CMQi+L? zJZp>$

    Uih`-qI|aEnAx<#XqpK9#4{Ub@|$Kku-H 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 OoaW%t-@90T5BwkOt)Y7W literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_add_product.xml b/app/src/main/res/layout/activity_add_product.xml new file mode 100644 index 0000000..94eeef0 --- /dev/null +++ b/app/src/main/res/layout/activity_add_product.xml @@ -0,0 +1,168 @@ + + + + + + + + + + +