commit e800824cc10536594daec39172493d99b6741723 Author: hmalik144 Date: Sat Dec 14 21:31:42 2019 +1100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b75303 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..a88ded0 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,122 @@ + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/h_mal.xml b/.idea/dictionaries/h_mal.xml new file mode 100644 index 0000000..f32ad56 --- /dev/null +++ b/.idea/dictionaries/h_mal.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..15a15b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ 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..d5727af --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + \ 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..e1a3679 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.example.h_mal.shopapicasestudy" + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + dataBinding { + enabled = true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation "androidx.lifecycle:lifecycle-extensions:2.1.0" + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation "androidx.room:room-runtime:2.2.0-rc01" + implementation "androidx.room:room-ktx:2.2.0-rc01" + kapt "androidx.room:room-compiler:2.2.0-rc01" +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# 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/shopapicasestudy/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/h_mal/shopapicasestudy/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..25c8af2 --- /dev/null +++ b/app/src/androidTest/java/com/example/h_mal/shopapicasestudy/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.h_mal.shopapicasestudy + +import androidx.test.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + assertEquals("com.example.h_mal.shopapicasestudy", appContext.packageName) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..502e43c --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/ApiApplication.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/ApiApplication.kt new file mode 100644 index 0000000..ee96021 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/ApiApplication.kt @@ -0,0 +1,17 @@ +package com.example.h_mal.shopapicasestudy + +import android.app.Application +import com.example.h_mal.shopapicasestudy.db.AppDatabase + +class ApiApplication : Application() { + + companion object{ + var db: AppDatabase? = null + } + + override fun onCreate() { + super.onCreate() + + db = AppDatabase.invoke(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/CartlistAdapter.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/CartlistAdapter.kt new file mode 100644 index 0000000..273ead1 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/CartlistAdapter.kt @@ -0,0 +1,84 @@ +package com.example.h_mal.shopapicasestudy.adapters + +import android.app.AlertDialog +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import com.example.h_mal.shopapicasestudy.R +import com.example.h_mal.shopapicasestudy.databinding.CartItemLayoutBinding +import com.example.h_mal.shopapicasestudy.databinding.ListItemLayoutBinding +import com.example.h_mal.shopapicasestudy.databinding.WishlistItemLayoutBinding +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity +import com.example.h_mal.shopapicasestudy.ui.WishListActivity.Companion.wishResponseListener +import com.example.h_mal.shopapicasestudy.viewmodels.CartViewModel +import com.example.h_mal.shopapicasestudy.viewmodels.ListViewModel +import com.example.h_mal.shopapicasestudy.viewmodels.WishListViewModel +import kotlinx.android.synthetic.main.list_item_layout.view.* + +class CartlistAdapter(context: Context, objects: MutableList) : + ArrayAdapter(context, 0, objects) { + + var cartBinding: CartItemLayoutBinding? = null + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view: View? = convertView + + if (view == null){ + view = LayoutInflater.from(context).inflate(R.layout.cart_item_layout, null)!! + cartBinding = DataBindingUtil.bind(view) + view.tag = cartBinding + + }else{ + cartBinding = view.getTag() as CartItemLayoutBinding? + } + + val i = getItem(position) + + val vm = CartViewModel(i) + + cartBinding?.viewmodel = vm + + view.setOnClickListener { + showDialog(vm,position) + } + + return view + } + + fun showDialog(vm : CartViewModel, position: Int){ + val builder = AlertDialog.Builder(context) + builder.setTitle("Select Action") + + // Display a message on alert dialog + builder.setMessage("Do you want to delete?") + + builder.setPositiveButton("Delete"){dialog, which -> + dialog.dismiss() + + val item = getItem(position) + + val s = vm.deleteItemFromCart(item) + + if (!s.isEmpty()){ + Toast.makeText(context,"Item Successfully added to Cart",Toast.LENGTH_SHORT).show() + }else{ + Toast.makeText(context,"Failed to add Item to Wishlist",Toast.LENGTH_SHORT).show() + } + + } + + + builder.setNegativeButton("Cancel"){dialog,which -> + dialog.dismiss() + } + + val dialog: AlertDialog = builder.create() + + dialog.show() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/ListViewAdapter.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/ListViewAdapter.kt new file mode 100644 index 0000000..661df41 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/ListViewAdapter.kt @@ -0,0 +1,100 @@ +package com.example.h_mal.shopapicasestudy.adapters + +import android.app.AlertDialog +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.R +import com.example.h_mal.shopapicasestudy.databinding.ListItemLayoutBinding +import com.example.h_mal.shopapicasestudy.models.ShopItem +import com.example.h_mal.shopapicasestudy.ui.MainActivity +import com.example.h_mal.shopapicasestudy.ui.MainActivity.Companion.responseListener +import com.example.h_mal.shopapicasestudy.ui.ResponseListener +import com.example.h_mal.shopapicasestudy.viewmodels.ListViewModel +import kotlinx.android.synthetic.main.list_item_layout.view.* + +class ListViewAdapter(context: Context, objects: MutableList) : + ArrayAdapter(context, 0, objects) { + + private var listViewBinding: ListItemLayoutBinding? = null + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view: View? = convertView + + if (view == null){ + view = LayoutInflater.from(context).inflate(R.layout.list_item_layout, null)!! + listViewBinding = DataBindingUtil.bind(view) + view.setTag(listViewBinding) + }else{ + listViewBinding = view.getTag() as ListItemLayoutBinding + } + + val s = getItem(position) + val vm = ListViewModel(s) + + listViewBinding?.viewmodel = vm + + view.setOnClickListener { + //produce a dialog + showDialog(vm,position) + + } + + + return view + } + + fun showDialog(vm : ListViewModel, position: Int){ + val builder = AlertDialog.Builder(context) + builder.setTitle("Select Action") + + // Display a message on alert dialog + builder.setMessage("Do you want to add to Cart or Wishlist?") + + builder.setPositiveButton("WishList"){dialog, which -> + dialog.dismiss() + + val i = getItem(position) + + val id = vm.insertWishListItem(i) + + if (id > 0){ + Toast.makeText(context,"Item Successfully added to Wishlist",Toast.LENGTH_SHORT).show() + }else{ + Toast.makeText(context,"Failed to add Item to Wishlist",Toast.LENGTH_SHORT).show() + } + + } + + + builder.setNegativeButton("Cart"){dialog,which -> + dialog.dismiss() + + val stock = getItem(position).stock?.toInt() + + if (stock == 0){ + Toast.makeText(context,"Item out of stock",Toast.LENGTH_SHORT).show() + return@setNegativeButton + } + + val i = getItem(position).createCartItem() + + val id = vm.insertCartListItem(i, responseListener) + + if (!id.isEmpty()){ + Toast.makeText(context,"Item Successfully added to Cart",Toast.LENGTH_SHORT).show() + }else{ + Toast.makeText(context,"Failed to add Item to Cart",Toast.LENGTH_SHORT).show() + } + } + + val dialog: AlertDialog = builder.create() + + dialog.show() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/WishlistAdapter.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/WishlistAdapter.kt new file mode 100644 index 0000000..1d42d16 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/adapters/WishlistAdapter.kt @@ -0,0 +1,96 @@ +package com.example.h_mal.shopapicasestudy.adapters + +import android.app.AlertDialog +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import com.example.h_mal.shopapicasestudy.R +import com.example.h_mal.shopapicasestudy.databinding.ListItemLayoutBinding +import com.example.h_mal.shopapicasestudy.databinding.WishlistItemLayoutBinding +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity +import com.example.h_mal.shopapicasestudy.ui.WishListActivity.Companion.wishResponseListener +import com.example.h_mal.shopapicasestudy.viewmodels.ListViewModel +import com.example.h_mal.shopapicasestudy.viewmodels.WishListViewModel +import kotlinx.android.synthetic.main.list_item_layout.view.* + +class WishlistAdapter(context: Context, objects: MutableList) : + ArrayAdapter(context, 0, objects) { + + var wishlistItemLayoutBinding : WishlistItemLayoutBinding? = null + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view: View? = convertView + + if (view == null){ + view = LayoutInflater.from(context).inflate(R.layout.wishlist_item_layout, null)!! + wishlistItemLayoutBinding = DataBindingUtil.bind(view) + view.tag = wishlistItemLayoutBinding + }else{ + wishlistItemLayoutBinding = view.tag as WishlistItemLayoutBinding + } + + val item = getItem(position) + val vm = WishListViewModel(item) + + wishlistItemLayoutBinding?.viewmodel = vm + + view.setOnClickListener { + showDialog(vm,position) + } + + return view + } + + fun showDialog(vm : WishListViewModel, position: Int){ + val builder = AlertDialog.Builder(context) + builder.setTitle("Select Action") + + // Display a message on alert dialog + builder.setMessage("Do you want to add to Cart or Delete?") + + builder.setPositiveButton("Cart"){dialog, which -> + dialog.dismiss() + + val stock = getItem(position).stock + + if (stock == 0){ + Toast.makeText(context,"Item out of stock",Toast.LENGTH_SHORT).show() + return@setPositiveButton + } + + val i = getItem(position) + + val id = vm.insertCartListItem(i) + + if (!id.isEmpty()){ + Toast.makeText(context,"Item Successfully added to Cart",Toast.LENGTH_SHORT).show() + }else{ + Toast.makeText(context,"Failed to add Item to Cart",Toast.LENGTH_SHORT).show() + } + + } + + + builder.setNegativeButton("Delete"){dialog,which -> + dialog.dismiss() + + val item = getItem(position) + + val i = vm.deleteFromWishList(item) + + if (i > 0){ + Toast.makeText(context,"Item Successfully removed from Wishlist", Toast.LENGTH_SHORT).show() + }else{ + Toast.makeText(context,"Failed to remove Item from Wishlist", Toast.LENGTH_SHORT).show() + } + } + + val dialog: AlertDialog = builder.create() + + dialog.show() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/api/Api.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/api/Api.kt new file mode 100644 index 0000000..dfda220 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/api/Api.kt @@ -0,0 +1,49 @@ +package com.example.h_mal.shopapicasestudy.api + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import com.example.h_mal.shopapicasestudy.models.ShopItem +import org.json.JSONArray + +class Api { + + fun parseJson(jsonString : String) : MutableList{ + + + + val list = mutableListOf() + + try { + val json = JSONArray(jsonString) + + for (i in 0 until json.length()){ + val item = json.getJSONObject(i) + + val id = item.get("productId") as Int? + val name = item.get("name") as String? + val category = item.get("category") as String? + val price = (item.get("price")).toString().toDouble() + val stock = item.get("stock") as Int? + + val shopItem = + ShopItem( + id, + name, + category, + price, + stock.toString() + ) + + list.add(shopItem) + } + }catch (e: Exception){ + Log.e("Error", e.message) + } + + return list + + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/api/AsyncApiCall.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/api/AsyncApiCall.kt new file mode 100644 index 0000000..7f16562 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/api/AsyncApiCall.kt @@ -0,0 +1,59 @@ +package com.example.h_mal.shopapicasestudy.api + +import android.os.AsyncTask +import android.util.Log +import com.example.h_mal.shopapicasestudy.ui.ResponseListener +import java.lang.Exception +import java.net.HttpURLConnection +import java.net.URL + + +class AsyncApiCall( + val urlString : String, + val callBack : ResponseListener? +): AsyncTask() { + + override fun onPreExecute() { + super.onPreExecute() + callBack?.onStarted() + } + + override fun doInBackground(vararg params: String?): String { + + + return try { + val url = URL(urlString) + val con = url.openConnection() as HttpURLConnection + + if (urlString == + "https://private-anon-21a48b3d0e-ddshop.apiary-mock.com/cart/1"){ + con.requestMethod = "DELETE" + + } + + val code = con.responseCode + + Log.i("reponse", "code = ${code}") + + if (code == 204){ + return "successful delete" + } + + URL(urlString).readText() + }catch (e : Exception){ + Log.e("error", e.message) + "" + } + + + } + + override fun onPostExecute(result: String) { + if (result.isEmpty()){ + callBack?.onFailure("Failed to retrieve") + }else{ + callBack?.onSuccess() + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/db/AppDatabase.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/AppDatabase.kt new file mode 100644 index 0000000..e46a103 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/AppDatabase.kt @@ -0,0 +1,44 @@ +package com.example.h_mal.shopapicasestudy.db + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity + + +@Database( + entities = [ShopItemEntity::class, CartItemEntity::class], + version = 1, + exportSchema = false +) +abstract class AppDatabase : RoomDatabase(){ + + abstract fun getWishListDao() : WishListDao + abstract fun getCartDao() : CartDao + + + companion object{ + + @Volatile + private var instance: AppDatabase? = null + private val LOCK = Any() + + operator fun invoke(context: Context) = instance + ?: synchronized(LOCK){ + instance + ?: buildDatabase( + context + ).also { + instance = it + } + } + + private fun buildDatabase(context: Context) = Room + .databaseBuilder(context.applicationContext, + AppDatabase::class.java, + "MyDatabase").allowMainThreadQueries() + .build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/db/CartDao.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/CartDao.kt new file mode 100644 index 0000000..4425ce8 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/CartDao.kt @@ -0,0 +1,54 @@ +package com.example.h_mal.shopapicasestudy.db + +import androidx.lifecycle.LiveData +import androidx.room.* +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity + +@Dao +interface CartDao { + + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun insertItemToCart(item : CartItemEntity) : Long + + @Query("SELECT * FROM CartItemEntity") + fun getCartlist() : LiveData> + + @Query("SELECT * FROM CartItemEntity WHERE id IN(:id)") + fun getSingleItem(id: Int) : LiveData + + @Delete + fun delete(item: CartItemEntity) : Int + + @Query("UPDATE CartItemEntity SET quantity = quantity + 1 WHERE id IN (:id)") + fun incremementItem(id : Int) : Int + + @Query("UPDATE CartItemEntity SET quantity = quantity - 1 WHERE id IN (:id)") + fun decrementItem(id : Int) : Int + + @Query("SELECT SUM(price) FROM CartItemEntity") + fun getTotalSumOFCart() : Double + + @Transaction + fun upsert(item : CartItemEntity) : Int{ + val id = insertItemToCart(item) + + val idInt = id.toInt() + + if (idInt == -1){ + return incremementItem(item.id!!) + }else{ + return idInt + } + } + + @Transaction + fun downsert(item : CartItemEntity){ + val quantity = item.quantity!! + + if (quantity >1){ + decrementItem(item.id!!) + }else{ + delete(item) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/db/WishListDao.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/WishListDao.kt new file mode 100644 index 0000000..31335e4 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/WishListDao.kt @@ -0,0 +1,22 @@ +package com.example.h_mal.shopapicasestudy.db + +import androidx.lifecycle.LiveData +import androidx.room.* +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity + +@Dao +interface WishListDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertItemToWishList(item : ShopItemEntity) : Long + + @Query("SELECT * FROM ShopItemEntity") + fun getWishlist() : LiveData> + + @Query("SELECT * FROM ShopItemEntity WHERE id IN(:id)") + fun getSingleItem(id: Int) : LiveData + + @Delete + fun delete(item: ShopItemEntity) : Int + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/db/entities/CartItemEntity.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/entities/CartItemEntity.kt new file mode 100644 index 0000000..c0cb376 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/entities/CartItemEntity.kt @@ -0,0 +1,14 @@ +package com.example.h_mal.shopapicasestudy.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class CartItemEntity( + @PrimaryKey(autoGenerate = false) + val id : Int? = null, + val name : String? = null, + val category : String? = null, + val price : Double? = null, + val quantity : Int? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/db/entities/ShopItemEntity.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/entities/ShopItemEntity.kt new file mode 100644 index 0000000..a0c2106 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/db/entities/ShopItemEntity.kt @@ -0,0 +1,18 @@ +package com.example.h_mal.shopapicasestudy.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class ShopItemEntity( + @PrimaryKey(autoGenerate = false) + val id : Int? = null, + val name : String? = null, + val category : String? = null, + val price : Double? = null, + val stock : Int? = null +){ + fun createCartItem(): CartItemEntity{ + return CartItemEntity(id, name, category, price,1) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/models/ShopItem.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/models/ShopItem.kt new file mode 100644 index 0000000..a1c2b1b --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/models/ShopItem.kt @@ -0,0 +1,32 @@ +package com.example.h_mal.shopapicasestudy.models + +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity + +data class ShopItem( + val id : Int?, + val name : String?, + val category : String?, + val price : Double?, + val stock : String? +){ + fun createFromObject(): ShopItemEntity { + return ShopItemEntity( + id, + name, + category, + price, + stock?.toInt() + ) + } + + fun createCartItem(): CartItemEntity { + return CartItemEntity( + id, + name, + category, + price, + 1 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/repositories/ShopItemRepository.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/repositories/ShopItemRepository.kt new file mode 100644 index 0000000..bbb26ed --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/repositories/ShopItemRepository.kt @@ -0,0 +1,40 @@ +package com.example.h_mal.shopapicasestudy.repositories + +import com.example.h_mal.shopapicasestudy.api.Api +import com.example.h_mal.shopapicasestudy.ApiApplication +import com.example.h_mal.shopapicasestudy.db.AppDatabase +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity +import com.example.h_mal.shopapicasestudy.models.ShopItem + +class ShopItemRepository ( + val api: Api = Api(), + val db : AppDatabase = ApiApplication.db!! +) { + + + fun addWishItem(item: ShopItem): Long{ + val i = item.createFromObject() + return db.getWishListDao().insertItemToWishList(i) + } + + fun deleteWishListItem(item : ShopItemEntity) : Int = + db.getWishListDao().delete(item) + + + fun getWishList() = db.getWishListDao().getWishlist() + + fun addCartItem(item: CartItemEntity): Int + = db.getCartDao().upsert(item) + + + fun decrementItem(item: CartItemEntity): Int + = db.getCartDao().decrementItem(item.id!!) + + fun deleteCartItem(item : CartItemEntity): Int = + db.getCartDao().delete(item) + + fun getCartList() = db.getCartDao().getCartlist() + + fun getTotalPrice() :Double = db.getCartDao().getTotalSumOFCart() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/CartActivity.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/CartActivity.kt new file mode 100644 index 0000000..098e468 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/CartActivity.kt @@ -0,0 +1,65 @@ +package com.example.h_mal.shopapicasestudy.ui + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.example.h_mal.shopapicasestudy.R +import com.example.h_mal.shopapicasestudy.adapters.CartlistAdapter +import com.example.h_mal.shopapicasestudy.databinding.ActivityCartBinding +import com.example.h_mal.shopapicasestudy.viewmodels.ActivityCartViewModel +import com.example.h_mal.shopapicasestudy.viewmodels.CartViewModel +import kotlinx.android.synthetic.main.activity_cart.* +import kotlinx.android.synthetic.main.activity_main.* + +class CartActivity : AppCompatActivity(), ResponseListener { + + companion object{ + var cartResponseListener: ResponseListener? = null + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val binding: ActivityCartBinding = DataBindingUtil.setContentView(this,R.layout.activity_cart) + val cartViewModel = ViewModelProviders.of(this).get(ActivityCartViewModel::class.java) + binding.viewmodel = cartViewModel + + cartResponseListener = this + + cartViewModel.getCurrentDbItems().observe(this, Observer { + val adap = + CartlistAdapter( + this, + it + ) + cart_list_view.adapter = adap + + Log.i("Total", "executed") + + total_text.text = cartViewModel.setTotalPrice() + + onSuccess() + }) + + + } + + override fun onStarted() { + progress_bar_cart.visibility = View.VISIBLE + } + + override fun onSuccess() { + progress_bar_cart.visibility = View.GONE + } + + override fun onFailure(message: String) { + Toast.makeText(this,message, Toast.LENGTH_LONG).show() + + progress_bar_cart.visibility = View.GONE + } +} diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/MainActivity.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/MainActivity.kt new file mode 100644 index 0000000..21f1568 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/MainActivity.kt @@ -0,0 +1,91 @@ +package com.example.h_mal.shopapicasestudy.ui + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.example.h_mal.shopapicasestudy.R +import com.example.h_mal.shopapicasestudy.adapters.ListViewAdapter +import com.example.h_mal.shopapicasestudy.databinding.ActivityMainBinding +import com.example.h_mal.shopapicasestudy.viewmodels.MainViewModel +import kotlinx.android.synthetic.main.activity_main.* + +class MainActivity : AppCompatActivity(), + ResponseListener { + + companion object{ + var responseListener: ResponseListener? = null + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, + R.layout.activity_main + ) + val viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) + binding.viewmodel = viewModel + + responseListener = this + + //call to retrieve list + viewModel.callApiShopList() + + //observable an live list to populate the adapter and applu + viewModel.getShopList().observe(this, Observer { + val adapater = + ListViewAdapter( + this, + it + ) + list_view.adapter = adapater + }) + + } + + //create a menu to navigate to other activities + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.menu, menu) + + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item?.itemId){ + R.id.wish_list ->{ + val intent = Intent(this, + WishListActivity::class.java) + startActivity(intent) + + } + R.id.cart ->{ + val intent = Intent(this, + CartActivity::class.java) + startActivity(intent) + } + } + + + return super.onOptionsItemSelected(item) + } + + override fun onStarted() { + progress_bar.visibility = View.VISIBLE + } + + override fun onSuccess() { + progress_bar.visibility = View.GONE + } + + override fun onFailure(message: String) { + Toast.makeText(this,message, Toast.LENGTH_LONG).show() + + progress_bar.visibility = View.GONE + } +} diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/ResponseListener.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/ResponseListener.kt new file mode 100644 index 0000000..b9f1365 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/ResponseListener.kt @@ -0,0 +1,8 @@ +package com.example.h_mal.shopapicasestudy.ui + +interface ResponseListener{ + fun onStarted() + fun onSuccess() + fun onFailure(message: String) + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/WishListActivity.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/WishListActivity.kt new file mode 100644 index 0000000..c3d57a5 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/ui/WishListActivity.kt @@ -0,0 +1,62 @@ +package com.example.h_mal.shopapicasestudy.ui + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.example.h_mal.shopapicasestudy.R +import com.example.h_mal.shopapicasestudy.viewmodels.WishListViewModel +import com.example.h_mal.shopapicasestudy.adapters.WishlistAdapter +import com.example.h_mal.shopapicasestudy.databinding.ActivityWishListBinding +import com.example.h_mal.shopapicasestudy.viewmodels.ActivityWishViewModel +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.android.synthetic.main.activity_wish_list.* + +class WishListActivity : AppCompatActivity(), + ResponseListener { + + companion object{ + var wishResponseListener: ResponseListener? = null + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val binding: ActivityWishListBinding = DataBindingUtil.setContentView(this, + R.layout.activity_wish_list + ) + val viewModel = ViewModelProviders.of(this).get(ActivityWishViewModel::class.java) + binding.viewmodel = viewModel + + wishResponseListener = this + + viewModel.getCurrentDbItems().observe(this, Observer { + val adap = + WishlistAdapter( + this, + it + ) + wishlistview.adapter = adap + + }) + + onSuccess() + } + + override fun onStarted() { + progress_bar_wish.visibility = View.VISIBLE + } + + override fun onSuccess() { + progress_bar_wish.visibility = View.GONE + } + + override fun onFailure(message: String) { + Toast.makeText(this,message, Toast.LENGTH_LONG).show() + + progress_bar_wish.visibility = View.GONE + } +} diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ActivityCartViewModel.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ActivityCartViewModel.kt new file mode 100644 index 0000000..409d7eb --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ActivityCartViewModel.kt @@ -0,0 +1,19 @@ +package com.example.h_mal.shopapicasestudy.viewmodels + +import android.util.Log +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.repositories.ShopItemRepository +import kotlin.math.log + +class ActivityCartViewModel( + private val repository: ShopItemRepository = ShopItemRepository() +) : ViewModel(){ + + fun getCurrentDbItems() = repository.getCartList() + + fun setTotalPrice() : String{ + val total = repository.getTotalPrice().toString() + Log.i("total", total) + return total + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ActivityWishViewModel.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ActivityWishViewModel.kt new file mode 100644 index 0000000..a0db18d --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ActivityWishViewModel.kt @@ -0,0 +1,14 @@ +package com.example.h_mal.shopapicasestudy.viewmodels + +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.api.AsyncApiCall +import com.example.h_mal.shopapicasestudy.repositories.ShopItemRepository +import com.example.h_mal.shopapicasestudy.ui.ResponseListener + +class ActivityWishViewModel( + private val repository: ShopItemRepository = ShopItemRepository() +) : ViewModel(){ + + fun getCurrentDbItems() = repository.getWishList() + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/CartViewModel.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/CartViewModel.kt new file mode 100644 index 0000000..ed0a298 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/CartViewModel.kt @@ -0,0 +1,45 @@ +package com.example.h_mal.shopapicasestudy.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.api.AsyncApiCall +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity +import com.example.h_mal.shopapicasestudy.repositories.ShopItemRepository +import com.example.h_mal.shopapicasestudy.ui.CartActivity.Companion.cartResponseListener +import com.example.h_mal.shopapicasestudy.ui.ResponseListener + +class CartViewModel( + item: CartItemEntity?, + private val repository: ShopItemRepository = ShopItemRepository() +) : ViewModel(){ + + val id : Int? = item?.id + val name : String? = item?.name + val category :String? = item?.category + val price : String? = item?.price.toString() + val quantity : String? = item?.quantity.toString() + + fun deleteItemFromCart(item : CartItemEntity): String{ + val response = + AsyncApiCall( + "https://private-anon-21a48b3d0e-ddshop.apiary-mock.com/cart/1", + cartResponseListener + ) + .execute() + .get() + + if (!response.isEmpty()){ + repository.deleteCartItem(item) + + } + + return response + } + + fun getTotalPrice(): String{ + + return "" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ListViewModel.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ListViewModel.kt new file mode 100644 index 0000000..8fcc238 --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/ListViewModel.kt @@ -0,0 +1,40 @@ +package com.example.h_mal.shopapicasestudy.viewmodels + +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.api.AsyncApiCall +import com.example.h_mal.shopapicasestudy.db.entities.CartItemEntity +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity +import com.example.h_mal.shopapicasestudy.models.ShopItem +import com.example.h_mal.shopapicasestudy.repositories.ShopItemRepository +import com.example.h_mal.shopapicasestudy.ui.ResponseListener + +class ListViewModel( + item : ShopItem, + private val repository: ShopItemRepository = ShopItemRepository() +) : ViewModel(){ + + val id : Int? = item.id + val name : String? = item.name + val category :String? = item.category + val price : String? = item.price.toString() + val stock : String? = item.stock + + + fun insertWishListItem(shopItem : ShopItem) = repository.addWishItem(shopItem) + + fun insertCartListItem(cartItem : CartItemEntity, responseListener : ResponseListener?): String{ + val response = + AsyncApiCall( + "https://private-anon-f3c1195210-ddshop.apiary-mock.com/products", + responseListener + ) + .execute() + .get() + + if (!response.isEmpty()){ + repository.addCartItem(cartItem) + } + + return response + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/MainViewModel.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/MainViewModel.kt new file mode 100644 index 0000000..1ed144d --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/MainViewModel.kt @@ -0,0 +1,37 @@ +package com.example.h_mal.shopapicasestudy.viewmodels + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.api.AsyncApiCall +import com.example.h_mal.shopapicasestudy.ui.ResponseListener +import com.example.h_mal.shopapicasestudy.models.ShopItem +import com.example.h_mal.shopapicasestudy.repositories.ShopItemRepository +import com.example.h_mal.shopapicasestudy.ui.MainActivity.Companion.responseListener + + +class MainViewModel( + private val repository: ShopItemRepository = ShopItemRepository() +) : ViewModel(){ + + private var shopList: MutableLiveData> = MutableLiveData() + + + fun getShopList(): MutableLiveData> { + return shopList + } + + + fun callApiShopList(){ + val jsonResponse = + AsyncApiCall( + "https://private-anon-f3c1195210-ddshop.apiary-mock.com/products", + responseListener + ) + .execute() + .get() + + shopList.value = repository.api.parseJson(jsonResponse) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/WishListViewModel.kt b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/WishListViewModel.kt new file mode 100644 index 0000000..3f45a6f --- /dev/null +++ b/app/src/main/java/com/example/h_mal/shopapicasestudy/viewmodels/WishListViewModel.kt @@ -0,0 +1,40 @@ +package com.example.h_mal.shopapicasestudy.viewmodels + +import androidx.lifecycle.ViewModel +import com.example.h_mal.shopapicasestudy.api.AsyncApiCall +import com.example.h_mal.shopapicasestudy.db.entities.ShopItemEntity +import com.example.h_mal.shopapicasestudy.repositories.ShopItemRepository +import com.example.h_mal.shopapicasestudy.ui.ResponseListener +import com.example.h_mal.shopapicasestudy.ui.WishListActivity.Companion.wishResponseListener + +class WishListViewModel( + item: ShopItemEntity?, + private val repository: ShopItemRepository = ShopItemRepository() +) : ViewModel() { + + val id : Int? = item?.id + val name : String? = item?.name + val category :String? = item?.category + val price : String? = item?.price.toString() + val stock : String? = item?.stock.toString() + + fun deleteFromWishList(item : ShopItemEntity) = repository.deleteWishListItem(item) + + fun insertCartListItem(shopItem : ShopItemEntity): String{ + val response = + AsyncApiCall( + "https://private-anon-f3c1195210-ddshop.apiary-mock.com/products", + wishResponseListener + ) + .execute() + .get() + + if (!response.isEmpty()){ + val i = shopItem.createCartItem() + repository.addCartItem(i) + } + + return response + } + +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..6348baa --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..a0ad202 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_cart.xml b/app/src/main/res/layout/activity_cart.xml new file mode 100644 index 0000000..f519f10 --- /dev/null +++ b/app/src/main/res/layout/activity_cart.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..f8e7afd --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_wish_list.xml b/app/src/main/res/layout/activity_wish_list.xml new file mode 100644 index 0000000..e20bd84 --- /dev/null +++ b/app/src/main/res/layout/activity_wish_list.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/cart_item_layout.xml b/app/src/main/res/layout/cart_item_layout.xml new file mode 100644 index 0000000..789ca0b --- /dev/null +++ b/app/src/main/res/layout/cart_item_layout.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_item_layout.xml b/app/src/main/res/layout/list_item_layout.xml new file mode 100644 index 0000000..3997539 --- /dev/null +++ b/app/src/main/res/layout/list_item_layout.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/wishlist_item_layout.xml b/app/src/main/res/layout/wishlist_item_layout.xml new file mode 100644 index 0000000..87e1c91 --- /dev/null +++ b/app/src/main/res/layout/wishlist_item_layout.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000..a6bb065 --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..bbd3e02 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..898f3ed Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..dffca36 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..64ba76f Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..dae5e08 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..e5ed465 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..14ed0af Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..b0907ca Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..d8ae031 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..2c18de9 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..beed3cd Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..69b2233 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..b64221e --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ShopApiCaseStudy + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..5885930 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/test/java/com/example/h_mal/shopapicasestudy/ExampleUnitTest.kt b/app/src/test/java/com/example/h_mal/shopapicasestudy/ExampleUnitTest.kt new file mode 100644 index 0000000..2c10a9f --- /dev/null +++ b/app/src/test/java/com/example/h_mal/shopapicasestudy/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.example.h_mal.shopapicasestudy + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..e2b07f4 --- /dev/null +++ b/build.gradle @@ -0,0 +1,28 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.3.61' + repositories { + google() + jcenter() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.4.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..23339e0 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9549795 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Dec 12 02:30:30 AEDT 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app'