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..1bec35e --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,10 @@ + + + + + + + + \ 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/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..b6ea2b1 --- /dev/null +++ b/.idea/misc.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/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ 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..19063e4 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.anncode.offersandcoupons" + minSdkVersion 15 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation 'com.squareup.retrofit2:retrofit:2.3.0' + implementation 'com.squareup.retrofit2:converter-gson:2.3.0' + implementation 'com.android.support:recyclerview-v7:28.0.0' + implementation 'com.squareup.picasso:picasso:2.71828' + implementation 'com.android.support:cardview-v7:28.0.0' + implementation 'de.hdodenhof:circleimageview:3.0.0' +} 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/anncode/offersandcoupons/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/anncode/offersandcoupons/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b817fbb --- /dev/null +++ b/app/src/androidTest/java/com/anncode/offersandcoupons/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.anncode.offersandcoupons + +import android.support.test.InstrumentationRegistry +import android.support.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.anncode.offersandcoupons", appContext.packageName) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a690f7b --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/anncode/offersandcoupons/BaseCode.kt b/app/src/main/java/com/anncode/offersandcoupons/BaseCode.kt new file mode 100644 index 0000000..28e1782 --- /dev/null +++ b/app/src/main/java/com/anncode/offersandcoupons/BaseCode.kt @@ -0,0 +1,70 @@ +package com.anncode.offersandcoupons + +/* +* +* +* MainActivity.kt +val rvCoupons: RecyclerView = findViewById(R.id.rvCoupons) +rvCoupons.layoutManager = LinearLayoutManager(this) +val coupons = ArrayList() + +val apiService = getClientService() +val call = apiService.getCoupons() + +call.enqueue(object : Callback { + override fun onFailure(call: Call, t: Throwable) { + Log.e("ERROR: ", t.message) + t.stackTrace + } + + override fun onResponse(call: Call, response: Response) { + val offersJsonArray = response.body()?.getAsJsonArray("offers") + offersJsonArray?.forEach { jsonElement: JsonElement -> + var jsonObject = jsonElement.asJsonObject + var coupon = Coupon(jsonObject) + coupons.add(coupon) + } + rvCoupons.adapter = RecyclerCouponsAdapter(coupons, R.layout.card_coupon) + + } + + +}) + + +val apiKey = "69d1837829128f9565368ca704c63207" +val urlApi = "http://feed.linkmydeals.com/" + +fun getClientService(): ApiService { + val authInterceptor = Interceptor { chain -> + val url = chain.request().url().newBuilder() + .addQueryParameter("API_KEY", apiKey) + .addQueryParameter("format", "json") + .build() + + val newRequest = chain.request() + .newBuilder() + .url(url) + .build() + + chain.proceed(newRequest) + } + + val client = OkHttpClient.Builder() + .addInterceptor(authInterceptor).build() + + val retrofit = Retrofit.Builder() + .baseUrl(urlApi) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build() + + return retrofit.create(ApiService::class.java) +} + +interface ApiService { + @GET("getOffers/") + fun getCoupons(): Call +} + +* */ \ No newline at end of file diff --git a/app/src/main/java/com/anncode/offersandcoupons/Coupon.kt b/app/src/main/java/com/anncode/offersandcoupons/Coupon.kt new file mode 100644 index 0000000..a4b1a84 --- /dev/null +++ b/app/src/main/java/com/anncode/offersandcoupons/Coupon.kt @@ -0,0 +1,80 @@ +package com.anncode.offersandcoupons + +import com.google.gson.JsonObject +import java.lang.Exception +import java.text.ParseException +import java.text.SimpleDateFormat +import java.io.Serializable +import java.util.* + +class Coupon(couponJson: JsonObject?) : Serializable { + + lateinit var id: String + lateinit var image_url: String + lateinit var title: String + lateinit var descriptionShort: String + lateinit var category: String + lateinit var description:String + lateinit var offer: String + lateinit var website: String + lateinit var endDate: String + lateinit var url: String + + init { + try { + id = couponJson!!.get(ID).asString + image_url = couponJson!!.get(IMAGE_URL).asString + title = couponJson!!.get(TITLE).asString + descriptionShort = chunkWords(couponJson!!.get(DESCRIPTION_SHORT).asString, ' ', 5) + category = chunkWords(couponJson!!.get(CATEGORY).asString, ',', 1) + description = couponJson!!.get(DESCRIPTION).asString + offer = couponJson!!.get(OFFER).asString + website = couponJson!!.get(WEBSITE).asString + endDate = getFormatDate(couponJson!!.get(END_DATE).asString) + url = couponJson!!.get(URL).asString + }catch (e: Exception){ + e.printStackTrace() + } + + + } + + companion object { + private val ID = "lmd_id" + private val IMAGE_URL = "image_url" + private val TITLE = "title" + private val DESCRIPTION_SHORT = "offer_text" + private val CATEGORY = "categories" + private val DESCRIPTION = "description" + private val OFFER = "offer" + private val WEBSITE = "store" + private val END_DATE = "end_date" + private val URL = "url" + } + + private fun getFormatDate(dateCoupon:String):String { + val format = SimpleDateFormat("yyyy-MM-dd") + val dateFormat = SimpleDateFormat("dd MMMM yyyy") + try { + val parsedDateFormat = format.parse(dateCoupon) + val cal = Calendar.getInstance() + cal.time = parsedDateFormat + return dateFormat.format(cal.time) + } catch (e: ParseException) { + e.printStackTrace() + return "" + } + } + + + private fun chunkWords(string: String, delimiter: Char, quantity: Int): String { + val words = string.split(delimiter) + var newString: String = "" + + for (i in 0..quantity){ + newString += words.get(i) + " " + } + + return newString + } +} \ No newline at end of file diff --git a/app/src/main/java/com/anncode/offersandcoupons/CouponDetailActivity.kt b/app/src/main/java/com/anncode/offersandcoupons/CouponDetailActivity.kt new file mode 100644 index 0000000..cf2ed2b --- /dev/null +++ b/app/src/main/java/com/anncode/offersandcoupons/CouponDetailActivity.kt @@ -0,0 +1,55 @@ +package com.anncode.offersandcoupons + +import android.content.Intent +import android.net.Uri +import android.support.v7.app.AppCompatActivity +import android.os.Bundle +import android.widget.Button +import android.widget.ImageView +import android.widget.TextView +import com.squareup.picasso.Picasso +import de.hdodenhof.circleimageview.CircleImageView + +class CouponDetailActivity : AppCompatActivity() { + + private var couponSelected : Coupon? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_coupon_detail) + + couponSelected = intent.getSerializableExtra("COUPON") as Coupon + + var tvTitleDetail: TextView = findViewById(R.id.tvTitleDetail) + var tvDescriptionShortDetail: TextView = findViewById(R.id.tvDescriptionShortDetail) + var tvCategoryDetail: TextView = findViewById(R.id.tvCategoryDetail) + var tvDateDetail: TextView = findViewById(R.id.tvDateDetail) + var tvDescriptionDetailData: TextView = findViewById(R.id.tvDescriptionDetailData) + var tvOffertDetailData: TextView = findViewById(R.id.tvOffertDetailData) + var tvWebsiteDetailData: TextView = findViewById(R.id.tvWebsiteDetailData) + var tvDateEndData: TextView = findViewById(R.id.tvDateEndData) + var imgHeaderDetail: ImageView = findViewById(R.id.imgHeaderDetail) + var imgCouponDetail: CircleImageView = findViewById(R.id.imgCouponDetail) + var btnOpenOffer: Button = findViewById(R.id.btnOpenOffer) + + tvTitleDetail.text = couponSelected?.title + tvDescriptionShortDetail.text = couponSelected?.descriptionShort + tvCategoryDetail.text = couponSelected?.category + tvDateDetail.text = couponSelected?.endDate + tvDescriptionDetailData.text = couponSelected?.description + tvOffertDetailData.text = couponSelected?.offer + tvWebsiteDetailData.text = couponSelected?.website + tvDateEndData.text = couponSelected?.endDate + + Picasso.get().load(couponSelected?.image_url).resize(520, 520).centerCrop().into(imgHeaderDetail) + Picasso.get().load(couponSelected?.image_url).resize(520, 520).centerCrop().into(imgCouponDetail) + + btnOpenOffer.setOnClickListener { + val openURL = Intent(Intent.ACTION_VIEW) + openURL.data = Uri.parse(couponSelected?.url) + startActivity(openURL) + } + + + } +} diff --git a/app/src/main/java/com/anncode/offersandcoupons/MainActivity.kt b/app/src/main/java/com/anncode/offersandcoupons/MainActivity.kt new file mode 100644 index 0000000..46872fa --- /dev/null +++ b/app/src/main/java/com/anncode/offersandcoupons/MainActivity.kt @@ -0,0 +1,14 @@ +package com.anncode.offersandcoupons + +import android.support.v7.app.AppCompatActivity +import android.os.Bundle + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + supportActionBar?.hide() + + } +} diff --git a/app/src/main/java/com/anncode/offersandcoupons/RecyclerCouponsAdapter.kt b/app/src/main/java/com/anncode/offersandcoupons/RecyclerCouponsAdapter.kt new file mode 100644 index 0000000..4f104fa --- /dev/null +++ b/app/src/main/java/com/anncode/offersandcoupons/RecyclerCouponsAdapter.kt @@ -0,0 +1,63 @@ +package com.anncode.offersandcoupons + +import android.content.Intent +import android.support.v7.widget.RecyclerView +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import com.squareup.picasso.Picasso + +class RecyclerCouponsAdapter(var coupons : ArrayList, var resource: Int) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CardCouponHolder { + var view: View = LayoutInflater.from(p0!!.context).inflate(resource, p0, false) + return CardCouponHolder(view) + } + + override fun getItemCount(): Int { + return coupons.size + } + + override fun onBindViewHolder(p0: CardCouponHolder, p1: Int) { + var coupon = coupons.get(p1) + p0.setDataCard(coupon) + } + + class CardCouponHolder(v: View) : RecyclerView.ViewHolder(v), View.OnClickListener { + + private var coupon: Coupon? = null + private var imgCoupon: ImageView = v.findViewById(R.id.imgCoupon) + private var tvTitle: TextView = v.findViewById(R.id.tvTitle) + private var tvDescriptionShort: TextView = v.findViewById(R.id.tvDescriptionShort) + private var tvCategory: TextView = v.findViewById(R.id.tvCategory) + private var tvDate: TextView = v.findViewById(R.id.tvDate) + + init { + v.setOnClickListener(this) + } + + fun setDataCard(coupon: Coupon){ + this.coupon = coupon + Picasso.get().load(coupon.image_url).resize(520, 520).centerCrop().into(imgCoupon) + tvTitle.setText(coupon.title) + tvDescriptionShort.setText(coupon.descriptionShort) + tvCategory.setText(coupon.category) + tvDate.setText(coupon.endDate) + + } + + override fun onClick(v: View) { + Log.i("CLICK Coupon: ", coupon?.title) + val context = v.context + val showPhotoIntent = Intent(context, CouponDetailActivity::class.java) + showPhotoIntent.putExtra("COUPON", coupon) + context.startActivity(showPhotoIntent) + + } + + } + +} 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/gradient.xml b/app/src/main/res/drawable/gradient.xml new file mode 100644 index 0000000..2a6f966 --- /dev/null +++ b/app/src/main/res/drawable/gradient.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/header.png b/app/src/main/res/drawable/header.png new file mode 100644 index 0000000..fdc355e Binary files /dev/null and b/app/src/main/res/drawable/header.png differ 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/drawable/rounded_corner_category.xml b/app/src/main/res/drawable/rounded_corner_category.xml new file mode 100644 index 0000000..95a3dba --- /dev/null +++ b/app/src/main/res/drawable/rounded_corner_category.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_corner_deadline.xml b/app/src/main/res/drawable/rounded_corner_deadline.xml new file mode 100644 index 0000000..b66bd23 --- /dev/null +++ b/app/src/main/res/drawable/rounded_corner_deadline.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_coupon_detail.xml b/app/src/main/res/layout/activity_coupon_detail.xml new file mode 100644 index 0000000..353490e --- /dev/null +++ b/app/src/main/res/layout/activity_coupon_detail.xml @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +